Files
lingxi/docs/开发计划/灵犀_A4数据字典与系统配置_实施报告_V0.1.md
T
Stev_Wang 02c716d6f2 docs(plan): A4 实施报告与计划回写
背景:A4 开发完成,需要回写实施报告、技术架构与开发计划状态。\n改动:新增 A4 实施报告;技术架构补 system_config_versions 与 dict:manage 口径;开发计划 A4 标记完成并回写门禁/遗留;README 索引补 A4 报告。\n影响面:仅文档;不改变需求与技术边界。\n回滚:回滚本提交即可。\n验证:prettier 通过;文档链接已检查。
2026-11-04 11:50:30 +08:00

166 lines
12 KiB
Markdown
Raw 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.
# 灵犀 A4 数据字典与系统配置 · 实施报告 V0.1
| 项 | 内容 |
| --- | --- |
| 实施日期 | 2026-11-04 |
| 批次 | A4(数据字典与系统配置) |
| 状态 | **已完成**(开发 + 全部门禁 + 浏览器 e2e 通过;未推送) |
| 依据 | 开发计划 V0.1 §6.5 / §7.3 / §12.1;PRD V1.6 §5.4.5 / R-01 / R-10 / R-26;技术架构 V0.4 §5.3 / §5.7 / §6.3.7;ADR-001 |
| 视觉基线 | A0「方向 A · 云白蓝」;用户选定 **方案 A · 主从分栏** |
| 迁移 | `prisma/migrations/20261104024511_a4_dict_system_configs/` |
| 前端路由 | `/system/dicts`、`/system/dicts/:type`、`/system/settings` |
---
## 1 范围与完成度
| 任务 | 内容 | 状态 |
| --- | --- | --- |
| A4-BE-01 | 字典模型与三层合并(`dict_types` / `dict_items`,树 / 词表一张表) | ✅ |
| A4-BE-02 | 系统配置与版本(`system_configs` + `system_config_versions`,阈值同源) | ✅ |
| A4-BE-03 | 命名规则服务(R-01 占位符 / 白名单 / 同名序号 / ≤100) | ✅ |
| A4-BE-04 | 字典快照(R-10,共享契约 + `toDictItemSnapshot`) | ✅ |
| A4-FE-01 | 字典管理(方案 A 主从分栏,树 / 词表双视图) | ✅ |
| A4-FE-02 | 系统配置页(6 组 / 命名预览 / 阈值二次确认 / 变更记录) | ✅ |
| A4-QA-01 | 合并 / 快照 / 同源用例 + 浏览器 e2e | ✅ |
> 权限口径:A2 定稿的 30 个权限点中字典为单个 `dict:manage`;系统配置为 `system:configure`。本轮未新增权限点,已同步技术架构 §6.3.7 与开发计划附录 B / C。
---
## 2 交付物
### 2.1 文档与决策
- 技术架构 §5.3 / §5.7 / §6.3.7 回写:新增 `system_config_versions`,字典权限统一 `dict:manage`。
- 开发计划 §7.3 / 附录 B / 附录 C 权限口径回写。
- `prisma/SEED.md` 更新:`system_configs` 26 项、A4 字典 13 类 / 96 条。
- 前端原型:`design/a4-ui-v1/`(三套候选 + 两轮独立评审 + 用户选定 A);实现截图:`design/a4-ui-v1/impl/`。
### 2.2 共享契约(`packages/shared`)
- `schemas/dict.ts`:字典类型 / 条目 / 三层来源 / 类型与条目编码不可改 / 查询与写接口 / `toDictItemSnapshot`。
- `schemas/config.ts`:系统配置响应、批量保存(`expectedVersion`)、变更记录、`effective` 读取。
- `config/system-configs.ts`:26 项配置定义(key / group / label / description / impact / type / default / 约束 / public)与 `validateSystemConfigValue`;前后端共用,R-26 唯一事实源。
- `naming.ts`:`NAMING_TOKEN_DEFINITIONS`、`validateNamingTemplate`、`resolveNamingTemplate`、`formatNamingDate`、`formatNamingSequence`;保留既有 `dedupeName` / `sanitizeFilename`。
- `schemas/client.ts`:`CUSTOMER_BASE_FIELD_HARD_LIMIT = 50` 作为 DTO 防御性硬上界;实际生效上限由服务端动态读取。
- 单测:`dict.spec.ts` / `config.spec.ts` / `naming.spec.ts` 覆盖合并口径、快照、配置校验、模板解析、同名序号。
### 2.3 数据库与种子
- 迁移 `20261104024511_a4_dict_system_configs`:
- `dict_types`(code unique;group / kind / industry_scoped / builtin / status / sort);
- `dict_items`(type_id + code + industry_id;parent_code;`dict_items_no_self_parent_check`);
- 部分唯一索引:通用层 `(type_id, code) WHERE industry_id IS NULL`、行业层 `(type_id, code, industry_id) WHERE industry_id IS NOT NULL`;
- `system_config_versions`(append-only:config_key / version / old_value / new_value / reason / changed_by / changed_at;`(config_key, version)` 唯一)。
- 种子:
- `system_configs` 26 项,元数据来自 `SYSTEM_CONFIG_DEFINITIONS`;重复执行不覆盖人工调整值 / 版本;
- 字典 13 类 / 96 条,行业作用域映射 A3 行业(电商 / 服饰鞋包 / 美妆个护 / 金融 / 信贷 等);内置类型不可删除、条目编码不可改。
### 2.4 后端(`apps/api`)
| 模块 | 接口 |
| --- | --- |
| `catalog` | `GET /dicts`、`GET /dicts/{code}`、`POST /dicts`、`PATCH /dicts/{code}`、`PATCH /dicts/{code}/status`、`DELETE /dicts/{code}`、`GET /dicts/{code}/items`、`POST /dicts/{code}/items`、`PATCH /dicts/{code}/items/{itemId}` |
| `platform` | `GET /system/configs`、`GET /system/configs/effective`、`PUT /system/configs`、`GET /system/configs/history` |
- 三层合并为纯函数 `dict-merge.ts`:通用 0 / 父行业 1 / 本行业 2,同 code 覆盖;返回 `source` / `overridden` / `layers` / `effectiveCount` / `disabledCount`。
- 编码不可改:schema `.strict()` 不接收 code / kind / industryScoped / parentCode / industryId 更新;冲突 40902;内置类型 / 有子条目删除 40001。
- 配置保存:事务 + `expectedVersion` 乐观锁(40901)+ 条件 `version+1` + `system_config_versions` + `@Audit('platform.system_config.update')` 前后值。
- 阈值同源:`roles` / `users` / `customers` / `customer-fields` 已改为 `SystemConfigService.getNumber('limit.*')`;shared 常量只作 fallback。
- 命名服务:`resolveScriptName` / `resolveImageName` / `resolveVideoName`,读 `naming.*` + `max_length` + `duplicate_start`;缺占位符 40001,非法 / 超长 / 同名过多 42201。
- 快照:`dict.mapper#toDictSnapshot` 委托 shared;单测证明改名后历史快照不变(R-10)。
- 审计:字典类型 / 条目写操作、系统配置保存均 @Audit + 结构化日志前后值(A5 落审计表)。
### 2.5 前端(`apps/web`,方案 A)
| 页面 | 路由 | 实现 |
| --- | --- | --- |
| 数据字典 | `/system/dicts` | 左 320 类型列表(4 分组折叠、搜索、状态筛选、统计)+ 右类型头 / 行业三层 chips / 树表切换 / 条目表 |
| 字典详情 | `/system/dicts/:type` | 同一主从骨架深链;默认 `script_direction` + 电商/服饰鞋包,7 项三层合并 |
| 系统配置 | `/system/settings` | 左 200 分组导航 + 6 组表单 + 命名占位符 / 实时预览 + 阈值二次确认 + 保存条 + 变更记录抽屉 |
- 组件:`DictTypeListPanel` / `DictDetailPanel` / `DictItemsView` / `DictItemSheet` / `DictTypeModal`;`SettingsPage` / `SettingsNav` / `SettingsGroupForm` / `ConfigRow` / `NamingAside` / `ConfigHistorySheet`。
- API / 状态:`api/dicts.ts` / `api/configs.ts`,shared Zod parse;`use-dicts` / `use-configs`,含 `useEffectiveSystemConfigsQuery` / `useCustomerFieldLimits`。
- 阈值同源:客户列表 / 详情 / 字段审批的 10 / 5 显示与禁用判断改为 effective config;后端最终校验不变。
- 路由 / 壳层:`/system/dicts`、`/system/dicts/:type`、`/system/settings` 已注册并按 `dict:manage` / `system:configure` 守卫;`AppLayout` 满高 flush;`main.tsx` 引入 `dicts.css` / `settings.css`。
- 侧边栏已更名「数据字典」(commit `32b44bd`)。
---
## 3 验证结果
| 门禁 | 命令 | 结果 |
| --- | --- | --- |
| 格式 | `pnpm format:check` | ✅ |
| Lint | `pnpm lint` | ✅ 0 warning |
| 类型 | `pnpm typecheck` | ✅ 10/10 tasks |
| 单测(shared) | `pnpm --filter @lingxi/shared test` | ✅ 13 files / 147 tests |
| 单测(api) | `pnpm --filter @lingxi/api test` | ✅ 18 files / 137 tests |
| 单测(web) | `pnpm --filter @lingxi/web test` | ✅ 29 files / 154 tests |
| 集成 | `pnpm --filter @lingxi/api test:int` | ✅ 7 files / 58 tests(新增 catalog 10 + config 9) |
| 构建 | `pnpm build` | ✅ 8/8 tasks |
| OpenAPI | `pnpm openapi:export` + `pnpm openapi:diff` | ✅ 无破坏性变更 |
| 浏览器 e2e | `A4_E2E=1 pnpm exec playwright test e2e/a4-dicts-settings.spec.ts` | ✅ 7 passed(约 1.1m) |
| 本地 CI | `pnpm ci:local` | ✅ 262.3s,全部门禁通过(build + test:int + openapi + smoke e2e) |
浏览器人工验收(真实 API + PG + seed):
- `/system/dicts` 默认脚本方向 / 电商·服饰鞋包,显示三层 chips(通用 5 + 父行业 2 + 本行业 1 = 生效 7),种草短视频「父行业 / 已覆盖」、直播切片「父行业」、穿搭教程「本行业」;
- 树 / 词表切换、非行业类型「全平台通用」、条目新增 / 编辑(编码只读)/ 停用 / 启用、类型新建 / 编辑(编码只读);
- `/system/settings` 6 组 / 26 项、命名占位符与实时预览、阈值旧→新二次确认、保存后版本 +1、变更记录(版本 / 前后值 / 操作人 / 时间 / 原因);
- 1440×900 与 1024×900 无横向溢出;截图:[impl](../../design/a4-ui-v1/impl/)。
---
## 4 关键口径与实现说明
1. **一张表同时表达树与词表**:`dict_items.parent_code` 表达二级树;不另建行业二级表(ADR-002 后行业树由 `industries` 承载)。
2. **三层合并**:查询取通用 + 父行业 + 本行业;同 code 以更具体层覆盖,返回 source / overridden;非行业作用域类型强制只读通用层。
3. **编码不可改**:类型 `code` 与条目 `code` 创建后不可改;更新 DTO `.strict()` 不接收;前端编辑态只读。
4. **配置唯一来源**:`SYSTEM_CONFIG_DEFINITIONS` 为元数据 / 默认值 / 校验唯一事实源;`system_configs` 只存值 / 版本;`/system/configs/effective` 供前端读取 public 项(上限),前端不再硬编码 10 / 5。
5. **版本与变更**:保存走事务 + 乐观锁;每次变更写 `system_config_versions`;审计日志记录前后值,A5 落审计表。
6. **命名规则**:shared 纯函数被前端预览与后端 `NamingService` 共用;字符白名单、占位符、≤100、同名序号一致。
7. **快照**:`toDictItemSnapshot` 生成填写时 typeCode / code / name / parentCode / industryId / capturedAt;业务记录在 B0 / M1 引用时保存,A4 只提供契约与工具。
---
## 5 已知差异与遗留
| 编号 | 项 | 说明 / 建议 |
| --- | --- | --- |
| 1 | `refCount` 固定 0 | A4 尚无引用表;B0 / B1 资产与行业包落地后接入真实引用计数 |
| 2 | 配置项 26 项(原型 24 项) | 含 A0 已有 2 项 AI 成本比例配置;A7 会提供专门 AI 配置页,A4 暂列在「业务阈值」 |
| 3 | 审计落库 | A4 只写结构化 `@Audit` 日志;审计表 / 检索 / 导出按 A5 |
| 4 | 只读态不可达 | 路由守卫为 `dict:manage` / `system:configure`,无独立 view 权限;页面保留 canWrite=false 防御分支,后续如拆分 view/manage 权限可直接生效 |
| 5 | 详情面包屑 | `/system/dicts/:type` 面包屑仍为「管理中心 / 数据字典」,未展示类型名;`breadcrumbs.ts` 无类型参数,后续统一处理(与 A3 客户详情同源问题) |
| 6 | 字典类型分页 | 当前 13 类,前端一次拉 100 条后本地筛选;类型数 >100 时需补游标分页 UI |
| 7 | `updatedBy` 存储 | 字典表存操作人姓名;`system_configs.updated_by` 存 ULID,列表 / 历史批量 join 返回姓名 |
| 8 | DTO 硬上界 | 客户基础字段 schema 硬上界 50(防御性);若配置 >50 仍会被 Zod 拦截,需同步调整 shared 硬上界 |
| 9 | e2e | `A4_E2E=1` 用例已落地并 7/7 通过;默认 skip,不影响 smoke / CI;`e2e/README.md` 待补登记一行 |
---
## 6 回滚方式
1. 代码:回滚 A4 提交(catalog / platform 配置与命名 / 前端字典与配置页 / shared 契约 / 路由 / 样式 / 迁移 / seed / 文档)。
2. 数据库:A4 为新增表,回滚可保留表;彻底回滚删除顺序:`system_config_versions → dict_items → dict_types`;`system_configs` 为 A0 既有表,保留。
3. 配置:删除 A4 新增 `system_configs` 行或恢复默认值;`system_config_versions` 清空即可。
4. 前端:回滚路由 / 导航 / 页面 / 样式;`/system/dicts` / `/system/settings` 将回退到 Workspace 占位页(导航保留)。
---
## 7 本地运行
```bash
pnpm check:dev
pnpm db:init
pnpm dev
# 浏览器 http://127.0.0.1:5173 → 管理中心 / 数据字典、系统配置
```
A4 e2e(需先起 `pnpm dev`):
```bash
A4_E2E=1 pnpm exec playwright test e2e/a4-dicts-settings.spec.ts --reporter=list
```