# robot-manager 模块开发记录

> **module**: robot-manager
> **doc_type**: Changelog
> **status**: Active
> **last_verified**: 2026-04-18

---

## v6：角色重命名 + 权限拆分 + 测试覆盖 100%（2026-04-18）

### 权限体系
- `admin` 整体权限拆分为 5 个 `manage:*`，按角色分配：
  - `manage:fields` / `manage:models` → 仅 RLE + Administrator
  - `manage:suppliers` → RLE + SupplyChain
  - `manage:customers` → RLE + Sales
  - `manage:locations` → RLE + SupplyChain + Sales
- 角色 code 规范化为 `RobotManager{Role}`：
  - `RobotManagerRLE` / `RobotManagerSupplyChain` / `RobotManagerSales` / `RobotManagerFinance`
  - Administrator 保持不变
- Seed 层 legacy cleanup：先 deleteMany 旧角色权限再 create，防盲区 #6 drift

### 错误码规整
- 引入 `RobotError` enum（单一事实源）
- 新增 `ATTACHMENT_NO_FILE` / `ATTACHMENT_TOO_LARGE` 归一
- zh/en i18n 字典同步，共 19 条

### 文档
- 新建 05-ui-interaction-spec.md / 08-error-codes.md / 09-test-scenarios.md / 11-user-guide.md / 12-roadmap.md
- 10-e2e-test-spec.md 扩 8 → 19 场景（多角色 / 组织隔离 / Dashboard / Compare / Help / Settings / 模板下载）
- 07-api.md 补 RobotFieldDef (§6.1 替换旧 RobotOption) / Attachment (§7) / Search (§8) 章节

### 测试覆盖
- L1 从 62 扩到 109 用例，19 个 describe
- 新增 module-config 三件套（contract / snapshot / quality）供 testing 脚本按 `--module robot-manager` 运行
- 58 个端点（+ `/excel/template`）全部有对应 L1 用例
- 18/19 错误码精确断言

---

## v5：FieldDef 统一字典（2026-04-17）

- RobotOption 表删除，字典选项内联到 RobotFieldDef.options JSONB
- 引入 RobotFieldDef.scope（unit / service_record / location）+ 复合唯一 (scope, key)
- Admin 字段页 2 Tab（Custom / System）

---

## v4：内联字典 + 货币（2026-04-17）

- FieldDef.options 首次以 JSONB 内联
- 新增 currency 字段 + 7 币种 + Intl.NumberFormat 格式化

---

## v2 Phase 3：字段级权限 + 多角色 Tab 视图（2026-04-14）

### 权限体系
- 新增 5 条 section 级写权限：`robot-manager:write:identity` / `write:supply-chain` / `write:sales` / `write:finance` / `write:after-sales`
- 重新分配角色：
  - **Administrator**: 所有权限（由 PermissionsGuard 绕过）
  - **RLE**: 所有 section 写权限 + admin + delete
  - **SupplyChain**: write:identity + write:supply-chain + create + import + change-status
  - **Sales**: write:sales + change-status + export
  - **Finance**: write:finance + export
- 修复了 `status-change` vs `change-status` 权限码不一致的历史遗留 bug

### 后端 Section 级端点
新增 5 个 PUT 端点，每个只允许写入对应 section 的字段：
- `PUT /robot-manager/:id/identity`（modelId / skuId / supplierSn / usageTypeCode / importTypeCode）
- `PUT /robot-manager/:id/supply-chain`（supplierId / poNumber / purchaseDate / purchasePrice / eta / arrivalDate / deliveryStatusCode）
- `PUT /robot-manager/:id/sales`（customerId / salesOrderId / salesPrice / contractStatusCode / contractLink）
- `PUT /robot-manager/:id/finance`（cost / paymentMethodCode / paymentStatusCode）
- `PUT /robot-manager/:id/after-sales`（warrantyStatusCode / issueTagCode）

