chore(openspec): 归档 C1/C2/C3 change,spec 合并进主 specs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-15 01:13:08 +08:00
parent 9a91fc6597
commit 19876fdadd
36 changed files with 393 additions and 0 deletions

View File

@ -0,0 +1,27 @@
# backend/abnormal Specification
## Purpose
定义服务机构端异常上报域的后端行为——异常上报(9 宫格)与扑空(未遇)专门形态。
## Requirements
### Requirement: 异常上报
`POST /abnormal/report` MUST 仅 abnormal_type 必选,其余(desc/voice/photo/关联)可选;关联 record 或 order(扑空)。
#### Scenario: 分类必选其余可选
- **WHEN** 上报异常只选分类、其余留空
- **THEN** 允许提交(宁要一条没人名的异常也不要漏报)
### Requirement: 扑空专门形态
扑空(未遇)MUST:工单转 not_met(not_met_reason/not_met_at)+ 写 record_abnormal(到访时间/定位/原因必留);不产生 record、不计费。与「逾期未做」(到点无记录)严格区分。
#### Scenario: 扑空留证据
- **WHEN** 护理员登记未遇(老人不在/拒绝/改期)
- **THEN** 到访时间+定位+原因必留,工单转 not_met,不产生服务记录
### Requirement: 异常列表
`GET /abnormal/list` MUST 返回异常列表(后台 B4),按 abnormal_type/notify_status/handle_status/老人 筛选。
#### Scenario: 质控查看异常
- **WHEN** 质控员打开异常列表
- **THEN** 看到异常分类、状态、关联老人

View File

@ -0,0 +1,41 @@
# backend/elder Specification
## Purpose
定义服务机构端待遇档案(elder)域的后端行为——老人建档、十态状态机、评估结论承载、身份证防重与掩码。
## Requirements
### Requirement: 老人建档
`POST /elder` MUST 校验身份证 18 位+校验位、出生日期由身份证带出、同机构 id_card_no 唯一、待遇止 > 起;建档后按待遇有效期置初始状态(active 或 waiting_period)。
#### Scenario: 身份证防重
- **WHEN** 同机构重复录入同一 id_card_no
- **THEN** 提示「已有档案」,不创建重复档案
### Requirement: 等级唯一来源
建档时 assess_level/care_level MUST 绑定评估结论副本(assess_evidence_file):有等级必须有副本,否则拒绝(ELDER_LEVEL_REQUIRES_EVIDENCE)。
#### Scenario: 等级绑定副本
- **WHEN** 建档请求携带 assess_level 但无 assess_evidence_file
- **THEN** 拒绝并返回 ELDER_LEVEL_REQUIRES_EVIDENCE
### Requirement: 十态状态机
`elder.treat_status` MUST 支持十态;状态变更 MUST 写 elder_status_log 且 change_reason 必填。
#### Scenario: 状态变更留痕
- **WHEN** 变更状态缺 change_reason
- **THEN** 拒绝并返回校验错误
### Requirement: 评估结论副本上传
`POST /elder/assess-evidence` MUST 上传文件到 MinIO 并返回 file key。
#### Scenario: 上传成功
- **WHEN** 上传评估结论副本
- **THEN** 返回 file key,供建档引用
### Requirement: 身份证明文查看留痕
仅 admin/qc 可查看身份证明文,且每次明文查看 MUST 落审计。
#### Scenario: 明文查看留痕
- **WHEN** qc 查看老人身份证明文
- **THEN** 写一条审计日志

View File

@ -0,0 +1,34 @@
# backend/order Specification
## Purpose
定义服务机构端工单域的后端行为——八态工单、派单/调单/取消、时间冲突硬拦、批量推荐。
## Requirements
### Requirement: 派单前置校验
`POST /order/assign` MUST 按序校验:工单态 → 老人态(treat_status ∈ {active, waiting_period},否则 1001)→ 有计划(否则 1002)→ 护理员当班 → 时间冲突(2001 硬拦)→ 资质(1006 提示)。
#### Scenario: 无有效待遇不可派单
- **WHEN** 派单时老人 treat_status 非 active/waiting_period
- **THEN** 返回 1001 拒绝
### Requirement: 时间冲突硬拦
同 assignee_id 且 time_slot 重叠 MUST 拒绝(2001)。
#### Scenario: 同时段重叠
- **WHEN** 同一护理员已有 09:00-10:00 工单,再派 09:30-10:30
- **THEN** 返回 2001,拒绝保存
### Requirement: 调单与批量推荐
`POST /order/:id/reassign` MUST 记 reschedule_log(改前改后/时间/操作人);`GET /order/batch-recommend` MUST 只返回推荐(权重:同资质→历史服务过→距离近→负荷低),不自动派单。
#### Scenario: 调单留痕
- **WHEN** 调单改派护理员
- **THEN** 写 reschedule_log 并通知新护理员
### Requirement: 工单八态
order_status MUST 支持 to_assign/assigned/serving/done/abnormal/cancelled/overdue/not_met;取消必填 cancel_reason。
#### Scenario: 取消需原因
- **WHEN** 取消工单缺 cancel_reason
- **THEN** 拒绝

