Files
chis_osi/tasks.md
T

19 KiB
Raw Blame History

任务看板(Tasks)

把 docs/05-实施路线图.md 的阶段拆成小步、可独立交付、可验收的任务。 每轮只领取一个状态为 TODO 且依赖均 DONE 的任务(取最靠前的)。

使用规则

  1. 开工前读 docs/current-state.md(当前快照)与 CLAUDE.md(硬规则)。
  2. 领取任务时把状态改为 DOING(同一时间最多 1 个)。
  3. 标 DONE 前必须有可运行证据:验证命令和结果追加到 progress.md;只有"代码已写"不算完成。
  4. 完成后:更新本文状态 → 追加 progress.md → 覆盖更新 docs/current-state.md。
  5. 代码现实与看板冲突时,先说明冲突,不擅自跳步。

状态图例:TODO 待开始 · DOING 进行中 · DONE 完成并验收 · BLOCKED 受阻(注明原因)


Phase B · 基线(接入 harness,先于一切新功能)

ID 任务 依赖 验收要点 状态
T-000 处理失效测试 tests/test_query_health_record.py - 它 import 的旧脚本 API 已删除(脚本已重写为硬编码版):要么删除,要么改写为校验新信封结构的最小测试;pytest tests/ 通过或目录清空 DONE

Phase 0 · 脚手架与契约骨架(路线图阶段 0)

ID 任务 依赖 验收要点 状态
T-001 初始化 go module + main.go 双子命令骨架 + config/(viper) - go build ./... 通过;-mode server|deliver 可解析;config.yaml.example 占位值就绪 DONE
T-002 osi/sign.go MD5 头签名 + 单测 T-001 单测校验 password=md5("ts=<ts>&ask=<ask>") 32 位小写;与 Python 脚本(scripts/,本地)产出比对一致 DONE
T-003 osi/transport.go:从 chis_upload 移植传输层 T-001 保留 SOCKS5/超时;去掉 cookiejar 与网页拟态头;单测或最小连通验证 DONE
T-004 osi/client.go Call + osi/codes.go + contract/envelope.go T-002, T-003 信封为 serviceId+uploadinfo{baseInfo,manageInfo,...}(docs/04 §8);成功码按去前导零 == "1" 判定(实测 "01",docs/01 §1);405 归类可重试 DONE
T-005 阶段 0 验收:Go 侧真实请求打通 + 配置 init.sh T-004 用 JKDA00002(Python 已验证的同一查询)发真实请求拿到 code="01";./init.sh 三命令替换完成,本机 Git Bash 运行限制见 progress 记录 DONE
T-006 Phase 0 review hardening T-005 处理审核指出的 gzip 声明、传输层死代码、命令行 PII、Envelope 冗余;go test ./... 通过 DONE

执行顺序说明(2026-07-06 重排,查询先行):原路线图"阶段1字典 → 阶段2档案"的顺序假设了先建字典。 但查询档案(Find)根本不依赖字典,映射纯函数单测也只需码表 + 注入假字典快照。 真正需要字典查询接口(网格/责任医生/机构反查)的只有真实创建闭环。 故按能力重排为 Q(查询)→ M(映射)→ D(字典+创建);ID 保持不变,osi/jkda.go 的 Find 与 Create 拆成 T-203 / T-206。 字母命名的执行阶段(B/0/Q/M/D)区别于 Backlog 里的"路线图阶段 3~6"。

Phase Q · 查询档案打通(Find,不依赖字典)