特性：
- `version` 乐观锁
- `poNumber` / `salesOrderId` 不可变校验
- FK + 字典 code 合法性校验
- 白名单字段过滤（传入多余字段会被忽略）
- `robot-unit.service.ts` 新增 `updateSection()` 方法；legacy `update()` 仍保留供 RLE/Administrator 使用

### 前端多角色 Tab 视图
- 详情页顶部 Tab 切换：全部 / 设备身份 / 供应链 / 销售 / 财务 / 售后
- 按用户权限过滤可见 Tab（Administrator/RLE 看全部，其他只看自己 section）
- 默认选中第一个可见 Tab
- 每个 Tab 只渲染对应 section，其他 section 不显示
- 无权限字段自动 `disabled` + "(只读)" 标注
- "保存"按钮按当前 Tab 调用对应 section 端点（只传送该 section 字段，减少带宽和冲突）
- "状态变更" 按钮按 `change-status` 权限显示

### 破坏性变更
无 —— legacy `PUT /:id` 仍然工作（仅 RLE/Administrator）

---

## v2 Phase 2：前端重写 + 7 个 admin 页（2026-04-14）

### 前端 API client 重写
- `_lib/api/index.ts` 全量重写：所有类型按 v2 schema 重定义
- 新增 5 个业务实体 API 客户端（`modelApi` / `skuApi` / `supplierApi` / `customerApi` / `locationApi`）
- 新增 `optionApi` / `configApi` 管理客户端
- 新增 `robotApi.updateSection()`（Phase 3 时使用）

### 业务页面重写（5）
- `/robot-manager` 列表：FK join 展示、状态多选筛选、model/supplier 下拉筛选、**批量状态变更前端真正接上**（v1 是假按钮）
- `/robot-manager/create` 创建：所有业务实体改下拉源 + model→sku 联动 + 字典字段下拉
- `/robot-manager/[id]` 详情：FK 实体下拉 + 字典下拉 + 状态变更菜单 click 控制（修复 v1 hover bug）+ 删除按钮 + statusChangeLog 富化 changedByUser
- `/robot-manager/reports` 报表：字段名对齐 v2 API（total/physical/inTransit/totalDelivered/customerBreakdown/revenue/margin）
- `/robot-manager/import-export` 导入导出：Excel 列说明换为 *Code 形式

### 管理页面新增（7）
- `/robot-manager/admin/models` 型号档案
- `/robot-manager/admin/skus` SKU 档案（FK Model）
- `/robot-manager/admin/suppliers` 供应商档案
- `/robot-manager/admin/customers` 客户档案
- `/robot-manager/admin/locations` 位置档案（FK Customer 可选）
- `/robot-manager/admin/dictionary` 统一字典管理（10 category tab）
- `/robot-manager/admin/settings` 系统配置（FFSN 规则 + 状态默认 location 映射 + 维修 ServiceType）

### 共享组件
- `admin/_lib/EntityAdminPage.tsx` 通用 CRUD 组件（5 个实体页共用）
- `EnabledBadge` 启用/禁用标签

### Layout 扩展
- 左侧导航新增 7 个 admin 入口（按 `robot-manager:admin` 权限显示）

---

## v2 Phase 1：后端重构（2026-04-14）

**主题**：从 wide-table + Prisma enum 演进到 FK-driven + 统一字典 + 配置化

### 数据模型变更
- 新增 5 张业务实体表：`RobotModel`, `RobotSku`(FK Model), `RobotSupplier`, `RobotCustomer`, `RobotLocation`
- 新增统一字典表 `RobotOption`（10 category）
- 新增系统配置表 `RobotSystemConfig`（FFSN 规则 + 状态→默认 location 映射 + REPAIR 自动 ServiceType）
- 删除 7 个 Prisma enum（UsageType/ImportType/DeliveryStatus/ContractStatus/PaymentMethod/PaymentStatus/WarrantyStatus），统一进 `RobotOption`
- 删除 `RobotLocation` enum（升级为业务实体表），`RobotServiceType` enum 也进 `RobotOption`
- 保留 `RobotStatus` 唯一 Prisma enum（核心状态机）
- `robot_units`：`model/sku/supplier/customerName` 改为 FK；`location` 改为 `locationId` FK；7 个 enum 字段改为 `*Code` 字符串（引用 RobotOption.code）

