feat(api): album domain schema

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-17 20:05:09 +08:00
parent 2801e4f158
commit a99b8f200b
5 changed files with 240 additions and 11 deletions
+10 -11
View File
@@ -362,24 +362,21 @@ model audit_logs {
}
```
- [ ] **Step 2: 迁移**
```bash
pnpm db:migrate -- --name init_identity
```
- [x] **Step 2: 迁移**(完成:20260917114313_init_identity 已应用。**重要发现 A**:Prisma 生成的 MySQL DDL 每表硬编码 `utf8mb4_unicode_ci`,覆盖库级 `utf8mb4_0900_bin`——已手工改 migration.sql 为 bin 校对并经 information_schema 验证;**Task 9/10 每张新表必须重复:`--create-only` 生成→改 COLLATE→应用**。**重要发现 B**:`pnpm db:migrate -- --name x` 会转发字面 `--` 使 prisma 交互挂起——正确语法 `pnpm db:migrate --name xxx`)
Expected: migration SQL 生成并应用。
- [ ] **Step 3: 写语义复核 E2E 测试**(TDD:先写测试)——UTC 往返(写入+读回同为 UTC 瞬间)、`utf8mb4_0900_bin` 下 `public_token` 大小写敏感查询、audit 插入。运行 `pnpm --filter @photo/api-cn test:e2e`,Expected: PASS。
- [ ] **Step 4: Commit** `feat(api): identity and audit schema with mysql semantics tests`
- [x] **Step 3: 写语义复核 E2E 测试**(完成:7/7 通过——UTC DateTime(6) 毫秒往返、bin 校对大小写敏感查找、audit Json+actor 关系、带会话删用户被 P2003 拒绝;reset.ts 已实现真实 truncate)
- [x] **Step 4: Commit** `feat(api): identity and audit schema with mysql semantics tests`(完成:2801e4f)
### Task 9: Prisma cn schema —— 相册域
**Files:**
- Modify: `packages/db-cn/prisma/schema.prisma`
- [ ] **Step 1: 模型**:`albums`(publicToken `@unique @db.VarChar(32)`、ownerId、startAt/endAt、timezone、status active|offline、defaultLocale、uploadEnabled/publicEnabled/downloadEnabled/originalDownloadEnabled 默认 true/true/true/false、watermarkVersion 默认 0)、`album_translations`(`@@unique([albumId, locale])`,title/description/venue/address)、`album_members`(`@@unique([albumId, userId])`,role owner|collaborator,status)、`categories`(albumId、sortOrder)+ `category_translations`(`@@unique([categoryId, locale])`)、`album_assets`(kind banner|cover|logo、locale?、objectKey)。
- [ ] **Step 2: 迁移** `--name album_domain`;Step 3: Commit `feat(api): album domain schema`
- [x] **Step 1: 模型**(完成:六模型入 schema,相册域全量扁平字符串外键、无 Prisma relation;Task 10 照片域沿用):`albums`(publicToken `@unique @db.VarChar(32)`、ownerId、startAt/endAt、timezone、status active|offline、defaultLocale、uploadEnabled/publicEnabled/downloadEnabled/originalDownloadEnabled 默认 true/true/true/false、watermarkVersion 默认 0)、`album_translations`(`@@unique([albumId, locale])`,title/description/venue/address)、`album_members`(`@@unique([albumId, userId])`,role owner|collaborator,status)、`categories`(albumId、sortOrder)+ `category_translations`(`@@unique([categoryId, locale])`)、`album_assets`(kind banner|cover|logo、locale?、objectKey)。
- [x] **Step 2: 迁移**(完成:20260917120158_album_domain。流程固化:`pnpm db:migrate --create-only --name album_domain` 生成→sed 改 6 表 COLLATE→`pnpm db:migrate`(无参,非交互应用 pending)→information_schema 验证 10 张域表全 utf8mb4_0900_bin。补充发现 C:`pnpm db:migrate --create-only --name x` 参数可直传,无需进包目录)
- [x] **Step 3: 语义冒烟 + Commit**(完成:reset.ts 增 6 表(翻译/资产/成员在前、albums 在后);db.semantics.e2e-spec.ts 增相册用例——(albumId, locale) 复合唯一双向命中 + 同键重复与 publicToken 重复均 P2002;e2e 8/8、lint/typecheck/test 全绿)
### Task 10: Prisma cn schema —— 照片与上传域 + outbox
@@ -459,7 +456,7 @@ model outbox_events {
}
```
- [ ] **Step 2: 迁移** `--name photo_upload_domain`;Step 3: Commit `feat(api): photo, upload, outbox schema`
- [ ] **Step 2: 迁移** `pnpm db:migrate --name photo_upload_domain`(同 Task 9:`--create-only` → 逐表改 COLLATE `utf8mb4_0900_bin` → 应用 → information_schema 验证);Step 3: Commit `feat(api): photo, upload, outbox schema`
### Task 11: StoragePort 接口 + MinIO 适配器
@@ -496,6 +493,8 @@ export interface StoragePort {
- Create: `services/api/src/auth/password.ts`、`services/api/scripts/seed-admin.ts`
- Test: `services/api/test/password.spec.ts`
> Task 7 质量审查遗留(本任务一并落地):① `ApiException extends HttpException` 携带 `{code: ErrorCode, message, httpStatus}`,异常过滤器优先识别(状态码表无法表达同状态多错误码的契约空间)+ 未映射状态分支单测;② 5xx/INTERNAL_ERROR 强制通用文案(堵住 InternalServerErrorException(message) 泄露);③ pino redact 增 cookie/set-cookie;④ x-request-id 回显加长度上限(128);⑤ LOG_LEVEL 非法值启动期明确报错;⑥ 抽出 `API_PREFIX='v1'` 与 `RequestWithId` 共享类型;⑦ jest ts-jest 改 `tsconfig: 'tsconfig.json'` 复用;⑧ 增加 `start:dev`(tsc --watch + node --watch 或 nodemon 任一)。计划文本笔误修正:request-id 生成为 UUID v4(非 cuid)。
- [ ] **Step 1: 失败测试**:hash/verify(@node-rs/argon2,memoryCost 默认)、错误口令 verify=false。
- [ ] **Step 2: 实现 + seed 脚本**(读 env `ADMIN_ACCOUNT/ADMIN_PASSWORD`,不存在则插入 admin 角色,存在则跳过——幂等)。
- [ ] **Step 3: 测试通过;Commit** `feat(api): argon2 password and idempotent admin seed`
@@ -645,7 +644,7 @@ export interface StoragePort {
- 每任务 TDD 节奏不可跳步:先失败测试→实现→通过→提交;集成/E2E 测试统一跑在 compose 依赖上(`docker compose up -d` 前置)。
- e2e 隔离:每个 e2e spec `beforeAll` 调 `test/reset.ts`(truncate cn 全表 + 清 MinIO `photo-live/dev` 前缀);worker/storage 测试沿用同约定(各自包内复制 reset 工具或引用)。
- 基础设施注意:minio 镜像统一用 `quay.io/minio/*`(Docker Hub 官方仓库已删除,P2 ov 侧同样);跑 prisma/集成测试前先确认宿主端口实际指向 photo-live 容器(`docker port photo-live-mysql-cn-1`),Docker Desktop 重启可能拉起其他项目容器抢占 3306/6379(已对其设 restart=no,但新冲突可能来自其他来源)。
- env:命令一律在仓库根执行;根 `.env` 为唯一 env 文件,脚本经 dotenv-cli 注入、测试经 `test/load-env.ts` 载入(Task 7 约定;`services/worker/test` 与 `packages/storage/test` 复制同约定 load-env.ts——两者到仓库根同为三级向上,路径一致);新增 env 变量必须同步 `.env.example`;密钥不入库。
- env:命令一律在仓库根执行;根 `.env` 为唯一 env 文件,脚本经 dotenv-cli 注入、测试经 `test/load-env.ts` 载入(Task 7 约定;注意路径深度:`services/api/test`、`services/worker/test` 为三级向上(`../../../.env`),`packages/storage/test` 为**两级**向上(`../../.env`)——Task 11 复制时按包调整,或改为向上查找 pnpm-workspace.yaml 定位仓库根);新增 env 变量必须同步 `.env.example`;密钥不入库。
- 发现契约需变更时:先改 `packages/contracts` 并重新生成类型、在任务提交信息中登记,再改消费端(契约单一事实源)。
- 与总纲冲突处以总纲为准并回写修订;HEIC、MySQL 行值比较等 D12 复核项结论写入验收记录。
- P1a 完成后:编写 P1b 计划(viewer 基础页 + admin 最小页 + **宣传图/封面/Logo 上传链路(album_assets 的 presign+确认,复用照片上传机制,R09 依赖)** + **GET /albums/{albumId}/photos 管理端照片列表**(含未发布/隐藏态,照片管理入口)+ **用户账号查询接口**(邀请协作者时按 account 搜索)+ Playwright 冒烟)。