View File

@ -0,0 +1,27 @@
# backend/plan Specification
## Purpose
定义服务机构端服务计划与老人个人项目库的后端行为——制定/变更计划、属地项数校验、个人项目库带入。
## Requirements
### Requirement: 制定服务计划
`POST /plan` MUST 校验:老人存在、项目从本机构 L4 选、属地项数(昆明校验/州市提示)、care_mode×care_level 规则。plan_status 置 active。
#### Scenario: 制定计划
- **WHEN** 质控员制定计划并选够项目
- **THEN** 创建 active 计划,item_count 与 item_count_rule 快照记录
### Requirement: 计划变更不原地改
`POST /plan/change` MUST 新建计划 + change_from_plan_id 指向旧计划,旧计划转 changed。
#### Scenario: 变更留旧版
- **WHEN** 变更计划
- **THEN** 旧计划转 changed、新计划 active,历史工单仍指向旧计划
### Requirement: 老人个人项目库
`PUT /elder-svc/:elderId` MUST 整表覆盖(svc_id 必须落在本机构 L4、care_mode 变更=重制、旧库留档);制定计划可一键带入。
#### Scenario: 带入计划
- **WHEN** 制定计划时选择「从个人项目库带入」
- **THEN** 自动生成 plan_item 初稿,可修改

View File

@ -0,0 +1,63 @@
# backend/record Specification
## Purpose
定义服务机构端履约留痕域的后端行为——签到/签退/项目执行/照片/离线补传/垫付台账与结转。
## Requirements
### Requirement: 签到
`POST /record/checkin` MUST 校验 L3(order 存在、order_status ∈ {assigned, serving}、elder/assignee 匹配);checkin_time 服务器取时(不接受客户端传入);定位失败 3002 不阻塞(locate_status=failed/denied);建 record(serving)并返回 record_id。
#### Scenario: 服务器取时
- **WHEN** 签到
- **THEN** checkin_time 由服务端生成,客户端传入被忽略
#### Scenario: 定位失败不阻塞
- **WHEN** 签到但定位失败
- **THEN** 标记 locate_status=failed,照常提交(3002)
### Requirement: 签退提交
`POST /record/checkout` MUST 校验必拍未拍(3001 硬拒 + 拒拍出路 is_refused_photo=1);checkout_time/duration_min 服务器取时;record_status 转 submitted;waiting_period 老人 is_prepaid=1、billable=0(3004 仅标记)。
#### Scenario: 必拍未拍硬拒
- **WHEN** 必拍项未拍照且未走拒拍出路
- **THEN** 返回 3001 拒绝签退
#### Scenario: 垫付标记
- **WHEN** 等待期老人签退
- **THEN** record.is_prepaid=1、billable=0,不计费
### Requirement: 项目执行
`POST /record/item/save` MUST exec_result ∈ {done, undo_not_done, undo_refused};svc_id 落本机构 L4;photo_required 快照自 order.item_list。
#### Scenario: 措辞纪律
- **WHEN** 项目未执行
- **THEN** exec_result 用 undo_not_done(非 not_done)
### Requirement: 照片上传
`POST /record/photo/upload` MUST 校验文件 ≤500KB;visible_to_family=0;keep_until 补传后 ≥7 天。
#### Scenario: 超限拒绝
- **WHEN** 上传超过 500KB 的照片
- **THEN** 拒绝并提示压缩
### Requirement: 离线补传
`POST /record/offline/sync` MUST 按 client_md5 幂等去重(重复提交返回已存在,静默不弹窗)。
#### Scenario: 去重
- **WHEN** 同 client_md5 重复补传
- **THEN** 幂等返回,不重复落库
### Requirement: 垫付台账与结转
`waiting_period` 老人留痕 MUST `is_prepaid=1`、`billable=0`;`POST /record/prepaid/carryover` MUST 勾选若干 is_prepaid=1 记录 → 生成对应正式记录(复制、is_prepaid=0、source_prepaid_of=原 id),原记录保留只读、不改原始时间戳(签到时间/定位/照片仍是原始值)。
#### Scenario: 结转不改原始时间戳
- **WHEN** 结转垫付记录
- **THEN** 新记录签到时间/定位/照片仍为原始值,仅标记来源
### Requirement: 留痕列表与详情
`GET /record/list`(admin B3,按 elder/assignee/日期/状态筛选)与 `GET /record/detail` MUST 返回留痕列表/详情(含项目、照片、异常、定位、垫付标记)。
#### Scenario: 质控查看留痕
- **WHEN** 质控员查询留痕列表与详情
- **THEN** 返回时间/项目/照片/异常/定位/垫付标记