ID 任务 依赖 验收要点 状态
T-201 contract/jkda.go:以 docs/04 §8 实测契约建查询响应结构体 T-004 Find 响应能完整反序列化本地联调样本(data 数组、null 字段用指针/omitempty、adressNumber 坑点拼写);创建请求结构体延到 T-206 补 DONE
T-203 osi/jkda.go:Find + FindRqbj T-201 用 JKDA00002 真实请求打通,拿到 code="01" 与档案数据,与 Python 脚本结果一致 DONE
T-208 server 模式健康档案查询端点 GET /api/health-record/find T-203 server 模式起 HTTP 服务,curl 按 idCard/phrid/personName/empiId 查询返回平台完整档案 JSON;默认仅绑本机 DONE
T-209 优化人群分类查询 JKDA00005(路径/契约/HTTP 端点) T-203, T-208 按实测 auto/jkda/findrqbj 查询,响应结构含 personSign/idCard/phrId;server 模式提供人群分类查询端点并原样回写平台 JSON DONE

Phase M · 映射层(码表 + 纯函数,注入假字典快照)

ID 任务 依赖 验收要点 状态
T-102 mapping/dict.go 全量码表(含 56 项民族) T-001 双向查表;未命中显式 ValidationError;单测覆盖(静态枚举,不走网络) DONE
T-202 mapping/health_record.go + mapping/checkid.go T-102, T-201 映射纯函数 + 结构化校验错误;主数据经 MapContext 字典快照注入(单测塞假快照);checkId 确定性生成单测 DONE
T-205 映射单测基线:docx 样例 + 联调样本 T-202 go test ./mapping/... 全绿;必填/码表/格式校验生效 DONE

Phase D · 字典服务与创建闭环(真实主数据反查)

读先行调整(2026-07-08):档案创建/更新真实验收(现拆为 T-215)依赖厂家写入授权 + 安全测试档案(docs/06 D3),当前锁死。 故把其余业务线的查询(Phase Q2)提到写入之前先做——读路径不被授权阻塞,且顺带摸清各业务线响应字段,为将来写入去风险。 T-206 本地契约、客户端和映射组装代码已完成并通过测试;真实平台验收不再阻塞后续本地编排开发。

ID 任务 依赖 验收要点 状态
T-101 osi/public.go 四个字典查询(网格/责任医生/药品/机构) T-005 真实机构码能查到下级网格、责任医生、机构树 DONE
T-103 字典缓存(内存 + redis 可选) T-101, T-102 映射层能反查 regionCode/manaDoctorId/manaUnitId;redis 不可用不阻断 DONE
T-210 公开查询 HTTP API(人群分类、网格地址、责任医生、药品目录、机构) T-101, T-209 server 模式暴露人群分类与四类公开查询 HTTP API;原样回写平台 JSON;同步 docs/07 与 docs/openapi.yaml;按内网部署场景明确绑定地址/鉴权边界 DONE
T-211 药品目录查询按分页契约修正 YPML00001 T-210 依 docx:pageNo 必填(去 omitempty+handler 缺则 400)、补 pageSize;docs/07 §8+openapi.yaml 标 pageNo 必填并补 pageSize;docx 契约未联调,注明待厂家样本核对(尤其 pageNo 是否真必填、响应 ypxh/ypjl/ycjl 字段) DONE
T-206 osi/jkda.go:Create/Update 本地能力 + contract/jkda.go 写入请求结构体 T-201, T-202, T-103 JKDA00001/00003 serviceId、路径、uploadinfo 同级节点、响应解码和映射组装均有单测;go test ./contract ./osi ./mapping 通过 DONE(真实写入验收拆至 T-215)
T-204 handler+router:POST /api/health-record/upsert T-213 server 模式接收 PHIS 档案 DTO,调用同一 upsert 应用服务并返回结构化结果;handler 假依赖测试覆盖 create/update/manual_review/error,默认仍只绑定本机 TODO(真实 curl 验收待 T-215)

Phase Q2 · 其余业务线查询(读先行)

每条查询任务都顺带把响应真实字段记入 docs/04(像 §8),作为将来对应业务线 create 映射的事实基线。

