18 KiB
任务看板(Tasks)
把
docs/05-实施路线图.md的阶段拆成小步、可独立交付、可验收的任务。 每轮只领取一个状态为TODO且依赖均DONE的任务(取最靠前的)。
使用规则
- 开工前读
docs/current-state.md(当前快照)与CLAUDE.md(硬规则)。 - 领取任务时把状态改为
DOING(同一时间最多 1 个)。 - 标
DONE前必须有可运行证据:验证命令和结果追加到progress.md;只有"代码已写"不算完成。 - 完成后:更新本文状态 → 追加
progress.md→ 覆盖更新docs/current-state.md。 - 代码现实与看板冲突时,先说明冲突,不擅自跳步。
状态图例: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 回归;按档案责任医生生成请求操作上下文 |
TODO |
| 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-213 upsert 规则
- 用 PHIS
record.idCard调用 JKDA00002 查询,只有明确成功响应才允许判断记录数量。 - 查询结果为 0 条:构造 JKDA00001 创建请求;查询结果为 1 条时,先校验身份证精确一致、档案状态可更新、目标机构/责任医生符合授权范围,再构造 JKDA00003 更新请求。
- 查询结果超过 1 条、跨机构或状态不可更新时停止投递并标记人工处理,禁止任选一条更新。
- 查询网络错误、超时、平台业务错误或响应无法解析时进入可重试/失败流程,禁止按“不存在”执行创建。
- 更新失败不得自动回退创建;创建失败也不得自动改走更新,避免平台状态不明时产生重复档案。
- 更新目标单独建模为
UpdateTarget,保留查询返回的phrId/empiId/checkId/manaUnitId/status;仅把 T-215 真实契约确认允许的标识写入更新请求,不用 PHIS 空值覆盖平台已有值。 - 以稳定
checkId和身份证建立幂等/并发保护;成功事件只记录脱敏后的phrId、serviceId、响应码和 trace_id,禁止把原始 payload、OSI 完整请求/响应写入普通日志。 - 内部状态定义为
done/retry/failed/manual_review,只有 CHIS 明确成功码才标done。T-213 只定义并注入IdempotencyStore/ReportSink/PHISStatusWriter接口,用内存假实现验证编排;Redis/文件持久化、重试调度和熔断统一留给路线图阶段 3。 - PHIS 真实回写由 T-214 实现;内部状态与 PHIS 实际支持状态分开建模,由适配器完成映射,不能预设 PHIS 原生支持
manual_review。 - 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.mdP1-2。向厂家确认生产地址协议(见docs/06A10)后,若为 https 则本任务提升为阻断项;若确认生产仍是 http,则关闭本任务并在传输层注释说明。