touyun-elderly-care/docs/tech-debt.md
liuyun 3f0fff5129 docs: 标记 tenant_super_admin/孤儿清理/hint 已解决
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 15:00:49 +08:00

94 lines
8.9 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.

# 服务机构端 · 遗留项清单(Tech Debt)
> 记录 C0 基础骨架 / C1 待遇档案的遗留项,供后续 change 处理。来源:各 change 的 SDD ledger(deferred minor / parked / pre-existing)。按优先级分组。
## 安全 / 合规(优先处理)
- [x] ~~**id_card_no 存储层加密**~~ ✅ 已做(2026-10-21):AES-256-GCM 加密 + SHA-256 哈希唯一,掩码/查看留痕保留。密钥 `DATA_ENC_KEY`(缺省开发回退 key,生产必须配置)。
- [x] ~~**tenant_super_admin 未纳入身份证明文查看口径**~~ ✅ 已修(2026-10-21):canViewPlainIdCard 加入 tenant_super_admin。
- [ ] **身份核验 P-9**(扫脸/人证核验):依赖医保 APP 能力,后置;本期兜底=拍照留痕 + 实名账号 + 家属可选确认。
- [x] ~~**评估结论副本孤儿文件**~~ ✅ 已修(2026-10-21):建档失败 catch 清理 MinIO 对象(StorageService.delete)。
## 数据完整性
- [ ] **staff.entryDate/leaveDate 字符串直传 Prisma**:潜在 50000(C0 遗留,与 C1 elder 日期 bug 同类),需按 `toDateOnly` 方式统一修。
- [ ] **Agency.deletedAt 未纳入 SOFT_DELETE**:C0 无机构删除 flow,后续需要软删时补。
- [ ] **catalog 白名单对未声明字段覆盖不全**(parked Important):`data` pick 已兜底、无完整性风险;全站 `forbidNonWhitelisted` 后续再评估。
- [ ] **changeStatus 写 statusChangeDate 用 `new Date()` 未走 `toDateOnly`**:理论上 UTC 回退一天,当前无前端展示、零实际影响。
## 契约 / 文档
- [x] ~~**统一响应 `hint` 字段**~~ ✅ 已补(2026-10-21):TransformInterceptor + error filter 都加 `hint: null`。
- [ ] **api-contract 错误码列表(1001–4001)未实现**:实际用 5 位 `[域2][序3]`(如 40001),spec 内部不一致,需先收敛 spec 再对齐。
- [ ] **登录页属地提示**:frontend spec「属地提示」未实现(多租户登录前属地未知,需先厘清语义)。
- [ ] **前端等级筛选未暴露**:后端 `ListElderQuery.level` 已实现,前端搜索未用。
## seed / 数据
- [ ] **全量 L1 36 项 / 昆明 L2 45 项 / L3 映射未 seed**:C0 只落样例,全量数据延后到 C3/C4 或运营导入(异常分类/拍照分档字典已复用脚手架并 seed)。
## 测试 / 健壮性(次要)
- [ ] error-codes 头注释 legend 缺域 40–43(cosmetic)。
- [ ] StorageService 默认凭据回退、useSSL 硬编码、size 断言过松。
- [ ] 身份证格式错误用通用 400(无 `ELDER_ID_CARD_INVALID` 专用码)。
- [ ] staff `groupLeaderId` 未校验组长存在、listStaff 过滤字段自行推断、`UpdateStaffDto.userId` 不支持 null 解绑。
- [ ] catalog `loc_code` 缺失未校验、newNational 返全量、config 空更新。
- [ ] agency PATCH 空 body、NOT_FOUND 分支未测。
- [ ] 建档表单未收集 `insurYears`/`hospStart`/`hospEnd`/`guardian*`(spec 未要求)。
- [ ] 状态变更 `evidenceFile` 前端未提供上传(后端字段已留)。
## C2 派单工单
- [x] ~~**[高] 迁移链损坏**~~ ✅ 已 squash 到 `0_baseline`(2026-10-21),干净回放验证通过。
- [x] ~~**[高] 业务角色未授 elder/plan/order 权限**~~ ✅ 已于 C5 补全 `BUSINESS_ROLES` 五角色完整矩阵 + `sync:resources` 重同步。
- [ ] **生成工单 UI 入口缺失**:frontend spec 未要求,但端到端「计划→生成工单→派单」缺「生成工单」按钮(后端 `POST /order/generate` 已实现、已测)。C2.5/C3 补。
- [ ] **待派工单在排班日视图不可见**:日视图 `ordersOf` 只按 `assigneeId` 挂卡,`to_assign` 工单只出现在批量推荐下拉,网格无法一眼看出待派。
- [ ] **L4 机构项目库未 seed + 无创建端点**:`svc_org` 无 HTTP 创建端点、seed 未含 L4(冒烟用 Prisma 直插 18 行绕过)。补 seed + 端点(与 C0「全量 L1/L2/L3 未 seed」同批)。
- [ ] **属地项数 2002 前端未展示提示**:后端已改提示级(`item_count_rule` 记 `2002:…`),但 plan-form 未显示该警告。
- [ ] **当班无排班模型**:staff 无 shift/duty 字段,派单「当班」用 `employStatus` 代理(pass-through + TODO 指向未来排班模型)。
- [ ] **toDateOnly 跨域引用**:order.service 从 elder.service 引 `toDateOnly`,宜提公共 util。
- [ ] **billable 硬编码 + price_snapshot/settle_period 留 C3**(垫付/结转)。
- [ ] **batchRecommend 复用 order.assign 权限码**(无独立 `order.recommend`);C3 前在 shared/ 登记。
- [ ] **plan_status ended 无入口**(无结束计划端点);`plan.change` 不要求旧计划 active。
- [x] ~~**非事务多写**~~ ✅ 已包 `$transaction`(plan.create/change、elder-svc.put)。
- [ ] **toDateTime 硬编码 +08:00**(业务假设北京时区,已注释;如多时区属地需配置化)。
## C3 履约留痕
- [x] ~~**[高] 缺事务**~~ ✅ 已包 `$transaction`(扑空、itemSave、prepaidCarryover)。
- [ ] **扑空证据缺失用通用 40000**(无 `ABNORMAL_EVIDENCE_REQUIRED` 专用码,规则号 3003 写 message)。
- [ ] **照片/语音无 presign/下载端点**:前端只显示 file_path/key、有无,无法预览;APP 上线前补。
- [ ] **留痕/异常列表不分页**(`findMany` 全量);admin B3 规模可接受,APP 前补分页。
- [ ] **record.detail 嵌套 abnormals 的 visitLat/visitLng 仍带 Decimal**(顶层坐标已修,嵌套未序列化,minor 不一致)。
- [x] ~~**业务角色未授 record/abnormal 权限**~~ ✅ 已于 C5 补全 `BUSINESS_ROLES` 五角色完整矩阵 + `sync:resources` 重同步。
- [ ] **offlineSync 接受客户端 checkinTime/checkoutTime**(离线补传固有例外,仅 client_md5 去重兜底,防补录时间有缺口——可加 serviceDate 窗口约束)。
- [ ] **prepaidCarryover 不限制 record_status=submitted**(serving 垫付记录也能被结转);prepaidList 有 N+1 查询。
- [ ] 前端 pageSize 200 固定、serviceDate 文本输入、`loadPrepaid` 非 active 也请求(小浪费)。
## C4 质控闸门
- [x] ~~**[高] nurse 角色零 record.*/qc.correct 权限**~~ ✅ 已于 C5 补全 `BUSINESS_ROLES` 五角色完整矩阵(nurse 含 record.*/qc.correct/abnormal.report)+ `sync:resources` 重同步。
- [x] ~~**batchPass 两阶段预检但未包 `$transaction`**~~ ✅ 已包 `$transaction`(batchPass/markPassed)。其余(定时任务+五类聚合 N+1、prepaidList N+1)仍待。
- [ ] **QC_NOTE_REQUIRED(46005) 死代码**(DTO @IsNotEmpty 先拦,实际返回 40000);qc_note 纯空白串会漏过 DTO。
- [ ] **5 工作日不含节假日**(只跳周末);cron raw 扫描未过滤 `deletedAt`(软删留痕也可能生成 qc);qc 表 `record_id` 无唯一约束(并发重入可能重复生成)。
- [ ] **handleAbnormal 无状态机**(closed→handling 可重开,仅枚举限制);前端批量放行只挡 correctionCount>0(其余靠后端 QC_BATCH_UNSAFE 兜底);goAbnormal 不清其他筛选(UX)。
## C5 后台配置与文书补齐
- [ ] **文书导出审计丢目标老人**:`@AuditLog` 只序列化 body,`elderId` 在 query,`sys_audit_log.params=null`——无法追溯导出了哪位老人(需拦截器兼容 query 或 service 显式写)。
- [ ] **document「查看」复用导出接口**:查看等价一次导出+写 export 审计,再点导出又记一次(语义漂移);宜拆 detail/export 两端点。
- [ ] **文书导出 phone 未掩码**(仅 idCardNo 掩码);「一人一档」对外文书 PII 一致性待定。
- [ ] **info 页允许选 C 档 vs docking 页禁 C**(不一致,spec 只约束 docking);catalog 开关变量名 `before` 误导;loc 页 notify 开关失败不回滚。
- [ ] **listNewNational 返全量**(C1 L3 映射遗留,C5 用作名称解析 map 反而正确,正式 L3 映射时收敛)。
## 护理员 APP(Flutter)
- [x] ~~**[高] 异常/扑空离线补传非幂等**~~ ✅ 已修(2026-10-21):record_abnormal 加 client_md5 唯一 + report 幂等 + Flutter 补传传 md5。
- [x] ~~**[高] 工单完成态不回显**~~ ✅ 已修(2026-10-21):checkin→serving、checkout→done、offlineSync 同步;Flutter 签退后 invalidate today。
- [ ] **压疮结构化标签后端无字段**(RecordPhoto 无部位/分期字段,APP 仅会话内留存);压疮项靠 svcName 含「压疮」识别(脆弱)。
- [ ] **异常照片/语音后端无上传端点**:APP 在线/离线异常照片字节都未上传,却置 hasPhoto=true(乐观标记,误报);语音占位未实现。
- [ ] **离线照片直传通道缺**(R8 已发空数组);cleanupExpiredPhotos 死代码;临时目录不保证 ≥7 天(宜落 Documents 目录并接线清理)。
- [ ] **isOfflineError 不把 DioExceptionType.unknown 当断网**(真机飞行模式可能判错);补传「毒消息」静默驻留(无死信/提示)。
- [ ] 大字 ≥20pt 未全覆盖(badge/chip 仍小);undoReason 未采集;OfflineDb 实体无直接测试。