### 业务逻辑变更
- **财务公式简化**：`margin = salesPrice - cost`，任何状态都计入（非 null 过滤）
- **FFSN 配置化**：前缀/日期格式/位数/重置周期从 `RobotSystemConfig.ffsn_rule` 读
- **状态→Location 映射配置化**：从 `status_default_location` 读
- **REPAIR 自动 ServiceType 配置化**：从 `repair_auto_service_type` 读

### 角色与权限
- 新增 4 个角色：RLE / SupplyChain / Sales / Finance（+ 原有 Administrator）
- 新增 8 条 robot-manager 权限：`read/create/update/delete/change-status/import/export/admin`
- Phase 3 在此基础上做字段级权限 + 详情页 Tab 切换视图

### 新增后端代码
- 7 个新 service：`RobotOptionService`, `RobotSystemConfigService`, `RobotModelService`, `RobotSkuService`, `RobotSupplierService`, `RobotCustomerService`, `RobotLocationService`
- 1 个新 controller：`RobotAdminController`（`/robot-manager/admin/*` 统一管理）

### 种子脚本
- `backend/prisma/seeds/robot-manager-e2e-seed.ts` 重写为 v2：46 条字典（10 类）+ 3 Model + 5 SKU + 2 Supplier + 3 Customer + 2 Location + 6 机器人 + 5 角色 + 5 用户

### 破坏性变更
- 前端 API 字段完全变化（所有 enum 字段 → *Code；model/sku/supplier/customerName → FK id）
- 前端在 Phase 2 同步重构

---

## 概要（v1 历史）

> 以下为 v1 阶段（2026-04-12 ~ 2026-04-13）的产出清单。schema 数字、表数等已被 v2 重构覆盖，仅作历史参考。

**模块名称**：机器人全生命周期管理（Robot Lifecycle Management, RLE）
**技术名**：robot-manager
**分支**：feature/robot-manager
**PR**：#72
**开发周期**：2026-04-12 ~ 2026-04-14
**总产出**：19 次提交，43 个文件，7,307 行代码

---

## 产出清单

### 1. 需求文档（docs/modules/robot-manager/）

| 文件 | 说明 |
|------|------|
| README.md | 模块总览、文档索引、核心概念、代码位置 |
| 01-prd.md | PRD：功能清单（F1-F8）、业务约束、权限矩阵（5 角色 × 14 操作）、边界规则 |
| 04-state-machine.md | 8 状态生命周期状态机：15 条合法转换、Guard Conditions、副作用、Location 联动、初始状态、Excel 导入规则 |
| 06-data-model.md | Prisma schema 设计：3 表 35 列、10 个 Enum、partial unique index、索引策略、约束规则 |
| 10-e2e-test-spec.md | E2E 测试规格：8 个流程（P0:3 + P1:3 + P2:2） |
| database-schema.md | 历史参考：早期订单维度数据模型 |
| implementation-guide.md | 历史参考：Power Apps 实施方案 |
| us-compliance.md | 历史参考：美国合规要求（Phase 2） |

**文档经过 13 轮交叉审查，修复 56 个问题**，覆盖维度：
1. 文档结构与完整性（9）
2. Schema 七维审查（12）
3. 跨文档一致性（3）
4. 实现者视角（6）
5. 端到端场景走查（5）
6. 数据完整性与并发（5）
7. Guard 一致性与取消路径（3）
8. Excel 导入与字段联动（3）
9. 数据生命周期完整性（5）
10. 清理与遗漏检查（3）
11. 批量操作与通知（2）
12. 精确计数验证（2）
13. 实现模拟验证（2）