View File

@ -0,0 +1,27 @@
# frontend/ad/elder Specification
## Purpose
定义服务机构端「服务对象」页面——老人档案列表、建档表单、详情与状态变更的交互。
## Requirements
### Requirement: 服务对象列表
列表 MUST 显示姓名/护理等级(带「(最高级)」)/状态/计划/下次服务,支持状态筛选。
#### Scenario: 状态筛选
- **WHEN** 按「住院暂停」筛选
- **THEN** 只显示该状态的老人
### Requirement: 建档表单
建档表单 MUST 含身份证校验、出生日期自动带出、参保地默认取机构属地、参保核验字段、评估结论副本上传与等级录入(等级必须绑定评估结论副本)。
#### Scenario: 等级绑定副本
- **WHEN** 填了等级但未上传评估结论副本
- **THEN** 拦截提交,提示先上传副本
### Requirement: 状态变更
详情页 MUST 支持十态状态变更(原因必填)+ 状态日志时间线。
#### Scenario: 变更需原因
- **WHEN** 变更状态未填原因
- **THEN** 不允许提交

View File

@ -0,0 +1,27 @@
# frontend/ad/record Specification
## Purpose
定义服务机构端「工单留痕」「异常列表」页面与服务对象页结转入口的交互。
## Requirements
### Requirement: 工单留痕页
admin「工单留痕」页 MUST 提供记录列表 + 详情(签到/签退时间、时长、项目 exec_result、照片、异常、定位、垫付标记);质控员/院长可见,护理员看自己。
#### Scenario: 查看留痕
- **WHEN** 质控员打开工单留痕
- **THEN** 看到记录列表与详情(时间/项目/照片/异常/定位)
### Requirement: 异常列表页
admin「异常列表」页 MUST 展示异常(分类、状态、关联老人、语音/照片入口)。
#### Scenario: 查看异常
- **WHEN** 质控员打开异常列表
- **THEN** 看到异常分类与状态
### Requirement: 结转入口
服务对象页 MUST 在待遇转「正常享受」后提供「结转垫付期服务」按钮:勾选 is_prepaid=1 记录 → 生成正式记录,原记录保留只读。
#### Scenario: 结转垫付
- **WHEN** 待遇已生效,点「结转垫付期服务」
- **THEN** 勾选垫付记录生成正式记录,原记录保留只读

View File

@ -0,0 +1,20 @@
# frontend/ad/schedule Specification
## Purpose
定义服务机构端「排班派单」页面与「服务对象」页扩展的交互。
## Requirements
### Requirement: 排班派单页
日视图(横轴时间段/纵轴护理员)MUST 显示工单卡片、空缺橙框、冲突红框;调单面板 ≤3 步;批量推荐需人工确认。
#### Scenario: 调单三步
- **WHEN** 点击卡片→选目标护理员→确认
- **THEN** 生效并自动通知
### Requirement: 服务对象页扩展
档案页 MUST 提供「个人项目库」区块(勾选 L4 项目、可空)与「制定计划」入口(一键带入、可改、校验项数)。
#### Scenario: 从个人项目库带入
- **WHEN** 制定计划并点「从个人项目库带入」
- **THEN** 自动生成计划项初稿,可修改

View File

