merge: 集成V2.5 AppData退场与权限审计

This commit is contained in:
2026-07-08 17:58:38 +08:00
156 changed files with 9487 additions and 285 deletions

View File

@@ -33,8 +33,8 @@ Requirement Version TestCase
| 前端 | Next.js 14 (App Router) | TypeScript + 客户端组件为主 |
| UI | Tailwind CSS + Shadcn/ui | 紧凑信息密度、现代风格 |
| 状态 | Zustand | 每个领域一个 store |
| 持久化 | PostgreSQL AppData + 关系表迁移层V2.4 | V2.2/V2.3 关系表用于热路径快读和写后同步V2.4 起领域关系表逐步成为主写入AppData 仅作兼容/迁移入口 |
| 后端 | NestJS + Prisma + PostgreSQLV2.4 | Product/Requirement 已有领域 CRUD其他领域正在从 AppData 向领域 API 迁移 |
| 持久化 | PostgreSQL 关系表领域主写 + AppData 兼容兜底V2.4/V2.5 | 高增长领域直接写关系表AppData 进入禁写、核对、归档退场阶段 |
| 后端 | NestJS + Prisma + PostgreSQLV2.5 | Product/Project/Version/Requirement/VersionPlan/DevTask/TestCase/Bug/Member/TaskCategory/TaskWorklog/Overtime/WorkActivity 均有领域 CRUDV2.5 收口 RBAC/审计/一致性 |
| AI | Anthropic SDKV3 远景) | 健康度/风险预警/排期建议 |
## 模块结构
@@ -47,7 +47,7 @@ apps/web/
│ ├── versions/ # 版本列表 + 详情
│ ├── requirements/ # 需求池
│ ├── workspace/ # 与我相关(聚合工作台)
│ └── admin/ # 系统管理(任务类型字典等
│ └── admin/ # 系统管理(成员/角色/任务类型/审计/一致性/AI 配置
├── components/
│ ├── product/ # 产品组件
│ ├── version/ # 版本组件PlanTab, CapsuleStages, MemberChips...
@@ -114,21 +114,32 @@ DevTask 没有"已完成"状态,"已提测"就是终态——开发交付完
## 数据持久化
**当前 V2.4 分层:** AppData 兼容写入 + 关系表快读/同步 + 领域 CRUD 主写迁移
**当前 V2.5 分层:** 领域 CRUD 主写 + AppData 禁写/核对/归档退场
兼容写入层仍使用通用服务端文档表 `app_data`
- 后端:`apps/server/src/modules/data/` 提供 `GET/PUT /api/v1/data/:key`
领域主写层已经覆盖主要业务实体
- 根数据Product、Project、Version 直接写领域 API`products-overview` 只作为兼容读取/兜底。
- 需求池Requirement 直接按 `productId` 分区键写 `requirements`,列表/search/filter/sort 使用服务端分页。
- 版本详情VersionPlan、DevTask、TestCase、Bug 直接按 `versionId` 分区键写关系表,并继续标脏 Xiaobao 摘要和写入工作活动证据。
- 字典/成员/证据Member 写 `users` 的成员身份字段TaskCategory 写 `task_categories`TaskWorklog、OvertimeRecord、WorkActivity 保持追加/证据型关系表写入。
V2.5 控制面新增三类横切能力:
- 权限:`apps/server/src/common/auth/` 提供当前用户解析、`@CurrentUser()``@RequirePermission()``PermissionGuard`。当前 V2.5 使用前端会话透传的 `x-ftb-user-*` 请求头作为服务端 auth adapter正式 JWT/NextAuth 接入仍属于后续认证阶段。
- 审计:`audit_events` 是 append-only 表,按 `created_at` 分区,领域 mutation 通过 `@ProtectedMutation()` 同时挂权限、资源作用域和 `AuditMutationInterceptor`。审计查询走 `GET /api/v1/audit`,需要 `audit:view`
- 一致性:`GET /api/v1/consistency``pnpm consistency:v25` 检查 counts、分区键、孤儿引用和审计覆盖。历史数据没有审计事件时只报 warning不阻断关系表主源运行。
兼容层仍保留通用服务端文档表 `app_data`
- 后端:`apps/server/src/modules/data/` 提供 `GET/PUT /api/v1/data/:key`V2.5 起所有业务 key 都由 `AppDataRetirementService` 标记为 `write_frozen``read_only_archive`,冻结写入返回 `409 APP_DATA_WRITE_FROZEN` 并给出替代领域 API。
- 数据库Prisma `AppData` 模型,表名 `app_data``key` 为主键,`value` 为 JSONB
- 一致性:`GET` 返回 `updatedAt` 派生的 `version`;前端保存时带上最近读取的 `version`,后端用 `key + updatedAt` 原子更新,版本不匹配返回 `409 APP_DATA_CONFLICT`
- 前端:各 Zustand store 保持现有数据形状,通过 `apps/web/lib/server-data.ts` 读写服务端
- 覆盖范围:产品/项目/版本树、需求池、调研/产品方案/UI 计划、开发任务、测试用例、Bug、成员/角色/部门、任务类型、任务工时日志、加班记录
- 前端:各 Zustand store 保持现有 UI 数据形状,优先调用 `apps/web/lib/domain-api.ts``apps/web/lib/server-data.ts` 只保留兼容读取和冻结写入错误处理,不再作为业务保存 fallback。
- 仍留在 AppData 历史形状中的内容:部门、角色、密码规则、加班原因等尚未拆出独立 RBAC/配置表的低频配置。`members``overtime` AppData key 已禁写;这些配置的独立表/API 归 V2.7 管理治理阶段承接。
- 浏览器仅保留登录会话(`ftb_auth_session` / `ftb_auth_persist`),不再作为业务数据主存储
关系表层已经包含 V2.2/V2.3 能力:
关系表层包含 V2.2-V2.4 能力:
- V2.2:高增长业务表使用分区表,并提供版本详情、需求池、工作台和小宝预警的快读 API。
- V2.3AppData 保存成功后触发关系表同步,让快读路径保持新鲜;同步失败只记日志,不阻塞用户保存。
V2.4 正在推进领域 CRUD 主写迁移Project、Version、VersionPlan、DevTask、TestCase、Bug、Member、TaskCategory、TaskWorklog、Overtime 等主写入需要逐步切到领域 API。迁移前不要恢复业务 localStorage 缓存,避免线上部署后出现多端数据分叉。
- V2.4:领域 CRUD 成为主写入路径AppData 写桥保留给历史数据和回滚兜底。不要恢复业务 localStorage 缓存,避免线上部署后出现多端数据分叉。
**目标主源(新方向):** 业务主数据必须落到 PostgreSQL 领域关系表。
- `app_data` 不再作为长期事实源,只保留迁移、回填、兼容读取和故障排查价值。
@@ -165,15 +176,17 @@ V2.4 正在推进领域 CRUD 主写迁移Project、Version、VersionPlan、De
生产数据库初始化使用 Prisma migration`pnpm --filter server db:deploy`。本地开发仍可使用 `pnpm db:migrate`
## 权限模型(轻量
## 权限模型(V2.5
V1 仅做前端校验,无后端鉴权
- 版本 `members` 字段限定参与者
- 版本列表/详情按 `members.contains(currentUser)` 过滤
- 创建版本时自动加入创建者
- 版本 `members` 为空时所有人可见(兼容旧数据)
V2.5 后端 mutation API 已接入服务端 RBAC
V2 接入后端后改为基于 `ProjectMember` 表的 RBACOwner/Admin/Member/Viewer
- 系统角色先按内置权限字典判断,`role-admin` 支持 wildcard `*`
-`projectId` / `versionId` 的请求会解析资源作用域;项目成员角色按 Owner/Admin/Member/Viewer 授权。
- 版本级资源如果能解析到项目,会优先用 `ProjectMember` 判断;具有系统权限的版本成员也可访问对应版本范围。
- 未认证返回 401已认证但无权限返回 403。
- `@ProtectedMutation(permission, scope, audit)` 是领域写接口的统一入口,避免权限和审计在 controller 中分散实现。
当前 auth context 仍是 V2.5 过渡 adapter前端从 `ftb_auth_session` / `ftb_auth_persist` 读取当前用户并透传 `x-ftb-user-*` 头。JWT/NextAuth 服务端校验、企业级角色/部门/配置表属于 V2.7 之前需要协调的认证治理工作。
## AI Agent 层
@@ -302,8 +315,9 @@ The server also has lightweight observability for this phase: a global API timin
Current source-of-truth boundary:
- Product and Requirement have domain CRUD modules.
- Project, Version, VersionPlan, DevTask, TestCase, Bug, Member, TaskCategory, TaskWorklog, Overtime, and WorkActivity relation models exist for V2.2/V2.3 mapping and fast reads, but their frontend write paths still mostly go through AppData stores.
- `products-overview` remains the primary document for the product/project/version tree until Project and Version write APIs replace it.
- V2.2 read APIs and V2.3 relation sync are compatibility infrastructure, not proof that every relation model already has a public CRUD API.
- `packages/shared` still contains early Requirement/Task status enums. Before switching frontend writes to domain APIs, align shared enums with the current workflow statuses in this document.
- Product, Project, Version, Requirement, VersionPlan, DevTask, TestCase, Bug, Member, TaskCategory, TaskWorklog, OvertimeRecord, and WorkActivity now have public domain CRUD/write APIs.
- Frontend stores use domain APIs as the primary mutation path. AppData reads remain for archive/fallback inspection, but business AppData writes are frozen server-side and return `APP_DATA_WRITE_FROZEN`.
- `products-overview` is no longer the product/project/version tree source of truth; it remains a compatibility document for fallback reads and rollback.
- V2.2 read APIs and V2.3 relation sync remain compatibility infrastructure for fast reads, historical AppData imports, and rollback. They are no longer the main proof of data freshness for domains that now write relation tables directly.
- `packages/shared` status contracts have been aligned with the current workflow statuses before the V2.4 write switch.
- V2.5 boundary: audit/RBAC/consistency are active on domain writes. Xiaobao risk snapshots/insights and warning read-state AppData keys are read-only archives pending V2.6 relation writer/backgrounding and V2.7 per-user read-state API.