ID 任务 依赖 验收要点 状态
T-301 体检查询打通:contract/jktj.go + osi/jktj.go(最近一次 JKTJLSJL00002) T-004 真实请求拿到 code="01" 与体检数据;响应字段(~260 项/7 节点)记入 docs/04 §11 DONE(单条 JKTJ00002 平台未部署,见 §11)
T-302 体检 HTTP 查询端点(复用 T-208 handler 模式) T-301 server 模式 GET /api/health-check/last+/all+/list curl 返回完整 JSON;默认仅绑本机 DONE
T-306 某人全部体检查询 JKTJ00002(osi.QueryHealthChecks + /api/health-check/all) T-004 实测已部署,按 idCard 返回全部体检数组;驼峰 idCard、历史记录 checkId 可空,契约见 docs/04 §11.1 DONE
T-303 老年人生活自理能力评估查询(LNRZLPG00002) T-004 按厂家查询文档实现 /auto/lnr/query;按 idCard 查询返回评估数组;真实请求确认 serviceId/路径/字段 BLOCKED(代码/单测/HTTP 文档完成;缺安全测试身份证做真实联调)
T-307 老年人中医体质辨识查询(LNRZYTZ00002) T-004 取得厂家查询契约后实现并真实请求打通 BLOCKED(待 docs/06 B4 补体质查询文档)
T-305 体检已检/未检名单查询 JKTJLIST00002(osi 方法 + 契约) T-004 auto/jktjlist/query 探针实测已部署(code=01 返回名单);osi.ListHealthCheckPeople 按 checkYear+idCard 返回名单(含 checkType 状态),契约见 docs/04 §11.4 DONE
T-304 列表类查询(档案 / 老年人自理·体质 / 中医指导 列表,serviceId docx 缺漏) T-004 各列表路径+serviceId 到位后返回分页数组 BLOCKED(待 docs/06 B1/B2 厂家回填)

Phase U · PHIS 健康档案转换与 upsert

输入事实来源为本地 payloads/441625198611255416_phis_health_record.json,目标契约来源为 docs/统一对外服务接口文档.docx 中 JKDA00001/JKDA00003,以及 docs/01、docs/04 的已整理契约。 两份本地原始材料均可能包含个人信息或凭据,只用于分析和生成脱敏测试夹具,不得提交 Git。

ID 任务 依赖 验收要点 状态
T-212 PHIS 健康档案真实结构建模与 PHIS→CHIS 转换器 T-202, T-103 建模 PHIS data.doctor/data.record/archId/businessId/empiId/phrId;先确认稳定源主键语义并落 ADR;完整转换 JKDA 主体、既往史和生活环境;校验必填/长度/日期/码表;脱敏 fixture 回归;按档案责任医生生成请求操作上下文 DONE
T-213 健康档案 upsert 应用编排(外部能力均接口注入) T-212, T-203, T-206 按身份证查询 CHIS:0 条创建、1 条合规档案更新、多条/跨机构/不可更新状态转人工;查询失败不得降级创建;用假 OSI/幂等/report/PHIS 回写实现验收,不在本任务实现持久化 TODO
T-215 JKDA 健康档案真实 create/update 验收 T-212, T-213 经明确授权的安全测试档案完成 create→query 回查→update→query 回查;确认 phrId、checkId、更新目标标识、addressNumber、责任医生/机构及重复提交语义,并回填 docs/03 §8、docs/04 §10 BLOCKED(待写入授权和可写测试档案)

T-212 需求与解决方案