### 2. Prisma Schema（backend/prisma/schema/robot_manager.prisma）

- **RobotUnit**：主表，26 个业务字段 + 9 个通用字段 = 35 列
- **RobotServiceRecord**：售后记录，1:N
- **RobotStatusChangeLog**：状态变更日志，1:N
- **10 个 Enum**：RobotStatus、RobotLocation、RobotUsageType、RobotImportType、RobotDeliveryStatus、RobotContractStatus、RobotPaymentMethod、RobotPaymentStatus、RobotWarrantyStatus、RobotServiceType
- **Partial unique index**：FFSN 组织内唯一 + 软删除兼容
- **4 个查询索引**：按状态/型号/客户/软删除

### 3. 后端代码（backend/src/modules/robot-manager/）

| 文件 | 说明 |
|------|------|
| robot-manager.module.ts | NestJS 模块注册 |
| robot-unit.controller.ts | CRUD + 批量状态变更（6 端点） |
| robot-status.controller.ts | 状态机变更（1 端点，@HttpCode 200） |
| robot-report.controller.ts | 库存/销售/财务报表（3 端点） |
| robot-excel.controller.ts | Excel 导入导出（2 端点） |
| dto/robot-unit.dto.ts | CreateRobotUnitDto、UpdateRobotUnitDto（含 version 乐观锁）、QueryRobotUnitDto、BulkStatusChangeDto |
| dto/status-change.dto.ts | StatusChangeDto（targetStatus + remark + location） |
| dto/service-record.dto.ts | CreateServiceRecordDto、QueryServiceRecordDto |
| services/robot-unit.service.ts | CRUD + FFSN 自动生成（FF-YYYYMM-NNNNN）+ 乐观锁 |
| services/robot-status.service.ts | 状态机核心：15 条转换 + Guard + 副作用 + 事务 |
| services/robot-report.service.ts | 聚合查询（groupBy + raw SQL） |
| services/robot-excel.service.ts | Excel 导出全字段 + 导入含按状态校验 |

### 4. 前端代码（frontend/src/app/(modules)/robot-manager/）

| 文件 | 说明 |
|------|------|
| layout.tsx | 模块布局：左侧导航（设备管理/报表/导入导出） |
| page.tsx | 列表页：搜索、状态筛选、表格（含 grossMargin 计算）、批量操作、分页 |
| [id]/page.tsx | 详情/编辑页：6 模块卡片、状态变更下拉、确认弹窗、StatusChangeLog 时间线 |
| create/page.tsx | 创建页：必填 model/sku + 可选字段 |
| reports/page.tsx | 报表页：库存/销售/财务三卡片 |
| import-export/page.tsx | 导入导出页：文件上传 + 校验规则 + 结果汇总 |
| _lib/api/index.ts | API service：robotApi + reportApi + excelApi + 完整 TypeScript 类型 |

### 5. 前端 i18n（frontend/src/locales/robot-manager/）

- zh.ts：中文翻译（状态/字段/操作/报表/消息/表单）
- en.ts：英文翻译

### 6. 集成测试（testing/backend/integration/robot-manager/）

- robot-manager.integration.test.ts：**22 个用例全部通过**
  - CRUD（6）：创建/列表/详情/更新/不可变字段
  - 状态机（10）：Happy path/取消/维修/归还/Guard 拦截/非法跳跃/乐观锁
  - 报表（3）：库存/销售/财务
  - 批量（2）：全部成功/部分失败
  - 软删除（1）

### 7. 测试报告（testing/reports/）

- robot-manager-2026-04-13-full-test-report.md：后端七层测试 v1
- robot-manager-2026-04-13-full-test-report-v2.md：含前端七层测试 v2

### 8. 修改的共享文件