View File

@@ -558,19 +558,26 @@
**理由**:这是从 AppData 兼容写入平滑过渡到领域 CRUD 的中间层。用户保存不能因为派生关系表暂时失败而丢失业务数据同时关系表保持跟随更新后V2.2 快读路径才能真正承受大数据量。把同步服务独立出来,也能让后续领域 CRUD 逐步替换 AppData 时复用同一套映射和小宝 dirty 策略。
## 44. 业务主数据源切换到 PostgreSQL 领域关系表
## 44. V2.4 领域 CRUD 成为主写入路径AppData 退为兼容兜底
**问题**AppData JSONB 文档表解决了浏览器 localStorage 丢数据问题,但如果继续把 `app_data.value` 当长期主数据源,会带来三个风险:整份 JSON 写入难以做字段级事务和权限校验,大数据量下筛选/分页/统计仍要依赖派生同步,线上排查时容易出现 AppData 与关系表不一致
**问题**V2.2/V2.3 让高增长页面优先读关系表,但前端主写仍长期停留在 AppData 时会形成“AppData 写入 + 关系表同步”的双层事实链。数据量继续增长后,需求池分页搜索、版本详情、与我相关和小宝预警仍会受 AppData 同步时效、整文档写入和双源理解成本影响
**决策**
- PostgreSQL 领域关系表是后续业务主数据源AppData 只保留为迁移、回填、兼容读取和审计排查入口
- 新增业务模块不得新增 AppData key 作为主存储必须先设计关系表、Prisma model、领域 CRUD API 和必要的索引/分区键
- 现有 AppData key 按领域逐步迁移:先补关系表写 API再让前端 store 写领域 API最后移除对应 `saveServerData/loadServerData` 主路径
- V2.2 快读失败时的 AppData fallback 只能作为迁移期兜底,不能通过硬编码 `usingV22=false` 长期绕开关系表
- 删除或停用 JSON 文档前必须完成数据备份、迁移计数核对、抽样校验和回滚预案
- 一次性同步脚本可以存在,但必须作为运维迁移工具管理,不能依赖提交 `.env` 或手工修改源码开关
- V2.4.0 先统一共享状态契约,避免领域 API 切换时把旧状态机重新带回系统
- V2.4.1-V2.4.4 将 Product、Project、Version、Requirement、VersionPlan、DevTask、TestCase、Bug 切为领域 API 主写
- V2.4.5 将 Member、TaskCategory、TaskWorklog、OvertimeRecord、WorkActivity 切为领域 API 主写
- 需求池列表/search/filter/sort 走服务端分页,避免加载全量 AppData 文档
- 版本详情实体按 `versionId` 分区键写入Requirement 按 `productId` 分区键写入;追加型证据表保留追加语义,不从 AppData 快照反向删除历史
- `/workspace``/xiaobao-warning` 继续走关系表聚合/快读。领域写成功后通过工作活动和小宝 dirty 标记维持证据链
- AppData 保留为兼容读取、失败回退、历史迁移和少量配置承载,不再作为已迁移领域的事实源。
- 成员迁移采用保守边界:`users` 存成员身份字段;部门、角色、密码规则暂不在本阶段发明完整 RBAC 表,仍作为 AppData 兼容配置。
- 加班原因同样暂留 AppData 配置;加班记录本身写 `overtime_records`
**理由**系统未来要承载大量需求、任务、测试用例、Bug、活动和风险数据。关系表才能提供可验证的约束、事务、索引、分页、权限和审计能力。AppData 是低风险迁移桥,不是最终架构;继续扩大 JSON 主存储会把数据一致性和性能问题推迟到更难修的阶段。
**理由**
- 领域 CRUD 直接写关系表后,读写路径对齐,分页、筛选、聚合和风险预警不再依赖 AppData 同步是否及时。
- 分区键进入每次领域写入,能维持 V2.2 分区表设计的查询边界。
- AppData fallback 让迁移可回滚、可兼容旧数据,但不再制造长期双事实源。
- RBAC/配置表会影响权限模型和管理流程单独成阶段更安全V2.4.5 只收口当前高频业务写入,避免为了“全收口”临时设计不稳的权限 schema。
## 45. V2 后端关系化采用八阶段交付链路
@@ -587,3 +594,32 @@
- V2.8:生产硬化稳定版 + 运维闭环。生产部署基线已存在V2.8 聚焦备份恢复演练、发布 smoke test、监控告警、日志检索、迁移回滚和运维手册。
**理由**:这条链路保持了从低风险兼容到强一致主源的顺序。权限/审计必须随领域 CRUD 进入代码路径否则后补会重写接口边界AppData 退场必须有闸门和回滚价值,不能直接删除;性能基础要从 V2.4 的 API 设计开始V2.6 只做规模化增强和后台化能力。这样每个阶段都有清晰验收物,也能避免长期双主源、无审计写入和大数据查询返工。
## 46. 业务主数据源切换到 PostgreSQL 领域关系表
**问题**AppData JSONB 文档表解决了浏览器 localStorage 丢数据问题,但如果继续把 `app_data.value` 当长期主数据源,会带来三个风险:整份 JSON 写入难以做字段级事务和权限校验,大数据量下筛选/分页/统计仍要依赖派生同步,线上排查时容易出现 AppData 与关系表不一致。
**决策**
- PostgreSQL 领域关系表是后续业务主数据源AppData 只保留为迁移、回填、兼容读取和审计排查入口。
- 新增业务模块不得新增 AppData key 作为主存储必须先设计关系表、Prisma model、领域 CRUD API 和必要的索引/分区键。
- 现有 AppData key 按领域逐步迁移:先补关系表写 API再让前端 store 写领域 API最后移除对应 `saveServerData/loadServerData` 主路径。
- V2.2 快读失败时的 AppData fallback 只能作为迁移期兜底,不能通过硬编码 `usingV22=false` 长期绕开关系表。
- 删除或停用 JSON 文档前必须完成数据备份、迁移计数核对、抽样校验和回滚预案。
- 一次性同步脚本可以存在,但必须作为运维迁移工具管理,不能依赖提交 `.env` 或手工修改源码开关。
**理由**系统未来要承载大量需求、任务、测试用例、Bug、活动和风险数据。关系表才能提供可验证的约束、事务、索引、分页、权限和审计能力。AppData 是低风险迁移桥,不是最终架构;继续扩大 JSON 主存储会把数据一致性和性能问题推迟到更难修的阶段。
## 47. V2.5 用冻结、审计和一致性校验收口迁移期,而不是直接删除 AppData
**问题**V2.4 已经把主要领域写入迁到关系表,但 AppData 里仍保存历史 JSON、旧部署 fallback 和少量尚未领域化的配置形状。如果直接删除 `app_data` 或移除 `/data/:key`,会失去回滚、迁移核对和历史排查依据;如果继续允许写入,又会把双事实源问题拖进 V2.6。
**决策**
- 每个 AppData key 明确进入 `write_frozen``read_only_archive`,由 `AppDataRetirementService` 集中配置替代 API 和说明。
- 冻结 key 的 `PUT /api/v1/data/:key` 返回 `409 APP_DATA_WRITE_FROZEN``GET` 继续可用,用于历史读取、归档导出和人工核对。
- Product/Project/Version/Requirement/VersionPlan/DevTask/TestCase/Bug/Member/TaskCategory/TaskWorklog/Overtime/WorkActivity 等领域 mutation 全部使用 `@ProtectedMutation()`,同一个装饰器组合权限、资源作用域和审计写入。
- `audit_events` 采用 append-only 模型,按 `created_at` 分区;敏感字段由 AuditService 脱敏,查询接口需要 `audit:view`
- 一致性校验同时提供 `GET /api/v1/consistency``pnpm consistency:v25`,检查 counts、分区键、孤儿引用和审计覆盖。历史数据缺少审计事件只作为 warning不把迁移前事实误判为当前写路径错误。
- 当前 server auth context 先用 `x-ftb-user-*` 头作为稳定 adapter前端从现有登录会话补齐这些头正式 JWT/NextAuth 服务端验证留给后续认证治理阶段。
- Xiaobao risk snapshots/insights 的 AppData key 进入 `read_only_archive`,关系表写入和后台化归 V2.6`xiaobao-warning-views` 读状态 API 归 V2.7。
**理由**:冻结写入能立即切断新的双主源风险,同时保留旧 JSON 的审计和回滚价值。把权限和审计合并到领域 mutation 装饰器,可以确保后续新增写接口默认带服务端 guard 和 audit event。审计覆盖对历史数据只告警避免为了“补齐历史审计”伪造事件。auth header adapter 给 V2.5 一个可测试的服务端权限边界,但不把它包装成最终安全方案,后续 JWT/企业 RBAC 可以替换 adapter 而不改领域 controller 合同。