需求

  • 接收 PHIS 健康档案响应,保留业务主键和档案数据;doctor.sxtAccount/sxtPassword 等凭据不得进入领域模型、日志、OSI 请求或测试夹具。
  • 把 PHIS 扁平字段转换为 CHIS uploadinfo 下同级的 healthRecord、pastHistory、jwsjb、jwsss、jwsws、jwssx、familyMiddle。
  • 支持字段改名:PHIS adressNumber → CHIS 写入字段 addressNumber。⚠ 该拼写仅有 docx 依据(查询响应实测是错拼 adressNumber,见 contract/jkda.go 查询结构体),列为首次真实创建后的联调必核对项:创建成功后回查该字段是否落库,若平台写入端实际收 adressNumber 则改名方向反转。
  • 支持结构转换:diseasetext_* → 既往史对象/数组,shhjCheck* → 生活环境对象;多选值统一输出英文逗号。
  • PHIS 未提供且 CHIS 非必填的 phoneNumber/addressCode/homePlaceCode/insuranceType/personGroup 不伪造值,按空值省略;后续若取得独立人群分类数据,再单独补充 personGroup。
  • 不根据单个样例预设 businessId 或 archId 的优先级。先向 PHIS 契约/维护方确认 archId/businessId/phrId/empiId 的语义、生命周期和更新时是否稳定,再由 ResolveSourceRecordKey 统一选择稳定源主键。
  • checkId 的同一源档案多次重试和多版本更新必须稳定;更新时间只用于版本审计。该调整会改变现有 GenerateCheckID(..., src.UpdatedAt) 行为,落地时必须同步修改调用、T-205 基线单测,并在 docs/decisions/ 记录主键事实、选择规则、回退规则和兼容影响;主键语义未确认前不得把策略标记为最终完成。
  • manageInfo.DSFMC/operateUnit 来自可信配置;operateUser 使用经责任医生字典验证的档案 manaDoctorId。若平台只允许固定配置医生,则必须校验二者一致,不得由客户端静默覆盖。

解决方案

  • 在 source/ 定义只含业务字段的 PHIS DTO,并提供 JSON 解码;对外层 code/msg/compress 和业务 data 分层建模。未知的医生账号/密码字段由解码器忽略,脱敏 fixture 放在 source/testdata/ 或 mapping/testdata/,不放入整体忽略的 payloads/。
  • 在 mapping/ 保持纯函数转换:直传字段显式赋值,码表字段统一走 dict.go,主数据通过 MapContext.MasterData 校验/反查,嵌套结构由专用小函数组装。
  • 扩充 contract.HealthRecordCreateInfo、PastHistory 和四类既往史结构,范围只到 PHIS 实际提供 + 本期映射需要的字段——不照搬 docx 写入字段全集(CLAUDE.md 铁律:docx 字段名/类型有前科,写入路径尚无联调样本兜底);docx 独有且 PHIS 给不出的字段不进结构体,确需预留的逐个标"待联调核对"。创建和更新复用同一业务数据契约,仅 serviceId/path 不同。
  • 返回结构化 ValidationError;身份证、日期、字段长度、CHIS 必填项、枚举和多选码未通过时禁止调用 OSI。
  • 建立逐字段映射表并由表驱动测试覆盖:主体直传字段;diseasetext_check_gm/check_bl/check_fq/CheckMQ/CheckXDJM/CheckZN/RedioYCBS/CheckCJ → pastHistory;diseasetext_radio_jb/ss/ws/sx → 四类数组;shhjCheckCFPFSS/RLLX/YS/CS/QCL → familyMiddle。
  • 既往史代码非空时生成对应节点(包括“无”代码),空值省略;名称/日期未提供时不伪造。isFillShhj=n 时省略 familyMiddle,为 y 时才校验并组装生活环境。真实写入后由 T-215 校准平台对“无”代码节点的最终要求。
  • 从真实 payload 派生脱敏 fixture,覆盖完整转换、可选字段省略、未知码值、缺失必填、空既往史、生活环境未填写、稳定主键跨版本不变,以及人工构造的主键缺失/回退场景。

T-212 落地结论(2026-07-16):参考 PHIS worker 回调契约与多业务样例后,确认健康档案使用 archId 作为稳定源键,businessId 只用于追踪/回写;archId 缺失直接失败,不做危险回退。详见 docs/decisions/001-phis-health-record-source-key.md。

