Files
atlas-seller-kit/docs/guides/postgresql-local-development.md

236 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地 PostgreSQL:原生安装与 Docker Compose 使用指南
> 面向 Atlas Seller Kit 的开发环境。本文讲两种等价的本地运行方式:使用已安装在 macOS 上的 PostgreSQL,或使用 Docker Compose 容器。二选一即可;不要让二者同时占用 `5432` 端口。本项目表结构以版本化 SQL migration 为准,而不是由 NestJS 自动同步。
## 1. 先理解三个层次
| 层次 | 谁负责 | 是否要手工做 |
|---|---|---|
| PostgreSQL 服务 | Homebrew/安装包,或 Docker Compose | 第一次启动服务 |
| 数据库与角色 | 本地开发者的初始化步骤 | 每个本地环境一次 |
| 表、索引、RLS、函数 | 版本化 migration | 用命令执行,不逐表手工创建 |
当前可执行结构文件是:
1. [`001_foundation.sql`](../architecture/sql/001_foundation.sql):账户、工作空间、平台、门店、水印、物流、定价和 RLS 基础。
2. [`002_product-domain.sql`](../architecture/sql/002_product-domain.sql):采集箱、商品编辑、发布任务、在线商品镜像和 RLS。
它们只用于**全新的空数据库**的初始建表。项目初始化 NestJS 后,会将其纳入 migration runner;届时日常只运行统一的 `db:migrate` 命令,不再直接逐个执行 SQL 文件。
## 2. 共同的本地约定
| 名称 | 本地建议值 | 用途 |
|---|---|---|
| 数据库 | `atlas_dev` | 仅 Atlas 的本地开发数据 |
| 迁移角色 | `atlas_migrator` | 拥有 `atlas` schema 和表,只执行 migration |
| 应用角色 | `atlas_app_login` | 未来 NestJS API/Worker 的连接身份,不拥有表 |
| 权限组 | `atlas_app` | 授予 API/Worker 所需的 DML 权限 |
| schema | `atlas` | 所有 Atlas 表、类型、函数和策略 |
这三个角色的分工不能省略为“应用直接用管理员连接”:应用连接需要受 RLS 限制,迁移角色不能写入 API/Worker 的环境变量。完整原理见[数据库角色与 RLS 执行约束](../architecture/database-security.md)。
> 以下示例密码仅是本地占位符。不要复用到 staging/production,也不要提交 `.env` 文件。
## 3. 方式 A:使用已安装的本机 PostgreSQL
适合你已经通过 Homebrew 或 PostgreSQL.app 安装并日常使用 PostgreSQL 的情况。
### 3.1 确认服务和客户端
```bash
psql --version
pg_isready -h 127.0.0.1 -p 5432
```
第二行输出 `accepting connections` 即可。若通过 Homebrew 安装而服务未运行,可查看服务状态:
```bash
brew services list
```
启动命令因你的 PostgreSQL 大版本而不同,通常可用:
```bash
brew services start postgresql@16
```
若实际安装的是其他版本,将 `16` 换成对应版本;也可以在 PostgreSQL.app 中直接启动数据库服务。
### 3.2 一次性创建角色和数据库
以具有建角色、建库权限的本机管理员账号连接。Homebrew 的默认管理员通常是当前 macOS 用户,因此先试:
```bash
psql -d postgres
```
进入 `psql` 后执行下面 SQL。将尖括号内容替换为你自己的**本地**密码:
```sql
CREATE ROLE atlas_migrator LOGIN NOINHERIT NOBYPASSRLS PASSWORD '<local-migrator-password>';
CREATE ROLE atlas_app NOLOGIN NOINHERIT NOBYPASSRLS;
CREATE ROLE atlas_app_login LOGIN NOINHERIT NOBYPASSRLS PASSWORD '<local-app-password>';
GRANT atlas_app TO atlas_app_login;
CREATE DATABASE atlas_dev OWNER atlas_migrator;
```
退出后,用迁移角色创建 schema、安装扩展并建表:
```bash
psql -X -v ON_ERROR_STOP=1 -h 127.0.0.1 -p 5432 -U atlas_migrator -d atlas_dev \
-f docs/architecture/sql/001_foundation.sql
psql -X -v ON_ERROR_STOP=1 -h 127.0.0.1 -p 5432 -U atlas_migrator -d atlas_dev \
-f docs/architecture/sql/002_product-domain.sql
```
`-v ON_ERROR_STOP=1` 很重要:任一 SQL 出错时命令立即失败,而不是继续执行留下半成品结构。
### 3.3 授予应用角色权限
仍以 `atlas_migrator` 连接 `atlas_dev`,执行一次:
```sql
GRANT USAGE ON SCHEMA atlas TO atlas_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA atlas TO atlas_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA atlas TO atlas_app;
ALTER DEFAULT PRIVILEGES FOR ROLE atlas_migrator IN SCHEMA atlas
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO atlas_app;
ALTER DEFAULT PRIVILEGES FOR ROLE atlas_migrator IN SCHEMA atlas
GRANT USAGE, SELECT ON SEQUENCES TO atlas_app;
```
未来 API/Worker 使用的本地连接串形如:
```bash
DATABASE_URL=postgresql://atlas_app_login:<local-app-password>@127.0.0.1:5432/atlas_dev?options=-c%20search_path%3Datlas%2Cpublic
DATABASE_MIGRATOR_URL=postgresql://atlas_migrator:<local-migrator-password>@127.0.0.1:5432/atlas_dev?options=-c%20search_path%3Datlas%2Cpublic
```
`DATABASE_MIGRATOR_URL` 仅供 migration 命令使用;API 与 Worker 只读取 `DATABASE_URL`。
## 4. 方式 B:使用 Docker Compose
适合希望 PostgreSQL 版本、参数和数据卷与团队统一,或不想管理本机 PostgreSQL 服务的情况。若本机 PostgreSQL 已占用 `5432`,Docker 映射到 `5433`,避免冲突。
项目初始化时将在仓库根目录提供 Compose 配置。在此之前,可将以下内容保存为本机未提交的 `compose.postgres.local.yml`:
```yaml
services:
postgres:
image: postgres:16-alpine
container_name: atlas-postgres
ports:
- "5433:5432" # 本机已有 PostgreSQL 时使用 5433;没有冲突可改为 5432:5432
environment:
POSTGRES_USER: atlas_admin
POSTGRES_PASSWORD: atlas-admin-local-only
POSTGRES_DB: postgres
volumes:
- atlas_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U atlas_admin -d postgres"]
interval: 5s
timeout: 3s
retries: 10
volumes:
atlas_postgres_data:
```
启动并确认状态:
```bash
docker compose -f compose.postgres.local.yml up -d
docker compose -f compose.postgres.local.yml ps
```
初始化角色和数据库:
```bash
docker exec -it atlas-postgres psql -U atlas_admin -d postgres
```
在交互终端执行第 3.2 节的角色与 `atlas_dev` 创建 SQL。然后从仓库根目录执行 migration;此处端口使用 Docker 映射出的 `5433`:
```bash
psql -X -v ON_ERROR_STOP=1 -h 127.0.0.1 -p 5433 -U atlas_migrator -d atlas_dev \
-f docs/architecture/sql/001_foundation.sql
psql -X -v ON_ERROR_STOP=1 -h 127.0.0.1 -p 5433 -U atlas_migrator -d atlas_dev \
-f docs/architecture/sql/002_product-domain.sql
```
最后按第 3.3 节给 `atlas_app` 授权。Docker 方式对应的连接串只有端口不同:
```bash
DATABASE_URL=postgresql://atlas_app_login:<local-app-password>@127.0.0.1:5433/atlas_dev?options=-c%20search_path%3Datlas%2Cpublic
```
日常停止/再次启动不会删除数据:
```bash
docker compose -f compose.postgres.local.yml stop
docker compose -f compose.postgres.local.yml up -d
```
## 5. 检查表是否创建成功
用迁移角色连接后可执行:
```bash
psql -h 127.0.0.1 -p 5432 -U atlas_migrator -d atlas_dev
```
Docker 方式把 `5432` 改为 `5433`。进入后:
```sql
SELECT schemaname, tablename, tableowner
FROM pg_tables
WHERE schemaname = 'atlas'
ORDER BY tablename;
SELECT c.relname AS table_name, c.relrowsecurity, c.relforcerowsecurity
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'atlas' AND c.relkind = 'r'
ORDER BY c.relname;
```
你应看到 `users`、`workspaces`、`stores`、`products`、`platform_listings` 等表;带 `workspace_id` 的业务表应显示 `rowsecurity = true` 和 `forcerowsecurity = true`。
## 6. 常见问题和重置边界
### 6.1 `role already exists` 或 `database already exists`
说明这台机器已经初始化过。不要再执行创建角色/数据库命令,直接检查并执行尚未应用的 migration。当前两个初始 SQL 不能安全地重复执行;以后由 migration runner 记录版本并避免重复。
### 6.2 `permission denied to create extension`
`001_foundation.sql` 需要 `citext`、`pgcrypto` 扩展。原生本机库可用管理员账号预先执行:
```sql
CREATE EXTENSION IF NOT EXISTS citext;
CREATE EXTENSION IF NOT EXISTS pgcrypto;
```
然后再用迁移角色执行 migration。云托管数据库则由运维账户或云控制台预启用扩展。
### 6.3 要完全重建 Docker 开发库
下列命令会删除 Docker 命名卷中的**全部本地 Atlas 数据**,只用于你确定无需保留当前开发数据时:
```bash
docker compose -f compose.postgres.local.yml down -v
```
之后重新启动、创建角色/数据库并执行两份 migration。原生 PostgreSQL 不建议为重置而删除整个服务;只处理明确的 `atlas_dev` 数据库,并先确认其中没有需要保留的数据。
## 7. 与 staging / production 的差异
本地可以自行执行上述初始化;staging/production 不这样手工操作。云数据库管理员或基础设施脚本先创建角色和数据库,部署流程使用迁移角色执行 migration,随后 API/Worker 用应用角色启动。绝不把生产库当作家/公司开发库。
相关文档:[技术栈与部署](../architecture/technology-and-deployment.md)、[数据库角色与 RLS](../architecture/database-security.md)、[基础数据模型](../architecture/foundation-data-model.md)。