View File

@@ -203,6 +203,38 @@ pnpm deploy:check-runtime http://localhost/api/v1/health/version <expected-commi
浏览器不再作为业务数据主存储。清浏览器缓存不会删除产品、项目、版本、任务、测试用例、Bug 等业务数据。
## AppData 归档与校验V2.5
V2.5 起,已迁移业务 key 的 `PUT /api/v1/data/:key` 会返回 `409 APP_DATA_WRITE_FROZEN`,读路径仍保留给历史核对和回滚。停用 AppData 写入前后都建议导出一份只读归档:
```bash
pnpm appdata:archive:export -- --out backups/appdata-archive-$(date +%Y%m%d%H%M%S).json
pnpm appdata:archive:verify -- --archive backups/appdata-archive-20260708120000.json
```
归档 JSON 包含:
- `metadata.appVersion` / `metadata.appBuildTime` / `metadata.sourceCommit`:导出时的应用版本信息。
- `keys`:本次导出的 AppData key 列表。
- `rows[].valueChecksum`:每个 key 的 JSON 内容 SHA-256。
- `metadata.payloadChecksum`:整份 key list + rows payload 的 SHA-256。
生产环境执行导出前需要确保 `DATABASE_URL` 指向当前 PostgreSQL。默认输出文件名为 `appdata-archive-<timestamp>.json`,该模式已加入 `.gitignore`;真实归档应放入服务器备份目录或对象存储,不提交到代码仓库。
## V2.5 一致性校验
完成数据库 migration、AppData 写冻结和归档导出后,建议在发布窗口内运行一致性校验:
```bash
pnpm consistency:v25 -- --url http://localhost/api/v1/consistency
```
本地开发默认检查 `http://localhost:3001/api/v1/consistency`,也可以不传 `--url`。校验内容包括 counts、分区键、孤儿引用和审计覆盖
- `error` 必须在发布前修复。
- `warn` 需要记录原因;历史数据没有审计事件属于预期 warning不阻断 V2.5。
- 后台页面 `/admin/consistency` 展示同一份报告,需要当前用户具备 `consistency:view`
## 升级流程
```bash

View File

@@ -1,17 +1,19 @@
# 开发路线图
## 当前阶段V2.4 — 领域 CRUD 主写迁移
## 当前阶段V2.5 已完成 — 下一阶段 V2.6 大数据性能增强 + 小宝预警后台化
V2.4 的目标是把业务主数据源从 AppData JSONB 文档切换到 PostgreSQL 领域关系表。AppData 继续保留为迁移、回填、兼容读取和排查入口,但不再作为长期主写入源;新增业务能力必须优先设计关系表、领域 CRUD API、索引/分区键和权限边界。V2.4 做逐领域主写迁移,并随 CRUD 入口埋好基础权限、`actorId` 和审计事件骨架;完整 RBAC、审计覆盖和 AppData 退场收口放到 V2.5
V2.4 已将高增长和核心业务领域从“AppData 主写 + 关系表同步副本”推进到“领域 CRUD 主写关系表 + AppData 兼容/迁移兜底”。V2.2 快读 API 和 V2.3 AppData 写后同步继续保留,但它们现在是兼容基础设施,不再是已迁移领域的数据新鲜度主链路
### 当前重点
V2.5 的目标是正式收口后端权限、审计、AppData 禁写和一致性核对。AppData 不能直接删除,必须按“禁写 → 双读核对 → 移除 fallback → 只读归档/导出 → 后续删表”的顺序推进。
1. **领域写 API**:按模块补齐 Product/Project/Version/Requirement/VersionPlan/DevTask/TestCase/Bug/Member/TaskCategory/Worklog/Overtime 的关系表写入 API。
2. **前端持久化切换**Zustand store 保留状态管理,但保存入口从 `saveServerData(key)` 迁到领域 API读取优先 V2.2/V2.3 关系表接口。
3. **AppData 迁移工具化**:把 AppData → 关系表同步做成可重复运行、可计数校验、可回滚的运维脚本,不提交真实 `.env`
4. **主写切换闸门**:每个领域完成双读核对后,先停止该领域 JSON 主写入,再进入 V2.5 的 fallback 移除和归档退场
5. **数据一致性校验**:为每个迁移领域补 counts、抽样记录、孤儿引用、分区键完整性和唯一约束校验
6. **权限/审计骨架**:领域 API 必须携带当前用户、产品/项目/版本作用域和审计事件入口,避免 V2.5 做 RBAC 时返工
### V2.5 完成范围
1. **RBAC 收口**:领域 mutation API 已接入服务端权限校验、资源作用域和当前用户上下文
2. **审计事件**:领域 mutation 通过 `audit_events` 写 append-only audit event支持后台查询和敏感字段脱敏
3. **AppData 禁写**:业务 AppData key 已进入 `write_frozen``read_only_archive`,读仍可用,写返回明确替代领域 API
4. **导出归档**:已提供 AppData archive export/verify 脚本,包含 checksum、key list 和应用版本元数据
5. **一致性校验**:已提供 counts、partition key、orphan refs、audit coverage 的本地脚本和后台页面。
6. **管理端可视化**:已补 `/admin/audit``/admin/consistency`,并由 `audit:view` / `consistency:view` 控制。
## V2 分阶段交付链路
@@ -31,15 +33,34 @@ V2.4 的目标是把业务主数据源从 AppData JSONB 文档切换到 PostgreS
### 当前状态快照2026-07-08
- 项目已经不是早期骨架。前端业务功能已覆盖产品、项目、版本详情、需求池、工作台、成员/角色/任务类型、加班、小宝预警和 AI 配置等主要管理端路由。
- 版本详情已有需求、调研、产品方案、UI、开发任务、测试用例、Bug、概览等核心 Tab渲染重的路径优先接入 V2.2 关系表快读,并保留 AppData fallback。
- 后端已落地 Product、Requirement 领域 CRUDDataModule AppData 乐观锁V2.2 快读 APIV2.3 AppData 写后同步关系表AI Provider 抽象和健康版本接口
- Prisma schema 已包含 Product、Project、Version、Requirement、VersionPlan、DevTask、TestCase、Bug、WorkActivity、Xiaobao、AiLog、AppData 等关系模型;高增长表的分区 migration 已落地。
- 主写入源仍处在兼容窗口:多数前端 store 继续通过 `apps/web/lib/server-data.ts``loadServerData` / `saveServerData` 写 AppData`useProductStore` 仍以 `products-overview` 文档作为产品/项目/版本树主写入
- Project、Version、VersionPlan、DevTask、TestCase、Bug、Member、TaskCategory、TaskWorklog、Overtime 等领域写 API 尚未完整替代 AppData Store。若后续称为 V2.4,应理解为“领域 CRUD 迁移阶段”,不是 V2.3 已完成内容
- `packages/shared` 中仍保留早期枚举口径;切换领域 API 时需要统一为当前前端业务状态机
- 版本详情已有需求、调研、产品方案、UI、开发任务、测试用例、Bug、概览等核心 Tab渲染重的路径优先接入关系表快读并保留 AppData fallback。
- 后端已落地 Product、Project、Version、Requirement、VersionPlan、DevTask、TestCase、Bug、Member、TaskCategory、TaskWorklog、Overtime、WorkActivity 领域 CRUD/write API
- Prisma schema 已包含 Product、Project、Version、Requirement、VersionPlan、DevTask、TestCase、Bug、WorkActivity、TaskWorklog、Overtime、Xiaobao、AiLog、AppData 等关系模型;高增长表的分区 migration 已落地。
- 主写入源已经切到领域 API前端 store 优先调用 `apps/web/lib/domain-api.ts`AppData 只保留兼容读取、历史核对和少量旧配置形状
- V2.5 后端服务端权限、审计和一致性控制面已启用:领域 mutation 使用 `@ProtectedMutation()`,审计写 `audit_events`,后台查询需要 `audit:view` / `consistency:view`
- 所有业务 AppData key 已明确冻结或只读归档;`PUT /api/v1/data/:key` 对这些 key 返回 `APP_DATA_WRITE_FROZEN``GET` 留作历史核对与归档
- 需求池已切到服务端分页、搜索、筛选、排序,不再要求加载全量 AppData 文档。
- `packages/shared` 状态契约已统一为当前业务状态机。
- V2.6/V2.7 协调边界Xiaobao risk snapshots/insights 关系表写入和后台化归 V2.6warning read-state API、部门/角色/密码规则/加班原因配置表归 V2.7。
### 已完成(按时间倒序)
**2026-07-08**
- V2.5.0 added server auth context, current-user decorator, permission decorator/guard/service, wildcard super admin support, project/version-member scope checks, and guard/service tests.
- V2.5.1 added append-only `audit_events`, audit service/controller/query DTO, sensitive-field redaction, `audit:view`, and audit service/controller tests.
- V2.5.2 protected V2.4 domain mutation APIs with server-side permission metadata and audit writes through `@ProtectedMutation()`.
- V2.5.3 froze AppData business writes through `AppDataRetirementService`, returning `APP_DATA_WRITE_FROZEN` while preserving reads and replacement-path hints.
- V2.5.4 added AppData archive export/verify scripts and package scripts with checksum, key list, and app version metadata.
- V2.5.5 added consistency module/controller/script for counts, partition keys, orphan refs, and audit coverage; historical audit gaps are warnings.
- V2.5.6 added `/admin/audit` and `/admin/consistency` pages plus frontend API helpers and permission entries.
- V2.4.0 completed shared domain status contract alignment for Requirement, VersionPlan, DevTask, TestCase, Bug, and Version.
- V2.4.1 switched Product / Project / Version root mutations to domain APIs and left `products-overview` as compatibility fallback.
- V2.4.2 switched Requirement writes to relation-table CRUD and added server-side pagination, search, filters, sorting, and cursor support for the requirement pool.
- V2.4.3 switched VersionPlan and DevTask writes to version-scoped domain APIs, with work activity evidence and Xiaobao dirty marking.
- V2.4.4 switched TestCase and Bug writes to version-scoped domain APIs, preserving round-copy and bug workflow behavior.
- V2.4.5 switched Member, TaskCategory, TaskWorklog, OvertimeRecord, and WorkActivity writes to domain APIs. AppData remains only for compatibility fallback and low-frequency config such as departments, roles, password rules, and overtime reasons.
- Added focused source-contract tests proving migrated frontend stores use domain APIs as primary writes rather than AppData document saves.
**2026-07-06**
- Added production CI/CD flow: GitHub Actions builds `web` and `server` Docker images, pushes immutable commit-SHA tags to GHCR, deploys by SSH, pulls images on the server, runs `pnpm --filter server db:deploy`, restarts Compose, and verifies `/api/v1/health/version`.
- Added runtime version metadata: backend `GET /api/v1/health/version`, Docker build args/env, and a frontend refresh banner when browser assets are older than the server runtime.
@@ -74,6 +95,11 @@ V2.4 的目标是把业务主数据源从 AppData JSONB 文档切换到 PostgreS
- 新增 `pnpm deploy:verify` 校验生产部署文件完整性
- 新增 `docs/deployment.md`,覆盖本地开发、云服务器部署、升级、备份和排查流程
**2026-06-26**
- Workspace daily report upgraded from manual worklog summary to mixed activity aggregation.
- Added `work-activities` AppData key and a typed activity factory for VersionPlan, DevTask, TestCase, and Bug actions.
- `/workspace` daily report now groups delivery/progress/creation/risk/progress-note records and flags in-progress work that needs today's progress update.
**2026-06-24**
- 新增 NestJS `DataModule` + Prisma `AppData`,提供 `GET/PUT /api/v1/data/:key`
- 产品/项目/版本树、需求池、调研/产品方案/UI、开发任务、测试用例、Bug 改为服务端持久化
@@ -117,41 +143,55 @@ V2.4 的目标是把业务主数据源从 AppData JSONB 文档切换到 PostgreS
### 进行中
- V2.4 领域 CRUD 主写迁移:从 AppData JSONB 主写入切换到关系表 API并随 API 落基础权限、审计和查询性能边界
- V2.6 大数据性能增强与小宝预警后台化压测、慢查询治理、后台任务、Xiaobao relation writer、幂等与失败重试
- 项目详情页 VersionCard 状态胶囊数据联动(部分已完成)
## V2 — 后端接入
NestJS + Prisma + PostgreSQL 已接入到 V2.3。第一阶段用 `app_data` JSONB 文档表承接现有 store 数据形状,避免浏览器清站点数据导致业务数据丢失;第二阶段建立分区关系表、V2.2 快读 API 和 V2.3 AppData 写后同步。当前 V2.4 才是逐领域启用写 API让前端 store 从 AppData 主写入迁移到领域 CRUDAppData 后续只保留为迁移兼容层
NestJS + Prisma + PostgreSQL 已推进到 V2.5。第一阶段用 `app_data` JSONB 文档表承接现有 store 数据形状避免浏览器清站点数据导致业务数据丢失第二阶段建立分区关系表、V2.2 快读 API 和 V2.3 AppData 写后同步;第三阶段 V2.4 逐领域启用写 API让前端 store 从 AppData 主写入迁移到领域 CRUD 主写;第四阶段 V2.5 已冻结 AppData 业务写入并收口服务端 RBAC、审计和一致性校验
### 关键任务
1. **服务端文档层**`app_data` + `/api/v1/data/:key`(第一阶段已实现)
2. **localStorage → API 切换**:业务主数据不再写浏览器(第一阶段已实现)
3. **运行 Prisma 同步/迁移**:本地和服务器数据库都需要创建 `app_data` 与 V2.2/V2.3 关系表
4. **关系化拆表**:把稳定模块从 JSONB 拆成 Product/Project/Version/Task 等领域表(关系模型同步桥已落地,领域写 API 仍待迁移
5. **领域 CRUD 主写入**:前端保存不再写整份 JSON 文档,而是调用具体领域 API 写关系表
6. **基础权限/审计骨架**:领域 API 从迁移期开始接入用户身份、资源作用域、操作人和审计事件入口
7. **AppData 主路径移除**完成迁移核对后逐模块删除 JSON fallback 和 `/data/:key` 主写入依赖
8. **认证**NextAuth.js + JWT
9. **权限**RBACOwner/Admin/Member/Viewer按项目/版本级别
4. **关系化拆表**:把稳定模块从 JSONB 拆成 Product/Project/Version/Task 等领域表(关系模型同步桥和 V2.4 领域写 API 已落地
5. **领域 CRUD 主写入**:前端保存不再写整份 JSON 文档,而是调用具体领域 API 写关系表V2.4 已完成)
6. **基础权限/审计骨架**:领域 API 从迁移期开始接入用户身份、资源作用域、操作人和审计事件入口V2.5 已收口)
7. **AppData 主路径移除**业务写入已冻结;后续按核对结果逐模块删除 JSON fallback 和 `/data/:key` 依赖
8. **认证**当前为 V2.5 header auth adapter正式 NextAuth.js + JWT 服务端校验待后续治理
9. **权限**RBACOwner/Admin/Member/Viewer按项目/版本级别V2.5 服务端 guard 已启用,企业级配置表待 V2.7
10. **版本规则引擎收敛**VersionPlan 完成条件、关联需求候选、TaskCategory 语义码、TestCase.categoryId 统一收束到规则层
### 数据迁移策略
当前不做本地导入导出。清站点数据后浏览器旧数据无法恢复,后续新增数据直接写入 PostgreSQL。若以后需要迁移旧浏览器数据再单独做管理员导入工具。
## V2.4 — 领域 CRUD 迁移(当前阶段
## V2.4 — 领域 CRUD 迁移(已完成
目标是让关系表从“快读 + AppData 同步副本”逐步升级为主写入路径。迁移顺序应优先选择写入频率高、实体边界清晰、已经在 V2.2 mapper 中稳定的领域
目标是让关系表从“快读 + AppData 同步副本”升级为主写入路径。V2.4 按以下顺序完成
1. Project / Version替代 `products-overview` 中的项目和版本主写入,保留产品树兼容读取
2. VersionPlan / DevTask / TestCase / Bug`versionId` 分区键提供领域写 API写入后继续复用现有小宝 dirty 策略和工作活动记录
3. Member / TaskCategory替代 `members``task-categories` AppData 文档,统一权限、人员和任务类型字典来源
4. TaskWorklog / Overtime / WorkActivity保留追加型写入语义避免从当前 AppData 快照反向删除历史证据
5. 前端 store 分批切换:每切一个领域,都要保留兼容读取和回滚路径,直到 AppData 对应 key 不再是事实源
1. V2.4.0:统一 `packages/shared` 状态枚举与当前前端业务口径
2. V2.4.1Project / Version 替代 `products-overview` 中的项目和版本主写入,产品树文档保留兼容读取
3. V2.4.2Requirement 按 `productId` 分区键主写,并支持需求池服务端分页、搜索、筛选、排序
4. V2.4.3VersionPlan / DevTask 按 `versionId` 分区键主写,写入后继续复用小宝 dirty 策略和工作活动记录
5. V2.4.4TestCase / Bug 按 `versionId` 分区键主写,保留测试轮次和缺陷闭环
6. V2.4.5Member / TaskCategory / TaskWorklog / Overtime / WorkActivity 主写关系表,证据型数据保留追加语义。
V2.4 推进前必须先统一 `packages/shared` 的状态枚举与当前前端业务口径,避免领域 API 切换时把旧的 `draft/reviewing/approved``todo/in_review/done/closed` 状态重新带回系统
V2.4 完成后的兼容边界AppData 不再是上述领域的事实源,只用于 fallback、历史迁移和少量配置。部门、角色、密码规则、加班原因仍作为兼容配置保留后续由 RBAC/配置表阶段单独收口
## V2.5 — AppData 退场 + RBAC/审计/一致性收口(已完成)
V2.5 在 V2.4 领域 CRUD 主写基础上完成横切收口:
1. Server auth context、`@CurrentUser()``@RequirePermission()``PermissionGuard``PermissionService` 已落地。
2. `@ProtectedMutation()` 成为领域写接口统一入口,同时挂权限、资源作用域和审计 metadata。
3. `audit_events` append-only 表、审计查询接口和 `/admin/audit` 页面已落地。
4. `AppDataRetirementService` 集中声明每个 AppData key 的 `write_frozen` / `read_only_archive` 状态与替代路径。
5. AppData archive export/verify 脚本已落地,归档包含 checksum、key list 和 app version metadata。
6. Consistency module、`pnpm consistency:v25``/admin/consistency` 页面已落地。
V2.5 完成后的保留边界:`GET /api/v1/data/:key` 仍可读历史 JSONXiaobao risk archive、warning read state、部门/角色/密码规则和加班原因配置表分别交给 V2.6/V2.7,不在 V2.5 临时发明不稳定 schema。
## V3 — AI Agent 集成
@@ -168,14 +208,14 @@ V2.4 推进前必须先统一 `packages/shared` 的状态枚举与当前前端
- 编辑后自动清除 aiDraft 标记
- agent-spec.md / glossary.md 文档落地
- 约定:原型链接 = 产品方案 (VersionPlan type=product) 已完成计划的 resultUrl不在 Version 上独立存储
- V2.4 已完成 DevTask/TestCase/Bug 的 `versionId` 版本主归属和领域主写AI 写入可直接走版本级领域 API。
**待实现**
1. 后端 `AiGateway` + `PrototypeDecomposeService`NestJS module
2. 前端「AI 拆解任务和用例」按钮(产品方案 Tab
3. 对账报告组件(弹窗呈现:完美对应 / 需求未见原型 / 无需求ID分组 / 含糊)
4. 用户确认后批量创建 DevTask + TestCase 草案
5. DevTask 增加 `versionId``requirementId` 改为可选,兼容旧数据通过需求反查版本
6. AiLog 表调用记录、token 计量、用时)
5. AiLog 表调用记录、token 计量、用时)
**MVP 范围限制**
- 不自动分配 assignee留给用户在草案上手填
@@ -221,10 +261,6 @@ V2.4 推进前必须先统一 `packages/shared` 的状态枚举与当前前端
|------|------|
| V1 业务流程打磨 | 进行中 |
| V1 朋友试用反馈 | 持续中 |
| V2 后端接入 | 进行中V2.1/V2.2/V2.3 已完成V2.4 主写迁移中 |
| V2 后端接入 | 进行中V2.5 RBAC/审计/AppData 退场已完成V2.6/V2.7 待推进 |
| V3 AI 集成 | 等 V2 数据沉淀 |
| 公开发布 | TBD |
**2026-06-26**
- Workspace daily report upgraded from manual worklog summary to mixed activity aggregation.
- Added `work-activities` AppData key and a typed activity factory for VersionPlan, DevTask, TestCase, and Bug actions.
- `/workspace` daily report now groups delivery/progress/creation/risk/progress-note records and flags in-progress work that needs today's progress update.

View File

@@ -0,0 +1,236 @@
# V2.4 Domain CRUD Migration Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Move V2.4.0 through V2.4.5 from AppData-primary writes to domain CRUD primary writes backed by relation tables, while keeping AppData only as compatibility and migration fallback.
**Architecture:** Keep V2.2 query APIs and V2.3 AppData sync as compatibility infrastructure, then add focused NestJS domain modules that write relation tables directly and reuse Xiaobao dirty marking plus work-activity evidence rules. Frontend stores switch one domain at a time to domain APIs with AppData fallback reads until each AppData document is no longer a source of truth.
**Tech Stack:** Next.js 14 App Router, Zustand stores, NestJS, Prisma, PostgreSQL partitioned relation tables, Jest, node:test, TypeScript.
## Global Constraints
- Work only in `/Users/wanzi/Documents/xiaowanzi-claudecode/ftb-project-management-v24-worktree` on branch `codex/v2.4-domain-crud`.
- Do not edit the original dirty checkout.
- Do not push unless the user explicitly asks.
- Follow TDD: each behavior change starts with a failing test, then minimal implementation, then verification.
- Keep `/workspace` and `/xiaobao-warning` as relation-table read aggregations.
- Keep AppData as compatibility fallback only; do not introduce long-term dual-source writes.
- For partitioned tables, every lookup or mutation must carry the partition key: `productId` for requirements and `versionId` for version detail entities.
- `pnpm lint` is not a V2.4 gate until the baseline ESLint setup is fixed; current baseline fails because server/shared lint tooling is missing.
---
### Task 1: V2.4.0 Domain Contract Unification
**Files:**
- Modify: `packages/shared/src/enums.ts`
- Modify: `packages/shared/src/index.ts`
- Modify: `apps/server/src/modules/requirement/requirement.service.spec.ts`
- Modify: `apps/server/src/modules/requirement/requirement.service.ts`
- Modify: `apps/server/src/modules/requirement/dto/update-requirement-status.dto.ts`
- Modify: `apps/web/lib/requirement.ts`
- Modify: `apps/web/lib/dev-task.ts`
- Modify: `apps/web/lib/test-case.ts`
- Modify: `apps/web/lib/bug.ts`
- Modify: `apps/web/lib/version-plan.ts`
**Interfaces:**
- Produces: shared status constants/enums for Requirement, VersionPlan, DevTask, TestCase, Bug, and Version.
- Consumes: current frontend status values documented in `docs/architecture.md`.
- [x] Add failing shared contract tests proving shared statuses equal current frontend statuses.
- [x] Add failing backend tests proving Requirement transitions use `pending_review -> adopted/rejected`, `rejected -> pending_review`, and `adopted -> planned -> developing -> testing -> released -> closed`.
- [x] Replace old shared `draft/reviewing/approved/delivered` requirement status contract with current domain statuses.
- [x] Add shared contracts for `VersionPlanStatus`, `DevTaskStatus`, `TestCaseStatus`, `BugStatus`, and `VersionStatus`.
- [x] Update backend Requirement DTO validation and service transition table.
- [x] Run targeted tests: `pnpm --filter server test -- requirement.service.spec.ts` and shared/web tests added in this task.
- [x] Run gates: `pnpm type-check`, `pnpm test`, `pnpm build`, `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm pnpm --filter server exec prisma validate --schema prisma/schema.prisma`, `pnpm deploy:verify`.
- [x] Commit: `feat(v2.4): 统一领域状态契约`.
### Task 2: V2.4.1 Product / Project / Version Root Main Writes
**Files:**
- Create: `apps/server/src/modules/project/project.module.ts`
- Create: `apps/server/src/modules/project/project.controller.ts`
- Create: `apps/server/src/modules/project/project.service.ts`
- Create: `apps/server/src/modules/project/dto/create-project.dto.ts`
- Create: `apps/server/src/modules/project/dto/update-project.dto.ts`
- Create: `apps/server/src/modules/project/project.service.spec.ts`
- Create: `apps/server/src/modules/version/version.module.ts`
- Create: `apps/server/src/modules/version/version.controller.ts`
- Create: `apps/server/src/modules/version/version.service.ts`
- Create: `apps/server/src/modules/version/dto/create-version.dto.ts`
- Create: `apps/server/src/modules/version/dto/update-version.dto.ts`
- Create: `apps/server/src/modules/version/version.service.spec.ts`
- Modify: `apps/server/src/modules/product/product.service.ts`
- Modify: `apps/server/src/app.module.ts`
- Create: `apps/web/lib/domain-api.ts`
- Modify: `apps/web/stores/useProductStore.ts`
- Modify: `apps/web/lib/product-overview-persistence.test.ts`
- Modify: `apps/web/lib/product-store-persistence-source.test.ts`
**Interfaces:**
- Produces: `/api/v1/products`, `/api/v1/products/:productId/projects`, `/api/v1/products/:productId/versions`, and `/api/v1/products/:productId/projects/:projectId/versions`.
- Consumes: existing product/project/version tree shape from `products-overview`.
- [x] Add failing backend tests for project create/list/update/delete by `productId`.
- [x] Add failing backend tests for version create/list/update/delete by `productId` and optional `projectId`.
- [x] Add failing tests proving deleting a version releases linked requirements and deletes version-scoped plans/tasks/test cases/bugs.
- [x] Add failing frontend tests proving `useProductStore` saves root mutations through domain APIs and falls back to `products-overview` when APIs are unavailable.
- [x] Implement Project and Version modules with conservative DTO validation.
- [x] Keep Product CRUD as the top-level root and add child include helpers only where needed.
- [x] Switch Product store mutations to domain APIs while retaining AppData compatibility read.
- [x] Run targeted backend and frontend tests.
- [x] Run full gates and commit: `feat(v2.4): 切换根数据领域主写`.
### Task 3: V2.4.2 Requirement Main Writes And Server Pagination
**Files:**
- Modify: `apps/server/src/modules/requirement/requirement.controller.ts`
- Modify: `apps/server/src/modules/requirement/requirement.service.ts`
- Modify: `apps/server/src/modules/requirement/dto/create-requirement.dto.ts`
- Modify: `apps/server/src/modules/requirement/dto/update-requirement.dto.ts`
- Modify: `apps/server/src/modules/requirement/requirement.service.spec.ts`
- Modify: `apps/server/src/modules/v22-query/v22-query.service.ts`
- Modify: `apps/web/lib/requirement-v22-query.ts`
- Modify: `apps/web/stores/useRequirementStore.ts`
- Modify: `apps/web/lib/requirement-sort.test.ts`
- Modify: `apps/web/lib/requirement-v22-query.test.ts`
**Interfaces:**
- Produces: requirement create/update/delete/status/link APIs that write `requirements` directly by `(id, productId)`.
- Produces: server-side list contract with `productId`, `projectId`, `versionId`, `status`, `priority`, `type`, `q`, `sort`, `cursor`, and `limit`.
- [x] Add failing backend tests for server pagination, search, filters, sort, cursor, and partition-key validation.
- [x] Add failing tests for create/update fields currently present in frontend requirements: `projectId`, `versionId`, `type`, `sourceType`, `sourceTarget`, and `platform`.
- [x] Add failing frontend tests proving requirement pool calls server pagination and does not require loading the full AppData document for list/search/filter/sort.
- [x] Implement service-side query parsing and safe order fields.
- [x] Switch `useRequirementStore` create/update/delete/status/link writes to Requirement APIs.
- [x] Keep AppData read fallback only when relation API is unavailable.
- [x] Run targeted tests and full gates.
- [x] Commit: `feat(v2.4): 切换需求池领域主写`.
### Task 4: V2.4.3 VersionPlan / DevTask Main Writes
**Files:**
- Create: `apps/server/src/modules/version-plan/version-plan.module.ts`
- Create: `apps/server/src/modules/version-plan/version-plan.controller.ts`
- Create: `apps/server/src/modules/version-plan/version-plan.service.ts`
- Create: `apps/server/src/modules/version-plan/dto/create-version-plan.dto.ts`
- Create: `apps/server/src/modules/version-plan/dto/update-version-plan.dto.ts`
- Create: `apps/server/src/modules/version-plan/version-plan.service.spec.ts`
- Create: `apps/server/src/modules/dev-task/dev-task.module.ts`
- Create: `apps/server/src/modules/dev-task/dev-task.controller.ts`
- Create: `apps/server/src/modules/dev-task/dev-task.service.ts`
- Create: `apps/server/src/modules/dev-task/dto/create-dev-task.dto.ts`
- Create: `apps/server/src/modules/dev-task/dto/update-dev-task.dto.ts`
- Create: `apps/server/src/modules/dev-task/dev-task.service.spec.ts`
- Create: `apps/server/src/modules/work-activity/work-activity.module.ts`
- Create: `apps/server/src/modules/work-activity/work-activity.service.ts`
- Create: `apps/server/src/modules/work-activity/work-activity.service.spec.ts`
- Modify: `apps/server/src/modules/migration/app-data-v23-sync.service.ts`
- Modify: `apps/server/src/app.module.ts`
- Modify: `apps/web/stores/useVersionPlanStore.ts`
- Modify: `apps/web/stores/useDevTaskStore.ts`
- Modify: `apps/web/stores/useWorkActivityStore.ts`
- Modify: `apps/web/lib/version-plan.test.ts`
- Modify: `apps/web/lib/version-plan-workflow.test.ts`
- Modify: `apps/web/lib/dev-task.test.ts`
- Modify: `apps/web/lib/dev-task-transitions.test.ts`
**Interfaces:**
- Produces: `/api/v1/versions/:versionId/plans` and `/api/v1/versions/:versionId/dev-tasks`.
- Produces: minimal relational `WorkActivityService.record()` for successful plan/task domain actions.
- [x] Add failing backend tests for VersionPlan create/update/status/complete writing `version_plans`.
- [x] Add failing backend tests for DevTask create/update/status/block/unblock/transfer writing `dev_tasks` by `(id, versionId)`.
- [x] Add failing backend tests proving status changes create `work_activities` records and mark Xiaobao summaries dirty.
- [x] Add failing frontend tests proving plan/task stores write domain APIs and append activity evidence from API responses.
- [x] Implement VersionPlan and DevTask modules using existing frontend workflow rules as the contract.
- [x] Add minimal WorkActivity service and reuse V2.3 dirty-summary strategy.
- [x] Switch version plan and dev task stores to domain writes with AppData fallback read only.
- [x] Run targeted tests and full gates.
- [x] Commit: `feat(v2.4): 切换计划与开发任务主写`.
### Task 5: V2.4.4 TestCase / Bug Main Writes
**Files:**
- Create: `apps/server/src/modules/test-case/test-case.module.ts`
- Create: `apps/server/src/modules/test-case/test-case.controller.ts`
- Create: `apps/server/src/modules/test-case/test-case.service.ts`
- Create: `apps/server/src/modules/test-case/dto/create-test-case.dto.ts`
- Create: `apps/server/src/modules/test-case/dto/update-test-case.dto.ts`
- Create: `apps/server/src/modules/test-case/test-case.service.spec.ts`
- Create: `apps/server/src/modules/bug/bug.module.ts`
- Create: `apps/server/src/modules/bug/bug.controller.ts`
- Create: `apps/server/src/modules/bug/bug.service.ts`
- Create: `apps/server/src/modules/bug/dto/create-bug.dto.ts`
- Create: `apps/server/src/modules/bug/dto/update-bug.dto.ts`
- Create: `apps/server/src/modules/bug/bug.service.spec.ts`
- Modify: `apps/server/src/modules/work-activity/work-activity.service.ts`
- Modify: `apps/server/src/app.module.ts`
- Modify: `apps/web/stores/useTestCaseStore.ts`
- Modify: `apps/web/stores/useBugStore.ts`
- Modify: `apps/web/lib/test-case.test.ts`
- Modify: `apps/web/lib/test-case-workflow.test.ts`
- Modify: `apps/web/lib/bug.test.ts`
- Modify: `apps/web/lib/bug-workflow.test.ts`
**Interfaces:**
- Produces: `/api/v1/versions/:versionId/test-cases` and `/api/v1/versions/:versionId/bugs`.
- Consumes: TestCase round-copy workflow and Bug status workflow already defined in frontend helpers.
- [x] Add failing backend tests for TestCase create/update/status/round-copy by `(id, versionId)`.
- [x] Add failing backend tests for Bug create/update/status/transfer/close by `(id, versionId)`.
- [x] Add failing tests proving TestCase/Bug writes create activity evidence and mark Xiaobao dirty.
- [x] Add failing frontend tests proving stores write domain APIs and preserve existing workflow outputs.
- [x] Implement TestCase and Bug modules.
- [x] Switch test case and bug stores to domain writes with AppData fallback read only.
- [x] Run targeted tests and full gates.
- [x] Commit: `feat(v2.4): 切换测试与缺陷主写`.
### Task 6: V2.4.5 Dictionaries, Members, Worklogs, Overtime, Activity Evidence Consolidation
**Files:**
- Create: `apps/server/src/modules/member/member.module.ts`
- Create: `apps/server/src/modules/member/member.controller.ts`
- Create: `apps/server/src/modules/member/member.service.ts`
- Create: `apps/server/src/modules/member/member.service.spec.ts`
- Create: `apps/server/src/modules/task-category/task-category.module.ts`
- Create: `apps/server/src/modules/task-category/task-category.controller.ts`
- Create: `apps/server/src/modules/task-category/task-category.service.ts`
- Create: `apps/server/src/modules/task-category/task-category.service.spec.ts`
- Create: `apps/server/src/modules/task-worklog/task-worklog.module.ts`
- Create: `apps/server/src/modules/task-worklog/task-worklog.controller.ts`
- Create: `apps/server/src/modules/task-worklog/task-worklog.service.ts`
- Create: `apps/server/src/modules/task-worklog/task-worklog.service.spec.ts`
- Create: `apps/server/src/modules/overtime/overtime.module.ts`
- Create: `apps/server/src/modules/overtime/overtime.controller.ts`
- Create: `apps/server/src/modules/overtime/overtime.service.ts`
- Create: `apps/server/src/modules/overtime/overtime.service.spec.ts`
- Modify: `apps/server/src/modules/work-activity/work-activity.service.ts`
- Modify: `apps/server/src/app.module.ts`
- Modify: `apps/web/stores/useMemberStore.ts`
- Modify: `apps/web/stores/useTaskCategoryStore.ts`
- Modify: `apps/web/stores/useTaskWorklogStore.ts`
- Modify: `apps/web/stores/useOvertimeStore.ts`
- Modify: `apps/web/stores/useWorkActivityStore.ts`
- Modify: `docs/architecture.md`
- Modify: `docs/decisions.md`
- Modify: `docs/roadmap.md`
- Modify: `docs/workflow.md`
**Interfaces:**
- Produces: domain APIs for members, task categories, task worklogs, overtime records, and activity records.
- Consumes: existing AppData keys only for compatibility import/fallback during the transition.
- [x] Add failing backend tests for member CRUD, protected built-in admin behavior, and role/department fields used by the UI.
- [x] Add failing backend tests for task category CRUD and uniqueness by `(group, name)`.
- [x] Add failing backend tests for append-style TaskWorklog, OvertimeRecord, and WorkActivity writes.
- [x] Add failing frontend tests proving dictionary/member/evidence stores no longer save AppData as the main write path.
- [x] Implement the remaining domain modules.
- [x] Switch stores to domain writes, preserving fallback reads and current UI data shapes.
- [x] Update architecture, decisions, workflow, and roadmap to mark V2.4.0-V2.4.5 complete and clarify AppData is now compatibility/migration fallback.
- [x] Run full gates: `pnpm type-check`, `pnpm test`, `pnpm build`, `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm pnpm --filter server exec prisma validate --schema prisma/schema.prisma`, `pnpm deploy:verify`.
- [x] Commit: `feat(v2.4): 完成领域主写迁移`.

View File

@@ -130,8 +130,9 @@
## 测试 / 验证流程
- 改动后必须 `npx tsc --noEmit` 通过
- 涉及服务端数据持久化:`pnpm --filter server exec prisma validate --schema prisma/schema.prisma`
- 改动后必须 `pnpm type-check` 通过
- 涉及服务端数据持久化:`DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm pnpm --filter server exec prisma validate --schema prisma/schema.prisma`
- 涉及 V2.5 后端权限/审计/AppData/一致性:至少运行 `pnpm --filter server test`
- 涉及 UI 改动:`curl http://localhost:3000/<path>` 检查 200
- 不会自动跑 dev server假定它已经运行
@@ -142,6 +143,62 @@
- 后端只在 `key + updatedAt(version)` 匹配时更新;如果其他用户已经先保存,返回 `409 APP_DATA_CONFLICT`,响应包含当前服务端 `currentVersion``currentValue`
- 收到 `ServerDataConflictError` 时,不要自动重试覆盖。当前处理策略是阻止静默覆盖,后续 UI 冲突合并能力再单独补。
## V2.4 领域写入流程
已迁移领域的 store 默认写入顺序:
1. 本地状态先做乐观更新,保持 UI 响应速度。
2. 优先调用 `apps/web/lib/domain-api.ts` 中的领域 API。
3. 领域 API 成功后,用服务端返回行替换本地临时行;若返回 `activities`,直接合并工作活动证据。
4. 领域 API 不可用或旧环境未部署时,才使用 `loadServerData` / `saveServerData` 做 AppData 兼容兜底。
5. 不新增长期双写逻辑AppData fallback 只用于兼容、迁移和回滚,不作为已迁移领域的事实源。
当前领域主写范围:
- Product / Project / Version根数据主写`products-overview` 仅兼容。
- Requirement`productId` 写入,需求池列表走服务端分页、搜索、筛选、排序。
- VersionPlan / DevTask / TestCase / Bug`versionId` 写入,并维护工作活动和小宝 dirty 标记。
- Member / TaskCategory成员身份字段和任务类型字典主写关系表。
- TaskWorklog / OvertimeRecord / WorkActivity证据型数据主写关系表保持追加语义。
仍在 AppData 兼容配置中的内容:
- 部门、角色、密码规则。
- 加班原因。
新增领域 store 时,先写 source contract 测试证明主写不是 `saveServerData('<key>')`,再实现领域 API 和 fallback。
## V2.5 权限、审计与 AppData 退场流程
新增或修改领域 mutation endpoint 时,必须使用统一合同:
1. Controller mutation 使用 `@ProtectedMutation(permission, scope, audit)`,不要只在前端做权限判断。
2. `scope` 必须能从 param/body 中解析 `productId``projectId``versionId`,版本资源优先传 `versionId`
3. Service 写入需要保留 `actorId``resourceScope` 或可推导的产品/项目/版本上下文,便于审计与一致性校验。
4. 成功 mutation 必须写 `audit_events`审计详情中不得暴露密码、token、secret、API key 等敏感字段。
5. 查询审计走 `/admin/audit``GET /api/v1/audit`,需要 `audit:view`
AppData key 退场遵循:
1. 所有业务 key 先在 `AppDataRetirementService` 标注状态和替代路径。
2. `write_frozen` / `read_only_archive` key 的写入返回 `409 APP_DATA_WRITE_FROZEN`;前端捕获 `ServerDataWriteFrozenError` 后提示改用领域 API。
3. 读取仍可用,只用于历史数据核对、兼容导入、归档导出和故障排查。
4. 导出归档使用 `pnpm appdata:archive:export`,归档校验使用 `pnpm appdata:archive:verify -- --archive <file>`
5. 不新增 AppData key 作为主写新业务先设计关系表、Prisma model、领域 API、权限和审计。
一致性检查流程:
1. 本地或部署环境先确保 server 可访问并完成 migration。
2. 运行 `pnpm consistency:v25`,默认检查 `http://localhost:3001/api/v1/consistency`
3. `error` 必须修复后才能继续发布;`warn` 需要记录原因。历史数据缺少审计事件属于 warning不阻断 V2.5。
4. 后台页面 `/admin/consistency``consistency:view` 控制,展示 counts、分区键、孤儿引用和审计覆盖。
跨阶段协调点:
- `xiaobao-risk-snapshots` / `xiaobao-risk-insights` 已进入只读归档V2.6 负责关系表写入、后台任务和重试。
- `xiaobao-warning-views` 已进入只读归档V2.7 负责 per-user read-state API。
- 成员身份写 `users`,但部门、角色、密码规则和加班原因的正式配置 schema 仍属 V2.7 管理治理。
## 与我相关Workspace数据流
```