T-213 upsert 规则

  1. 用 PHIS record.idCard 调用 JKDA00002 查询,只有明确成功响应才允许判断记录数量。
  2. 查询结果为 0 条:构造 JKDA00001 创建请求;查询结果为 1 条时,先校验身份证精确一致、档案状态可更新、目标机构/责任医生符合授权范围,再构造 JKDA00003 更新请求。
  3. 查询结果超过 1 条、跨机构或状态不可更新时停止投递并标记人工处理,禁止任选一条更新。
  4. 查询网络错误、超时、平台业务错误或响应无法解析时进入可重试/失败流程,禁止按“不存在”执行创建。
  5. 更新失败不得自动回退创建;创建失败也不得自动改走更新,避免平台状态不明时产生重复档案。
  6. 更新目标单独建模为 UpdateTarget,保留查询返回的 phrId/empiId/checkId/manaUnitId/status;仅把 T-215 真实契约确认允许的标识写入更新请求,不用 PHIS 空值覆盖平台已有值。
  7. 以稳定 checkId 和身份证建立幂等/并发保护;成功事件只记录脱敏后的 phrId、serviceId、响应码和 trace_id,禁止把原始 payload、OSI 完整请求/响应写入普通日志。
  8. 内部状态定义为 done/retry/failed/manual_review,只有 CHIS 明确成功码才标 done。T-213 只定义并注入 IdempotencyStore/ReportSink/PHISStatusWriter 接口,用内存假实现验证编排;Redis/文件持久化、重试调度和熔断统一留给路线图阶段 3。
  9. PHIS 真实回写由 T-214 实现;内部状态与 PHIS 实际支持状态分开建模,由适配器完成映射,不能预设 PHIS 原生支持 manual_review。
  10. T-213 提供可被 HTTP handler 和未来 deliver-worker 复用的单一应用服务;T-204 只做 HTTP 适配,不复制 upsert 逻辑。

里程碑

  • M1 = T-005:Go 客户端与平台真实握手成功(签名/信封/判码全对)。
  • M2 = T-203:Go 版查询档案打通(Find,不碰字典)。
  • M3 = T-205:映射层就绪 + 单测基线(假字典快照)。
  • M4 = T-301:体检查询打通(其余业务线读先行第一条)。
  • M5 = T-215:真实 upsert 闭环(授权到位后,PHIS 转换 → create/query/update → 回查确认)。

待办池(Backlog,按路线图阶段 3~6 展开,进入时再拆小任务)

  • 阶段 3:投递流水线(retry/idempotency/circuit/report + -mode deliver)。
  • 阶段 4:其余业务线(体检 JKTJ 字段最多、老年人自理、中医体质、中医指导——B1/B2/B5 契约到位后拆)。
  • 阶段 5:PHIS 真实接入与状态回写。
  • 阶段 6:加固与交接(完整度定论、密钥环境变量化、运维文档、全绿)。
  • 联调依赖跟踪见 docs/06-厂家联调清单.md(B 组契约缺口会阻塞阶段 4)。

已登记的延期任务(带 ID,条件满足即提升到对应 Phase)

ID 任务 触发条件 验收要点 状态
T-007 传输层支持 https/TLS 生产环境地址确认为 https 时必须先做(沙箱是 http,不阻塞当前开发) osi/transport.go 裸 HTTP/1.1 写目前仅支持 http(明文 TCP、scheme != "http" 直接报错)。需在 TLS 下同样保留 orgCode/deviceSN/userName 头名大小写策略;对 https 目标能发起真实请求并拿到 code;单测覆盖 https 路径 TODO(生产前 gate)
T-214 PHIS 状态真实回写(替换 T-213 假实现) PHIS 回写接口契约到位(路线图阶段 5,回写接口/字段/状态码确认后启动) 实现 T-213 的 PHISStatusWriter:把内部 done/retry/failed/manual_review 映射为 PHIS 实际支持的状态/字段;回写失败不覆盖本地最终状态并可补偿重试;日志脱敏 TODO(依赖 PHIS 侧契约)

来源:docs/review/2026-07-06-phase0-review.md P1-2。向厂家确认生产地址协议(见 docs/06 A10)后,若为 https 则本任务提升为阻断项;若确认生产仍是 http,则关闭本任务并在传输层注释说明。