feat: 创建数据库

This commit is contained in:
R524809
2026-10-12 16:56:42 +08:00
parent 3c6fd2c8ca
commit 63a6993276
35 changed files with 826 additions and 266 deletions
+70
View File
@@ -0,0 +1,70 @@
# Doodle Store v3.5 开发与部署环境
> 更新日期:2026-10-12。
>
> 已确认:PostgreSQL 本地 Docker 开发环境;图片等资源直接使用七牛。
本地验证结果:PostgreSQL 18.6 已启动并通过健康检查,UTF-8 / UTC,密码 TCP 登录成功;NULL exportId 唯一键和大小写匹配行为通过临时表事务验证,检查后已回滚。随后已在用户授权下正式初始化 doodle_dev,public 下业务表共 10 张,current 配置和 homeAutoRefresh 开关已创建。Prisma 与七牛业务接入尚未实施。
> 首期建议:云服务器只常驻生产数据库,不长期部署第二套测试系统;真实微信联调和迁移演练按需开独立测试环境。本次未修改云服务器或配置七牛账户。
## 1. 首期安排
当前项目用户少、后端以 CRUD 为主,已有服务器为 2 核 4 GB。采用本地开发 + 单套线上生产即可起步;上线前仍在隔离数据库完成迁移验证,不拿生产库做自动测试或试导。
| 场景 | 应用 | 数据库 | 资源 |
| ------------------------- | ------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------- |
| 日常开发 | 本机 NestJS watch 模式 | 本机 Docker PostgreSQL / doodle_dev | 七牛开发资源空间或 dev 前缀 |
| 数据库自动测试 | 本机测试进程 | 本机同实例内独立 doodle_test,后续按需创建 | 测试替身;需要真实上传验证时使用七牛开发资源 |
| 微信体验版联调 / 迁移演练 | 按需部署测试 API,独立 HTTPS 域名及环境变量 | 先在本机试导;真实云端联调时同一云端 PostgreSQL 实例内独立 doodle_staging | 七牛测试资源,禁止覆盖生产对象 |
| 正式用户 | 云服务器生产 API | 云服务器 PostgreSQL / doodle_prod | 七牛生产资源 |
**目前无需在云端常驻生产和测试两个数据库,更无需两个 PostgreSQL 容器。** 当云端联调确有需求时,同一 PostgreSQL 实例创建独立 staging 库和独立登录角色即可;测试 API 用另一端口/域名连接 staging,验收后停止测试进程并按保留规则归档临时库。单独数据库主要提供数据与权限隔离,仍共享实例 CPU/内存;试导控制并发,不与生产高峰争抢资源。
微信体验版与正式版不是两个独立 AppID,后端地址须根据客户端版本环境配置。独立测试 API 不接生产库、不使用生产登录 token 签名密钥,生产配置也不回退到测试地址。测试角色不能访问生产库,需通过 PostgreSQL 库级 CONNECT 权限及 schema/对象权限验证;不只依赖连接串约定。
以下情况出现后再考虑长期 staging:连续有真实微信联调需求;频繁修改数据库;新支付、会员或服务端生成流程;多人并行开发;数据规模导致一次迁移演练需要长时间。首期按实际需求启用,避免预先复制完整部署。
## 2. 本地 Docker
参考项目 `/Users/joey-xd/sites/seller-store/atlas-seller-kit/infra/compose.yaml` 使用 PostgreSQL 容器、应用宿主机运行和命名卷持久化。本项目复用这种方式,数据库独立,未修改参考项目。
- Compose 文件:[infra/compose.yaml](../../infra/compose.yaml)。
- 固定镜像:`postgres:18.6-alpine`,与参考项目保持一致;生产部署前验证并固定同一兼容主版本。
- 默认地址:`127.0.0.1:5434`;数据库和用户均为 `doodle_dev`。
- 数据卷挂载 `/var/lib/postgresql`,适配 PostgreSQL 18 的版本子目录布局。
- 使用 UTF-8、C locale 和 UTC;业务任务仍明确采用 Asia/Shanghai。
- 根 `.env` 保存 Compose 配置,服务端连接串保存在 `apps/server/.env`;真实文件均被 Git 忽略。
- 本地已完成 10 张表及初始配置的创建;Prisma 与业务接入后续按 [数据库设计文档](./数据库设计文档.md) 实施。
使用步骤及 SQL 客户端连接见 [infra/README](../../infra/README.md)。本地故障和试导不会写入生产库;数据导入脚本后续应增加目标环境识别、dryRun 和生产写入保护。
## 3. 七牛直接使用与最小隔离
图片、头像、预览、字体及其他对象文件直接使用七牛;本地 PostgreSQL 只保存 assets 元数据与对象引用。开发无需仿真对象存储,不将图片存数据库或容器数据卷。上传 API 与七牛凭证尚待业务模块实施,本次不创建空间或上传文件。
尽量复用同一七牛账户与现有资源域名。访问策略保持公共预览/字体与私有头像区分,空间是否复用取决于现有空间访问属性。生产与开发至少使用不同对象 key 前缀,例如:
```text
prod/previews/<资产ID>/preview.png
prod/avatars/<用户ID>/<资产ID>.png
dev/previews/<资产ID>/preview.png
dev/avatars/<测试用户ID>/<资产ID>.png
staging/...
```
前缀由服务端环境配置生成,客户端不能指定 prod;资源 key 不因重试或重新发布覆盖已有文件。开发可以读取既有公共生产预览/字体,开发上传及删除只作用于 dev/staging;测试私有头像使用测试文件。清理任务同样限制环境和前缀,不能跨环境扫描后删除未在本地数据库引用的生产对象。
**前缀主要防操作混用,不是七牛账户 AK/SK 的权限边界。** 个人首期开发可采用前缀隔离、服务端限制和受控密钥文件;涉及多人开发或自动删除时,应使用能实际限制开发权限的独立凭证/空间。若现有账号权限无法按所需范围限制,则创建独立开发空间及相应权限,不能把改空间名当作凭证权限已经隔离。
七牛配置只放服务端环境变量,包含访问凭证、公共/私有空间、资源域名和环境前缀;具体变量在 assets 模块接入时落实。数据库不保存过期签名 URL;私有资源由 API 按需生成地址。普通小程序用户不能获取账户 AK/SK。
## 4. 上线前最低流程
1. 在本机完成业务检查、数据库事务验证和全量 dryRun/试导,对账正常、合并、隔离及文件映射。
2. 需要微信真实 HTTPS 联调时,临时部署独立测试 API 与 staging 库,体验版用测试数据完成真机验收;测试数据库可用脱敏快照,原始导出只在受控迁移位置处理。
3. 正式迁移前备份生产及旧数据,停止旧任务和写入;按迁移方案最终导入、核对后切换到唯一生产库。
4. 正式 API、定时任务与兼容桥只写 doodle_prod;测试任务关闭,测试上传不进入生产资源前缀。
5. 生产数据库每日备份到服务器之外并演练恢复;生产更新保留上一可运行 API 版本。测试库不充当生产备份。
上述安排保持一套长期生产系统,临时测试仍有明确数据边界,后续需求增加时再扩展部署。切换和回滚详细步骤继续以 [云服务端迁移方案](../云服务端迁移方案.md) 为准。
+21 -13
View File
@@ -2,12 +2,16 @@
> 数据库:PostgreSQL;ORM:Prisma。数据库选型已按用户确认更新。
>
> 状态:目标设计,尚未创建数据库、Prisma Schema 或业务迁移;线上集合、数据量和异常分布待 S0 盘点。
> 状态:目标设计,本地开发数据库已配置;10 张业务表及初始配置已在本地创建;尚未创建 Prisma Schema 或接入 Prisma 迁移历史;线上集合、数据量和异常分布待 S0 盘点。
>
> 更新日期:2026-10-12。
>
> 配套方案:[云服务端迁移方案](../云服务端迁移方案.md)。本文细化该方案的数据结构与一致性规则。
已生成 [数据库初始化 SQL](../../apps/server/prisma/sql/README.md),建库、10 张表及配置初始化已在 PostgreSQL 18.6 临时库执行验证,19 项约束检查通过;临时库已清理,开发库随后已正式执行基线 SQL,创建 10 张表和两条配置记录;未创建 Prisma Schema 或导入线上数据。
本地开发使用 Docker PostgreSQL,图片等资源直接使用七牛;云服务器首期只常驻生产库,隔离测试库在真实联调时按需创建,可复用同一 PostgreSQL 实例。详见 [开发与部署环境方案](./开发与部署环境方案.md) 与 [本地数据库说明](../../infra/README.md)。本地数据库已配置,本文 10 张表已在本地创建,业务 API 尚未实现。
## 1. 范围与依据
首期迁移现有微信小程序后端,统一使用 PostgreSQL 主数据库、NestJS API 和七牛文件存储。小程序仍在 `doodle-mini` 维护,数据库模型与迁移只放在 `doodle-store/apps/server/prisma`。Web 与管理后台通过 API 访问,不直接连接数据库。
@@ -170,6 +174,8 @@ UNIQUE `(user_id, worksheet_id)`;列表索引 `(user_id, created_at DESC, id D
UNIQUE `(user_id, export_id)` 使用 PostgreSQL 默认 NULL 语义,允许同用户多条 export_id=NULL;**不使用 NULLS NOT DISTINCT**。空串先转 NULL,避免旧记录冲突。新版 API 必填 exportId,NULL 只允许历史导入。重复非空 exportId 若指向不同题型,隔离处理,不能任意挑一条。
SQL CHECK 限定 NULL exportId 只能出现在 source=import 的历史记录中;其余来源必须提供非空白事件 ID,旧桥负责生成 legacy 事件 ID。
索引 `(user_id, created_at DESC, id DESC)`、`(worksheet_id, created_at DESC, id DESC)`。不同 exportId 的同题型多次保存都是有效事件;禁止 UNIQUE `(user_id, worksheet_id)` 或按秒级时间窗口去重。
### 3.6 page_configs — 页面配置权威源
@@ -189,17 +195,17 @@ UNIQUE `(user_id, export_id)` 使用 PostgreSQL 默认 NULL 语义,允许同
```json
{
"featured": [
{
"id": "原题型ID",
"title": "练习纸",
"previewImg": { "assetId": "预览资产ID" },
"path": "/原页面路径?原参数",
"available": true
}
],
"hot": [],
"sections": []
"featured": [
{
"id": "原题型ID",
"title": "练习纸",
"previewImg": { "assetId": "预览资产ID" },
"path": "/原页面路径?原参数",
"available": true
}
],
"hot": [],
"sections": []
}
```
@@ -247,6 +253,8 @@ UNIQUE source_ref_hash、UNIQUE object_ref_hash(可空);索引 `(owner_use
qiniu ready 必须具备 bucket、objectKey、objectRefHash、mimeType、sizeBytes 和 checksum;external ready 必须有经核实的 externalUrl,无法取得内容摘要时在报告注明。源文件下载、上传与校验完成后才 ready,再写业务外键。DB 存引用,访问域名从服务配置取;私有签名 URL 在响应时生成,不能写回数据库或页面配置。
SQL 检查 ready 必填字段、external 的 HTTPS 前缀、avatar 必须 private,以及摘要/hash 为 64 位小写十六进制。摘要计算和规范化由服务端完成;HTTPS 前缀检查不代替域名白名单或远程文件校验。
上传和对象存储操作不放在长数据库事务中;先完成上传并登记资产,再短事务绑定业务记录。未绑定文件由清理流程回收,清理前检查 users、worksheets、categories 和 page_configs 的所有引用。旧桥复制云文件后也必须遵循同一路径。
### 4.2 job_runs — 调度与执行结果
@@ -374,7 +382,7 @@ UNIQUE `(job_name, run_key)`;索引 `(status, locked_until)`、`(job_name, cre
- datasource 使用 `provider = "postgresql"`。具体 PostgreSQL 主版本、Prisma 版本、Node 运行时组合在 S1 样板中验证并锁定,不照抄旧 MySQL Schema 或旧连接参数。
- PostgreSQL 类型映射:字符串 `@db.VarChar(n)`、计数 BigInt `@db.BigInt`、日期 DateTime `@db.Timestamptz(3)`、JSON `@db.JsonB`。SQL 的 now() 负责新建时间;更新由服务显式维护,内容时间不依赖自动 updatedAt 推断。
- PostgreSQL CHECK、标识符列排序规则、DESC 索引和本文事务 SQL 以版本化迁移 SQL 为最终落点;Prisma Schema 同步描述可表达的约束。业务验证不能代替数据库唯一键。
- `apps/server/prisma/schema.prisma`、`migrations/` 与迁移说明同版本提交;本文是实施输入,本次不生成看似已执行的 Schema/迁移文件,也不连接生产库。
- 当前可执行基线 SQL 位于 `apps/server/prisma/sql`,尚未纳入 Prisma 迁移历史。后续 `schema.prisma`、`migrations/` 与迁移说明同版本提交;已有表的数据库先登记基线,不能重复执行初始建表 DDL。本次不连接生产库。
- 新增列采用可兼容上一 API 版本的步骤,数据回填和收紧 NOT NULL/外键分开验证;应用回滚继续使用新主库。正式环境不使用 db push 随意覆盖结构。
- 原始导出、隔离记录、文件映射、导入报告和恢复校验随迁移批次归档。数据库备份使用 PostgreSQL 工具链,并实际演练恢复;备份目标在服务器之外。
- 首期不分表、不分区、不引入 Redis、队列或全文搜索。限制连接池与导入并发,按 2 核 4 GB 实际联调结果配置,禁止所有应用默认建立无限连接。