docs: 服务机构端 C3 履约留痕设计文档
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
173e1d2553
commit
c936732aa2
78
docs/superpowers/specs/2026-10-15-服务机构端-C3履约留痕-design.md
Normal file
78
docs/superpowers/specs/2026-10-15-服务机构端-C3履约留痕-design.md
Normal file
@ -0,0 +1,78 @@
|
||||
# 服务机构端 C3 履约留痕 · 设计文档
|
||||
|
||||
> 本文是 C3 履约留痕的设计背景,规范权威见 `openspec/changes/svc-org-c3-record/`(proposal + specs + design + tasks)与 PRD《20261011-投云长护险管理系统-P0 PRD(交付开发·V1)》。
|
||||
|
||||
## Context
|
||||
|
||||
C0–C2 已落地:elder(十态)、plan/plan_item、order(八态,含 not_met_reason/not_met_at)、elder_svc、staff、svc_org(L4)、排班派单。C3 新增**履约留痕**:护理员签到/签退/项目执行/拍照/异常上报 + 垫付台账与结转 + admin「工单留痕/异常列表」两页。录入主战场是护理员 APP(尚未开发),本期交付**后端 record 模块 + admin Web**,录入流程靠 API 冒烟验收(同 C2)。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals**:record/record_item/record_photo/record_abnormal 四表 + 录入 API(签到/项目/照片/签退/离线补传/详情)+ 异常上报/列表 + 垫付台账与结转(is_prepaid)+ admin 工单留痕/异常列表两页 + settlement/report 二期预留建空表。
|
||||
|
||||
**Non-Goals**:质控放行/退回(qc 表 + 4001 自审自放行,C4)、补正(质控退回联动,C4)、离线队列+自动补传(APP 期,本期只做 client_md5 去重)、家属端、结算对账(二期)。
|
||||
|
||||
## Decisions
|
||||
|
||||
1. **表命名**:`record`/`record_item`/`record_photo`/`record_abnormal`(禁用 checkin/clockin/punch)。`settlement`/`report` 为二期预留、本期建空表不写业务数据。`qc` 表 C4 建。
|
||||
2. **模块划分**:`src/record/`(record + item + photo + 签到/签退/离线)+ `src/abnormal/`(异常有独立生命周期 notify/handle,供 C4 质控联动)。垫付结转并入 record 模块。
|
||||
3. **record 生命周期**:`serving`(签到后)→ `submitted`(签退后);`returned`/`passed` 留 C4 质控。
|
||||
4. **服务器取时**:`checkin_time`/`checkout_time`/`duration_min` 一律系统取,接口不接受客户端传入(防补录时间)。`submit_time` 系统取。
|
||||
5. **is_prepaid**:record 创建时若 `elder.treat_status = waiting_period` → `is_prepaid=1`、`billable=0`(不计费、不进上报池,L1 例外不被误拦)。
|
||||
6. **结转**:待遇转「正常享受」后,档案页「结转垫付期服务」按钮 → 勾选若干 `is_prepaid=1` record → 生成对应正式 record(复制,`is_prepaid=0` + 来源标记),**原垫付记录永久保留只读、不改原始时间戳**(签到时间/定位/照片仍是原始值)。
|
||||
7. **扑空(未遇)**:异常上报专门子类 → 工单转 `not_met`(not_met_reason/not_met_at)+ 写 record_abnormal(abnormal_type=扑空分类,含到访时间/定位/原因)→ **不产生 record、不计费**。与「逾期未做」严格区分。
|
||||
8. **exec_result 枚举**:`done`/`undo_not_done`(本次未执行)/`undo_refused`(老人拒绝)——措辞纪律。
|
||||
9. **照片**:复用 C1 MinIO StorageService,压缩后 ≤500KB,`visible_to_family` 恒 0,`keep_until` 补传后 ≥7 天。
|
||||
10. **必拍未拍**:签退硬拒 `3001` + 拒拍出路(`is_refused_photo=1`+原因,放行)。
|
||||
11. **client_md5 去重**:离线补传按 client_md5 幂等,静默不弹窗。
|
||||
12. **主键口径**:全站已用 UUID v7 `@db.VarChar(36)`(PRD 写 varchar(32)),C3 循代码库口径 VarChar(36)(字段一致唯一锚点)。
|
||||
|
||||
## 数据模型(DDL 概览)
|
||||
|
||||
通用:UUID v7、`tenant_code`、`@map` snake_case、utf8mb4_general_ci。record 入 SOFT_DELETE;record_item/record_photo/record_abnormal 为子表(循 ElderStatusLog/PlanItem 先例:带 tenant_code、无 deleted_at、不入 SOFT_DELETE)。
|
||||
|
||||
- **record**(`ltc_record`? 否——用业务前缀):`id`、`tenant_code`、`order_id`、`elder_id`、`assignee_id`、`checkin_time`、`checkout_time`、`duration_min`、`checkin_lat`、`checkin_lng`、`locate_status`(ok/failed/denied)、`record_status`(serving/submitted)、`voice_file`、`offline_flag`、`client_md5`、`submit_time`、`actual_duration_tier`、`biz_line`(恒 ltci)、`is_prepaid`、`billable`、`source_prepaid_of`(结转来源标记)、时间戳 + `deleted_at`。索引 (tenant_code, order_id)、(tenant_code, elder_id)、(tenant_code, assignee_id, checkin_time)。
|
||||
- **record_item**:`id`、`tenant_code`、`record_id`、`svc_id`、`svc_name_snapshot`、`exec_result`(done/undo_not_done/undo_refused)、`undo_reason`、`extra_flag`、`photo_required`、`is_refused_photo`、`refuse_reason`。索引 (record_id)。
|
||||
- **record_photo**:`id`、`tenant_code`、`record_id`、`svc_id`、`file_path`、`file_size`、`visible_to_family`(恒 0)、`upload_batch`、`keep_until`。索引 (record_id)。
|
||||
- **record_abnormal**:`id`、`tenant_code`、`record_id`(可空,扑空时无)、`order_id`(可空,扑空时指向工单)、`elder_id`、`reporter_id`、`abnormal_type`(必选)、`abnormal_desc`、`voice_file`、`has_photo`、`notify_status`、`handle_status`、`handle_result`、`link_plan_change`。索引 (tenant_code, elder_id)、(tenant_code, notify_status)。
|
||||
- **settlement**(预留空表):`id`、`tenant_code`、`settle_period`、`amount_total`、`amount_passed`、`amount_rejected`、`amount_fund`、`amount_self_pay`、`submit_date`、`pay_date`、`exception_reason`、`handle_deadline`。
|
||||
- **report**(预留空表):`id`、`tenant_code`、`record_id`、`order_id`、`report_status`、`report_time`、`official_no`、`loc_code`、`nat_code_snapshot`、`adapter_result`。
|
||||
|
||||
> 表前缀(定):留痕属老人服务域,循 `ltc_` 先例(`ltc_elder`/`ltc_elder_status_log`/`ltc_elder_svc`)——`ltc_record`/`ltc_record_item`/`ltc_record_photo`/`ltc_record_abnormal`;`settlement`/`report` 为二期预留,无前缀(与 PRD §7.3 一致)。
|
||||
|
||||
## 接口(`@Controller('record')` / `@Controller('abnormal')`)
|
||||
|
||||
**record**
|
||||
- `POST /record/checkin` — 签到:校验 L3(order 存在、order_status ∈ {assigned, serving}、elder/assignee 匹配)→ 系统取 checkin_time → 定位可选(失败不阻塞 3002)→ 建 record(serving) → 返回 record_id。
|
||||
- `POST /record/item/save` — 保存项目执行:record_id + items[](svc_id 落本机构 L4、exec_result 枚举)。
|
||||
- `POST /record/photo/upload` — 上传照片:record_id + svc_id + file(≤500KB)→ MinIO → 返回 photo_id。
|
||||
- `POST /record/checkout` — 签退提交:record_id → 必拍未拍硬拒 3001(+拒拍出路)→ 系统取 checkout_time + duration_min → record_status=submitted。
|
||||
- `POST /record/offline/sync` — 离线补传:client_md5 去重幂等。
|
||||
- `GET /record/detail` — 详情。
|
||||
- `GET /record/list` — 工单留痕列表(admin B3,质控员/院长;筛选 elder/assignee/日期/状态)。
|
||||
- `GET /record/prepaid-list` — 垫付台账列表(档案页,按 elderId 查 is_prepaid=1)。
|
||||
- `POST /record/prepaid/carryover` — 结转:勾选 record_ids → 生成正式 record(复制、is_prepaid=0、source_prepaid_of=原 id)→ 原记录保留只读。
|
||||
|
||||
**abnormal**
|
||||
- `POST /abnormal/report` — 异常上报:abnormal_type 必选,其余可选;可关联 record 或 order(扑空)。
|
||||
- `GET /abnormal/list` — 异常列表(admin B4)。
|
||||
|
||||
权限码:record.checkin/itemSave/photoUpload/checkout/offlineSync/detail/list/prepaidList/prepaidCarryover、abnormal.report/list。错误码域 45(RECORD_* / ABNORMAL_*);规则号 3001/3002/3003/3004 写 message 文本(循 C2 R3 口径)。
|
||||
|
||||
## 硬锁与校验
|
||||
|
||||
- **L3**:留痕必须关联有效工单(order 存在且非 cancelled/not_met/done)。
|
||||
- **L1 例外**:waiting_period → is_prepaid=1、billable=0(不误拦)。
|
||||
- **必拍未拍** → 3001 硬拒;定位失败 → 3002 标记不阻塞;垫付 → 3004 标记不计费;扑空 → 3003 状态变更。
|
||||
- **服务器取时**:接口不接受 checkin_time/checkout_time/duration_min。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [离线补传幂等] → client_md5 唯一约束 + upsert;APP 期补本地队列。
|
||||
- [扑空 vs 逾期未做] → 扑空有到访时间/定位/原因佐证;逾期未做=到点无记录(C4 质控发现)。
|
||||
- [结转=复制而非改标记] → 两套并存,合规(不自动算钱);代价=存储翻倍但可追溯。
|
||||
- [必拍档项目清单的 source of truth] → photo_tier 来自 plan_item/order.item_list 快照;C3 落 record_item.photo_required 快照。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
新增 6 表(record/record_item/record_photo/record_abnormal + settlement/report 预留)。utf8mb4_general_ci 手改。⚠️ 迁移链已损坏(tech-debt):`migrate dev` 不可用,用 `migrate diff --from-schema-datasource` + 手工迁移目录 + `migrate deploy`。
|
||||
Loading…
x
Reference in New Issue
Block a user