交付出件箱

← 返回出件箱

Phase 74 · patients 表处置说明(给 root)

2026-08-24 · dev2 · 应 root 要求书面确认
本文结论均为 sudo db-prod / git grep 实查,非推断;每条附证据。


〇、一句话结论

patients 表不要清理 —— 它是在役表,门店平板端强依赖,Phase 74 家长档案也建在它上面。
处置口径 = 保留但隔离(隔离已实装于分支 · 生产待迁移生效 · 见 §三)。


一、先纠正一处前提(重要,否则会做错决定)

root 原文:

「而 Phase 74 方案定的是 vision_exams 单表承载(D-A) —— 等于绕过了 patients」

实际情况相反:方案文档确实写了 vision_exams,但代码实现走的是 patients。

文档写的 代码实际
家长档案主体 vision_exams(D-A) patients
家长检查记录 vision_exams refractive_records + _eyes
vision_exams 在家长链路的命中 —— 0(grep -c 实证)

证据:

$ grep -c "vision_exams\|VisionExam" app/api/parent_patients.py app/api/parent_ocr.py
app/api/parent_patients.py:0
app/api/parent_ocr.py:0

判定:实现是对的,文档口径写错了。 已在两处文档标注作废并写明实证
(tech/phase74-c-end-parent-tech-v0.1.md §八之二 + flywheel-business.md §6.14)。

为什么 vision_exams 承载不了家长档案

-- 生产实查
SELECT count(*) AS 总数, count(patient_id) AS 挂了patient的 FROM vision_exams;
--  88 |  0        ← patient_id 全 NULL

vision_exams 事实上是按 org_id 归属的报告快照表(10 个机构),没有"孩子"这一层。
而家长端要的是「点开一个孩子 → 看他历次检查 → 画眼轴曲线」,必须有档案主体。
此外 refractive_records(+_eyes) 有双眼分行、验光方式、视力多记法、草稿态与版本并发控制,
效果图要求的四格数据与曲线全靠它;vision_exams 是宽表快照,做不到。

⚠️ D-A 的本意(长官原话)是「不能识别去 A 表、手填去 B 表,必须整到一个表」——
这一点 Phase 74 做到了:家长的手填与识别回填全部落同一套 refractive_records,没有分裂。
D-A 精神保留,承载表更正。


二、生产实况(与 root 所查一致,补两条他没提的)

表 行数 关键事实
patients 7 6 条「演示孩子」(2026-07-26 分发到 6 个 org)+ 1 条「小宝」(2026-05-17 测试)· root 说法属实
refractive_records 27 🔴 全部挂在那 7 条演示 patient 上(演示孩子 25 / 小宝 2)⇒ Phase 63 门店链在生产上也是演示态
vision_exams 88 patient_id 全 NULL,靠 org_id 归属
h5_reports 213 32 个不重复 external_user_id = 今天唯一真实的家长侧数据(与 root 判断一致)

三、处置决定:保留但隔离(root 三选一的第 3 项)

为什么不能「废弃」

refractive_records.patient_id 是 NOT NULL 外键,强依赖 patients。
把 patients 当死表清掉 → 门店平板端「视力与屈光检查记录」功能直接崩(Phase 63 在役功能)。
且 Phase 74 家长档案正建在这张表上(分支上已加归属列 · 生产待发版)。

它不是死表,是"低使用量的活表"。

为什么不做「迁移」

那 7 条是演示数据(演示孩子 / 小宝),无业务价值,迁进家长链路只会污染真实档案。
是否清理这 7 条与 Phase 74 无关 —— 若要清,建议 root 单独走数据清理流程,
但必须先删 refractive_records 里挂着的 27 条(外键),本 Phase 不动它们。

隔离怎么做的(已实装于分支 · 生产待迁移生效)

⚠️ 环境边界(root 2026-08-24 指正 · 已复验):
迁移 phase74_002 尚未上生产 —— 生产 patients 无 owner_type/owner_seat_id
(information_schema 实查 0 列,总列数 16);连 A 批的 users.seat_type 生产也没有
(0 列 / 总 33 列),因为 A+D 只发到 test。
⇒ 隔离逻辑在分支上已实装并有测试守门,但生产上尚未生效,待发版后
按「发版后 information_schema 物理验列」流程确认。

patients 加两列(migration phase74_002):

列 用途
owner_type 'seat'(门店建 · 默认)/ 'parent'(家长建)
owner_seat_id 家长席位 users.id

已有测试守门(真 PG 真打):
- test_store_cannot_see_parent_owned_patients —— 门店搜不到家长档案
- test_parent_creates_and_lists_own_children_only —— 家长只见自己的孩子,跨家长直读 404


四、两条链路怎么衔接(root 问的「同一个孩子会不会重复」)

会并存,但不是 bug —— 两条链记的不是同一件事。

报告秒读链(现存) 家长档案链(Phase 74 新增)
入口 上传报告 → 4L 解读 建档 → 填/拍检查单
落表 h5_reports + vision_exams patients + refractive_records(+_eyes)
归属键 external_user_id = seat_<id> owner_seat_id = <id>
语义 一次解读的快照(AI 结论/建议/图片) 一个孩子的成长档案(多次检查 + 眼轴曲线)
配额 吃秒读 6 次/365 天(G 批) 不吃(D-B 拍板 · 有源码级守门测试)

两个归属键指向同一行 users ⇒ 不会出现"两个不同的人",只是同一个人的两类记录。

一期不做自动关联(有意为之)

报告秒读没有"哪个孩子"这个维度。一个家长有多个孩子时,系统无法判断某份报告属于谁;
按席位强行关联会把老二的报告挂到老大档案上,比不关联更糟。

二期留口(不实装):提交检查单时可选「关联一份已有秒读报告」,由家长手动指认孩子 ——
届时在 refractive_records 加 source_report_id 一列即可,不动现有两条链。


五、给 root 的两条请求

  1. 🔴 不要把 patients 当死表清理 —— 门店平板端强依赖。若要清那 7 条演示数据,
    请先删 refractive_records 的 27 条,并知会我们(Phase 74 家长档案在同表上)。
  2. 口径以 tech/phase74-c-end-parent-tech-v0.1.md §八之二 为唯一事实源;
    若发现别处仍写「家长档案用 vision_exams」,那是已作废的旧口径,请以本文为准。

附:进度表状态

已按长官 8-24 授权改为 🔄(双文件同步)。
不标 ✅ 的依据:验收清单尚有 39 项未勾(浏览器 UAT / 识别准确性 test 真打 /
生产存量手机号重复检查),按验收铁律只要还有 [ ] 就不许标 ✅。

云机环境 · 生产数据引用均为 sudo db-prod 只读查询实际输出。