@ -18,3 +18,56 @@
#### Scenario: 资质不匹配提示级 #### Scenario: 资质不匹配提示级
- **WHEN** 派单时护理员资质不匹配 - **WHEN** 派单时护理员资质不匹配
- **THEN** 返回 1006,前端仅提示、允许继续(本期不拦截,二期改硬拒) - **THEN** 返回 1006,前端仅提示、允许继续(本期不拦截,二期改硬拒)
### Requirement: 老人档案接口
`GET /elder`、`POST /elder`、`GET /elder/:id`、`POST /elder/:id/status`、`GET /elder/:id/status/log`、`POST /elder/assess-evidence` MUST 存在,遵循统一响应 `{code,message,data,hint}`。
#### Scenario: 状态变更必填原因
- **WHEN** 调用 `/elder/:id/status` 且缺 change_reason
- **THEN** 返回校验错误,拒绝变更
### Requirement: 身份证服务端掩码
`/elder/list` MUST 返回掩码后的身份证(如 `5301**********1234`);明文仅在 `/elder/detail` 且 admin/qc 授权时返回,并 MUST 落审计。
#### Scenario: 列表掩码
- **WHEN** 调用 `/elder/list`
- **THEN** id_card_no 返回掩码值,非明文
### Requirement: 计划与工单接口
`POST /plan`、`POST /plan/change`、`GET /plan/:id`、`POST /plan/:id/confirm`、`GET /plan/by-elder/:elderId`、`POST /order/generate`、`POST /order/assign`、`POST /order/:id/reassign`、`GET /order/batch-recommend`、`GET /order/today`、`POST /order/:id/cancel`、`GET /order/:id`、`GET /elder-svc/:elderId`、`PUT /elder-svc/:elderId` MUST 存在,遵循统一响应。
#### Scenario: 时间冲突硬拒
- **WHEN** 派单时同护理员时间重叠
- **THEN** 返回 2001,拒绝保存
### Requirement: 属地项数校验
制定计划时,昆明按 care_mode×care_level 校验项数(一级≥18/二级≥15/三级≥13,附加≤5),不满足返回 2002(提示级);州市只提示不拦。
#### Scenario: 昆明项数不满足
- **WHEN** 昆明一级护理计划项数 < 18
- **THEN** 返回 2002 提示,不硬拦
### Requirement: 履约留痕接口
`POST /record/checkin`、`POST /record/item/save`、`POST /record/photo/upload`、`POST /record/checkout`、`POST /record/offline/sync`、`GET /record/:id`、`GET /record`、`GET /record/prepaid-list`、`POST /record/prepaid/carryover` MUST 存在,遵循统一响应。
#### Scenario: 签退必拍未拍硬拒
- **WHEN** 必拍项未拍照且未走拒拍出路时签退
- **THEN** 返回 3001,拒绝签退
#### Scenario: 签到服务器取时
- **WHEN** 签到
- **THEN** checkin_time 由服务端生成,客户端传入被忽略
### Requirement: 异常接口
`POST /abnormal`、`GET /abnormal` MUST 存在,遵循统一响应。
#### Scenario: 扑空
- **WHEN** 护理员登记未遇(扑空)
- **THEN** 工单转 not_met、到访时间/定位/原因必留、不产生 record
### Requirement: 垫付结转接口
`GET /record/prepaid-list` MUST 返回老人垫付台账(is_prepaid=1);`POST /record/prepaid/carryover` MUST 勾选垫付记录生成正式记录,原记录保留只读。
#### Scenario: 结转不改原始时间戳
- **WHEN** 结转垫付记录
- **THEN** 新记录签到时间/定位/照片仍为原始值,仅标记来源=垫付台账

View File

