feat: 方案设计、数据库和接口设计基本完成

This commit is contained in:
R524809
2026-09-02 14:47:18 +08:00
parent a3fe066a5f
commit 04c94e75db
30 changed files with 3305 additions and 122 deletions
+235
View File
@@ -0,0 +1,235 @@
# 本地 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)。