| 文件 | 变更 |
|------|------|
| backend/prisma/schema/base.prisma | 注册 `robot_manager` schema |
| backend/src/app.module.ts | 注册 RobotManagerModule |
| frontend/src/config/navigation.ts | 注册导航项（robot-manager:read 权限） |
| frontend/src/locales/index.ts | 注册 robotManager i18n |
| frontend/src/locales/nav/zh.ts | 添加"机器人管理"导航文案 |
| frontend/src/locales/nav/en.ts | 添加"Robot Manager"导航文案 |
| frontend/src/components/layout/Sidebar.tsx | 添加机器人图标 |
| testing/tsconfig.json | 添加 ignoreDeprecations: "6.0" |
| .githooks/pre-push | 移除 --transpile-only |

---

## 测试验证结果

| 测试层 | 结果 | 详情 |
|--------|------|------|
| L0a/L0b 前后端契约 | ✅ | 12 端点对齐（修复 5 个阻断级命名不匹配） |
| L0c 响应快照 | ✅ | 分页壳层/详情/报表字段一致 |
| L1 Jest 集成测试 | ✅ 22/22 | CRUD + 状态机 + Guard + 报表 + 批量 + 软删除 |
| L1 curl 全流程 | ✅ 14/14 | 创建 → 5 步状态变更 → 维修归还 → Guard 拦截 → 报表 |
| L1.5 数据质量 | ✅ 5/5 | 权限/FK/枚举/索引/孤儿 |
| L2 E2E（后端 API） | ✅ 10/10 | API 链路全通 |
| L2 E2E（前端 UI） | ⚠️ | Turbopack 不支持 git worktree，待合并后测试 |

---

## 开发过程中发现并修复的 Bug

| # | Bug | 发现方式 | 修复 |
|---|-----|---------|------|
| 1 | UpdateRobotUnitDto 缺 version 字段，乐观锁被 whitelist 静默丢弃 | Jest 测试 | 添加 version 到 DTO |
| 2 | POST /status 返回 201 而非 200 | Jest 测试 | 添加 @HttpCode(200) |
| 3 | FFSN 并发生成序号冲突 | Jest 测试 | 测试改为串行创建 |
| 4 | organizationId 硬编码 'default' 不是合法 UUID | curl 测试 | 改为 '00000000-...' |
| 5 | Express.Multer.File 类型不存在 | tsc 编译 | 改为内联类型 |
| 6 | 前端 StatusChangeDto.toStatus 与后端 targetStatus 不匹配 | L0a/L0b 契约校验 | 统一字段名 |
| 7 | 前端 BulkStatusChangeDto.ids 与后端 robotUnitIds 不匹配 | L0a/L0b 契约校验 | 统一字段名 |
| 8 | pre-push 契约校验在 TS 6.x 下编译失败 | git push | ignoreDeprecations + 移除 --transpile-only |

---

## 经验沉淀

存储在主仓库 `.learnings/` 目录：

1. **2026-04-12-data-model-review-patterns.md**：数据模型文档审查的 6 大经验（软删除+唯一约束、动态数据不用 Enum、计算字段不存表、Guard vs 副作用、PDF 提取工具链、多轮审查维度清单）

2. **2026-04-13-ts-node-transpile-only-deprecation.md**：ts-node --transpile-only 模式不尊重 ignoreDeprecations 的绕行方案

3. **2026-04-13-nextjs16-worktree-startup.md**：Next.js 16 Turbopack 不支持 git worktree 的根因分析

---

## 待办事项

- [ ] 业务方确认 7 个 AI 补充的 Enum 取值（标记 ⚠️）
- [ ] 确认 FFSN 生成规则（当前格式 FF-YYYYMM-NNNNN）
- [ ] 确认 cost 与 purchasePrice 是否需要区分
- [ ] 合并到 develop 后在主仓库执行前端 E2E 测试
- [ ] 补充 07-api.md API 文档
- [ ] 补充多角色权限隔离测试（SC/Sales/Finance 角色）