@ -53,3 +53,77 @@
#### Scenario: 属地配置驱动目录 #### Scenario: 属地配置驱动目录
- **WHEN** 新增一个州市 - **WHEN** 新增一个州市
- **THEN** 插入一条 `loc_config` + 一批 `svc_local` 即生效,无需改代码 - **THEN** 插入一条 `loc_config` + 一批 `svc_local` 即生效,无需改代码
### Requirement: 老人档案实体 elder
`elder` 表 MUST 存在,承载老人档案字段(tenant_code、loc_code、name、gender、birth_date、id_card_no、insur_no/type、assess_level/care_level、assess_date/org、assess_evidence_file、benefit_start/end、treat_status、hosp_start/end、note 等),主键 UUID v7,`tenant_code` 多租户隔离,`tenant_code + id_card_no` 唯一。
#### Scenario: 老人档案归属机构
- **WHEN** 创建一条老人档案
- **THEN** 带 tenant_code,读操作按当前租户自动过滤
#### Scenario: 同机构身份证唯一
- **WHEN** 同机构重复录入同一 id_card_no
- **THEN** 命中唯一约束,提示「已有档案」
### Requirement: 待遇状态日志实体 elder_status_log
`elder_status_log` 表 MUST 存在;每次待遇状态变更 MUST 写一条日志,含 from_status/to_status/change_reason(必填)/operator_id/changed_at。
#### Scenario: 状态变更留痕
- **WHEN** 变更老人待遇状态
- **THEN** 写入一条 elder_status_log,change_reason 非空
### Requirement: 服务计划实体 svc_plan / svc_plan_item
`svc_plan` 表 MUST 存在(plan_period_start/end、care_level、care_mode、item_count、item_count_rule、plan_status、change_from_plan_id 等);`svc_plan_item` MUST 存在(svc_id 引 L4、svc_name_snapshot、freq_type/value、duration_min、photo_tier、caution_note 等)。计划变更 MUST 新建 + change_from_plan_id 指向旧计划,不原地改。
#### Scenario: 计划变更留旧版
- **WHEN** 变更某老人的服务计划
- **THEN** 生成新计划并指向旧计划,旧计划保留
### Requirement: 工单实体 svc_order
`svc_order` 表 MUST 存在(plan_id、service_date、time_slot_start/end、assignee_id、order_status、item_list(json)、reschedule_log(json)、not_met_reason/at 等)。
#### Scenario: 工单关联计划
- **WHEN** 生成一张工单
- **THEN** 工单带 plan_id,item_list 为计划项目快照
### Requirement: 老人个人项目库实体 ltc_elder_svc
`ltc_elder_svc` 表 MUST 存在(elder_id、svc_id 引 L4、svc_name_snapshot、care_mode、is_active),一人一份;svc_id 必须落在本机构 L4。
#### Scenario: 项目只能从 L4 选
- **WHEN** 保存个人项目库
- **THEN** svc_id 必须在本机构 svc_org 内,否则拒绝
### Requirement: 履约留痕实体 ho_record
`ho_record` 表 MUST 存在(order_id、elder_id、assignee_id、checkin_time、checkout_time、duration_min、checkin_lat/lng、locate_status、record_status、voice_file、offline_flag、client_md5、submit_time、actual_duration_tier、biz_line、is_prepaid、billable、source_prepaid_of)。`record_status` MUST ∈ {serving, submitted}(returned/passed 留 C4)。签到签退时间与时长由系统生成,不接受客户端传入。
#### Scenario: 留痕关联有效工单
- **WHEN** 创建一条留痕
- **THEN** 必须带 order_id 且工单有效(L3 硬锁)
### Requirement: 留痕项目明细 ho_record_item
`ho_record_item` 表 MUST 存在(record_id、svc_id 引 L4、svc_name_snapshot、exec_result、undo_reason、extra_flag、photo_required、is_refused_photo、refuse_reason)。`exec_result` MUST ∈ {done, undo_not_done, undo_refused}。
#### Scenario: 项目只能从 L4 选
- **WHEN** 保存留痕项目
- **THEN** svc_id 必须在本机构 svc_org 内,否则拒绝
### Requirement: 留痕照片 ho_record_photo
`ho_record_photo` 表 MUST 存在(record_id、svc_id、file_path、file_size、visible_to_family、upload_batch、keep_until)。`visible_to_family` 本期恒 0;文件压缩后 ≤500KB。
#### Scenario: 家属端不可见
- **WHEN** 上传留痕照片
- **THEN** visible_to_family = 0
### Requirement: 异常上报 ho_record_abnormal
`ho_record_abnormal` 表 MUST 存在(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)。`abnormal_type` MUST 必填,其余可选。
#### Scenario: 扑空无留痕
- **WHEN** 登记未遇(扑空)
- **THEN** record_id 为空、order_id 指向工单、abnormal_type 为扑空分类
### Requirement: 二期预留表 settlement / report
`settlement`/`report` 表 MUST 建空表不写业务数据(settlement 含 amount_fund/amount_self_pay 个人自付拆分字段)。
#### Scenario: 预留表空建
- **WHEN** 迁移完成后
- **THEN** settlement/report 表存在且无业务数据