Commit 08c515b6 by luoqi

docs(friday): push 契约收敛为 9 张自洽 source(宿主 inline 自己的引用)

确立职责边界:宿主推送前解析好自己的引用、inline 进相关行;PAC 只做跨宿主临床归一。
14 → 9 个 source,删掉 5 张 lookup-only 源表:
- std_diag / std_check_class(纯翻译字典)→ 宿主解析 stdCode/class_name inline 进 diag[]/med_check;
  省掉大表全量重推 + PAC 持久化字典存储(仅留 _shared 跨宿主临床字典)
- customer_contacts(PAC 只要默认号+归属)→ inline phone/phone_relationship 进 customer_basic_info
- settlement_modes(总值在结算头 net_receipts_this,24% 多通道拆付暂不需要)→ 不摄入
- customer_treat_plan 头(PAC 只取诊所/方案名)→ inline organization_id/plan_name 进计划行

结果:每张 source 自洽,增量推变更行天然成立,无跨表依赖/无新表/无 hydration。
注:manifest + export.sh 的对应改动(删 lookup、宿主侧 join inline)随后跟进。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parent 4ca27401
---
title: FRIDAY 推送数据契约
description: FRIDAY SaaS 按形态 A 推送的 14 个 source 及字段定义;字段形状与已验证的存量导出一致(宿主推原表,消费/退费等 WHERE 全在 PAC 侧切分)
description: FRIDAY SaaS 按形态 A 推送的 9 个 source 及字段定义;宿主推自洽的业务表(自己的引用 inline 进相关行),PAC 做跨宿主临床归一
icon: FileJson
---
......@@ -30,15 +30,23 @@ icon: FileJson
| **金额单位** | **元**(decimal 原值,实证:洁治单价均值 ¥310/已结算客单均值 ¥1,730);PAC 侧转分 |
| **投递语义** | at-least-once:未收到 2xx 确认就重推;重复由 PAC 幂等键吸收 |
> **职责边界(重要)**:宿主**在推送前解析好自己的引用**,把结果 inline 进相关业务行 ——
> ① 私有字典码(诊断 `linkCode→std_code`、影像 `class_code→类型名`)② 1:N 派生标量(默认联系号 + 归属)
> ③ 头-行属性(计划头的诊所/方案名下放到计划行)。这些**都是宿主自己的 within-host join**,数据在它手里、成本极低。
> PAC 只做**跨宿主的临床归一**(共享 K 码/modality/治疗类别字典、金额单位、时区、结算 status 切分、变更检测/版本)。
> 好处:每张 source 自洽,增量推变更行天然成立,无跨表依赖。
---
## 2. 患者与关系(3 个 source)
## 2. 患者(2 个 source)
### `customer_basic_info` — 患者主档
> ✅ 患者主档已支持 push(2026-07-20):**部分更新语义** —— 只更新本次提供的字段,
> 未提供的字段不覆盖存量(如只推 `customer_basic_info` 时 phone 不在场 → 保留库内号码);
> push 无"清空字段"语义,需要清空走全量通道。`customer_referee_circle`(关系边)同样可 push。
> **部分更新语义**:只更新本次提供的字段,未提供的不覆盖存量;push 无"清空字段"语义,需清空走全量通道。
>
> **联系电话已 inline(不再单独推 customer_contacts)**:宿主按 `is_default↓ → contacts_type↑(1=本人优先) → id↑`
> **挑出默认号**,把号码与归属 inline 进本表的 `phone` / `phone_relationship` 两列。PAC 现只消费这一个有效号 + 归属
> (存 `patient.phone` 与 `contactPhone.isSelf`),不需要完整通讯录 → 联系方式 1:N 表无需摄入。改号 = 重推本表。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
......@@ -49,20 +57,10 @@ icon: FileJson
| `file_number` | string | | 病历号/档案号(客服沟通用) |
| `tenant_id` | string | ✅ | 品牌 GUID(宿主原生列) |
| `organization_id` | string | | 建档诊所 |
| `phone` | string | | **默认联系号(宿主 inline)**——按上述规则挑出的有效号码 |
| `phone_relationship` | string/number | | **该号归属(宿主 inline)**——`PhoneRelationshipEnum`:`1`本人 `2`爸爸 `3`妈妈 `4`爷爷 `5`奶奶 `6`朋友 `7`配偶 `8`子女 `9`其他(PAC 存 `isSelf`=码=='1') |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | 建档/更新时间 |
### `customer_contacts` — 联系方式(1:N)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | string | ✅ | 行主键 |
| `customer_id` | string | ✅ | → 患者 id |
| `contacts_tel` | string | ✅ | 电话号码 |
| `is_default` | string/number | | 默认号标记(PAC 挑默认号:is_default↓ → contacts_type↑ → id↑) |
| `contacts_type` | string/number | | 联系类型(`1` 本人号候选优先) |
| `tel_type` | string/number | | 号码类型 |
| `relationship` | string/number | | 持号人与患者的关系(官方枚举 `PhoneRelationshipEnum`:`1`本人 `2`爸爸 `3`妈妈 `4`爷爷 `5`奶奶 `6`朋友 `7`配偶 `8`子女 `9`其他) |
### `customer_referee_circle` — 转介绍圈(患者-患者关系)
| 字段 | 类型 | 必填 | 说明 |
......@@ -98,7 +96,7 @@ icon: FileJson
---
## 4. 病历链(4 个 source)
## 4. 病历链(2 个 source)
### `med_emr_info` — 病历正文(Mongo 平铺;一张表喂诊断/治疗/建议/复查/病历全链)
......@@ -117,7 +115,7 @@ icon: FileJson
| `clinic_time` | string(datetime) | ✅ | 就诊时刻 |
| `visit_indicator` | number | | `1`初诊 `2`复诊 |
| `status` | number | ✅ | `3`已完成 `4`归档(推送范围) |
| `diag` | array | | 诊断数组,元素 `{ "toothPosition": "41;42", "value": "慢性牙髓炎", "linkCode": "<std_diag.diag_code 或空>" }` |
| `diag` | array | | 诊断数组,元素 `{ "toothPosition": "41;42", "value": "慢性牙髓炎", "stdCode": "<宿主已解析的标准码或空>" }`。**`stdCode` 由宿主 inline**(原 `linkCode` → 自家 `std_diag.std_code` 解析好);K 开头 PAC 截 K 大类,非 K/空按自由文本 |
| `treat` | array | | 本次治疗数组,元素同上结构(`value`=治疗名) |
| `dispose` | array | | 处置叙述数组,元素 `{ "toothPosition", "value" }` |
| `examine` | array | | 检查所见数组,元素同上 |
......@@ -130,17 +128,8 @@ icon: FileJson
> 牙位格式:FDI 牙位号,多牙分号分隔,可带牙面字母(`"42 L;43 D"` / `"11;12;13"`)。
### `std_diag` — 诊断字典(诊断链 lookup 用)
`diag[].linkCode` → `std_code` 的翻译字典;**按品牌维护**(各品牌一套诊断词表),但 `diag_code` **全局唯一**(UUID,跨品牌不撞),故 PAC lookup 不需租户限定。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `diag_code` | string | ✅ | 字典主键(= `diag[].linkCode` 指向;全局唯一) |
| `diag_name` | string | ✅ | 诊断名 |
| `std_code` | string | | 标准码(`K02.901` 等;K 开头 PAC 截 K 大类,非 K 按自由文本处理) |
> **推送方式**:字典是 lookup-only 参考数据,**按 `diag_code` upsert、增量推变更行**(与其他表一致,`updated_gmt_at` 驱动;PAC 侧持久化字典存储落地中)。
> **`std_diag` 不再单独推**——它是纯翻译字典(`linkCode→std_code`),离开诊断行无独立意义。
> 宿主在导出/推 `med_emr_info` 时,把 `diag[].linkCode` 用自家 `std_diag` 解析成 `stdCode` **inline 进 diag 元素**即可。
### `med_check` — 影像档案(metadata,不含文件本体)
......@@ -152,32 +141,25 @@ icon: FileJson
| `organization_name` | string | | 诊所名称(同上,诊所名字典来源之一) |
| `patient_id` | string | ✅ | → 患者 id |
| `emr_id` | string | | → 病历号(`med_emr_info.emr_id`) |
| `class_code` | string | | 影像类型 → `std_check_class` |
| `class_name` | string | | **影像类型名(宿主 inline)**——原 `class_code` 经自家 `std_check_class` 解析成类型名(口内像照片/小牙片/全景片/CT影像截图/口腔扫描…);PAC 再映射成 modality |
| `file_name` / `file_type` | string | | 文件名 / 类型 |
| `file_url` | string | | OSS 相对路径 |
| `files_size` | number | | 字节数 |
| `shooting_time` | string(datetime) | ✅ | 拍摄时间 |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | |
### `std_check_class` — 影像类型字典(med_check 配套 lookup)
`med_check.class_code` → 影像类型名的翻译字典,PAC 再映射成 modality。**按品牌维护**,`class_code` **全局唯一**(UUID),lookup 不需租户限定;类型少(全品牌合计约几十种)。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `class_code` | string | ✅ | 字典主键(= `med_check.class_code` 指向;全局唯一) |
| `class_name` | string | ✅ | 影像类型名(口内像照片 / 小牙片 / 全景片 / CT影像截图 / 口腔扫描…) |
| `tenant_id` | string | | 品牌 GUID(字典按品牌维护) |
> **推送方式**:同 `std_diag` —— lookup-only 参考数据,按 `class_code` upsert、增量推变更行(PAC 侧持久化字典存储落地中)。
> **`std_check_class` 不再单独推**——同 `std_diag`,纯翻译字典。宿主把 `med_check.class_code`
> 用自家字典解析成 `class_name` **inline 进 med_check 行**即可。
---
## 5. 结算链(3 个 source)
## 5. 结算链(2 个 source)
> **结算原表照抄推送,宿主不做任何 status/金额过滤或分流**——消费 / 整单退费 / 行级退费明细的
> 切分全部由 PAC transforms 完成(单一真理源,与 file / cold-import 同口径)。宿主只推 3 张原表:
> `patient_settlement`(结算头,全 status)、`patient_settlement_spec`(结算明细,全量)、`settlement_modes`。
> 切分全部由 PAC transforms 完成(单一真理源,与 file / cold-import 同口径)。宿主推 2 张原表:
> `patient_settlement`(结算头,全 status)、`patient_settlement_spec`(结算明细,全量)。
> **支付金额取结算头 `net_receipts_this`(实收);支付通道明细(`settlement_modes`)暂不摄入**
> (总值在结算头,PAC 当前无需通道拆分;若后续要"支付方式分析"再加)。
>
> `status` 全值照推,PAC 侧识别(`PatientSettlementEntity` 实体注释):`0`未结算 `1`已结算
> `2`只生成uuid `3`含退费行 `4`整单反向冲减 `5`重新结算(废弃历史) `6`医生未提交 `7`流程结束
......@@ -221,43 +203,24 @@ icon: FileJson
| `is_refund` | string/number | ✅ | `1`=退费行(PAC 只取此值切退费明细) `0`=正常明细 `2`=其他 |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | |
### `settlement_modes` — 支付通道明细(每单×通道一行)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | string | ✅ | 行主键 |
| `tenant_id` | string | ✅ | 品牌 GUID |
| `settlement_id` | string | ✅ | → 结算单 uuid |
| `modes_name` | string | ✅ | 通道名(现金支付/微信支付/刷卡支付/医保支付…原样即可) |
| `money` | number(元) | ✅ | 该通道金额(PAC 取金额最大者为主导通道) |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | | |
---
## 6. 治疗计划与咨询(3 个 source)
### `customer_treat_plan` — 治疗计划(头)
## 6. 治疗计划与咨询(2 个 source)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | string | ✅ | 计划主键 |
| `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | ✅ | 诊所(**行项靠头表拿诊所,缺失该行会被丢弃**) |
| `customer_id` | string | ✅ | → 患者 id |
| `plan_group_id` / `plan_group_num` | string | | 方案分组(多方案对比) |
| `plan_name` | string | | 方案名 |
| `desired_effect` / `emergency_urgency` | string/number | | 期望效果 / 紧迫度 |
| `expect_cost` | string | | 期望费用 |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | |
### `customer_treat_plan_item` — 治疗计划(行;头属性已 inline)
### `customer_treat_plan_item` — 治疗计划(行)
> **计划头 `customer_treat_plan` 不再单独推**——PAC 只从头取"诊所 + 方案名"两个属性给计划行,
> 头不是 PAC 实体。宿主把头的 `organization_id` / `plan_name` **inline 进每条计划行**即可;
> 头的 `expect_cost`/`desired_effect` PAC 暂不消费(将来做计划价值/LTV 再约定加)。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | string | ✅ | 行主键 |
| `tenant_id` | string | ✅ | 品牌 GUID |
| `customer_id` | string | ✅ | → 患者 id |
| `treat_plan_id` | string | ✅ | → 计划头 id |
| `organization_id` | string | ✅ | **诊所(宿主 inline,取自计划头)**——缺失该行会被 PAC 丢弃(计划事实必须归属诊所) |
| `plan_name` | string | | **方案名(宿主 inline,取自计划头)** |
| `treat_plan_id` | string | | → 计划头 id(留作溯源,PAC 不再靠它 lookup) |
| `tooth_position` | string | | 牙位 |
| `mode_name` | string | ✅ | 术式名(PAC 翻 11 类治疗类别) |
| `charge_min` / `charge_max` | number(元) | | 价格区间 |
......@@ -291,7 +254,7 @@ icon: FileJson
|---|---|---|
| 时间口径 | MySQL `datetime` = 北京墙钟(`_gmt_` 命名系惯例误导);**Mongo `Date` 是北京墙钟伪装成 UTC** | `clinicTime`/`createdGmtAt` 小时分布呈营业双峰;按真 UTC 解释则半数病历落深夜 |
| 金额单位 | 元(`decimal(9,2)`) | 洁治单价均值 ¥310、已结算客单均值 ¥1,730 |
| `contacts.relationship` | `PhoneRelationshipEnum` 1-9(见 §2) | customer 服务枚举类 |
| `phone_relationship`(默认号归属) | `PhoneRelationshipEnum` 1-9(见 §2;宿主挑默认号后 inline) | customer 服务枚举类 |
| `referee_relationship` | `RecommendRelationshipEnum` 17 码,**语义 = 本行 customer 是 referee 的 X**(PAC 侧按逆关系映射) | 枚举类 `reverseValue()` + 双方年龄差数据 |
| `med_emr_info.treat` vs `dispose` | `treat` = 本次治疗(→ 结构化治疗事实);`dispose` = 处置叙述(→ 病历自由文本) | EMR 接口 DTO 字段注释 |
| `patient_settlement.status` 全 9 值 | `0`未结算 `1`已结算 `2`只生成uuid `3`含退费行 `4`整单反向冲减 `5`重新结算(废弃历史) `6`医生未提交 `7`流程结束 `8`欠款补缴克隆单 | 实体注释 + `savePatientSettlementQk()` 实现 |
......@@ -303,5 +266,6 @@ icon: FileJson
|---|---|
| `organization_name` 覆盖 | 目前仅病历/影像表带诊所名,**只覆盖有病历记录的诊所**;其余诊所前端回退显示 GUID。若贵方有组织树接口(如 `regional_nodes_structure`),提供 `诊所 id → 名称` 全量表可补齐 |
| 品牌名 | PAC 当前**不需要**品牌中文名(无展示位,内部按品牌 id 标识)。将来若有展示需求,再约定推品牌主档(`tenant_apply.tenant_info` 的 `tenant_id`/`name`)——贵方 `tenant_name` 未冗余进业务表,只能走主档 |
| 字典表推送 | `std_diag`(生产多品牌合计可达 1.5万~3万+行)/ `std_check_class`(几十种):**按 code upsert、增量推变更行**(与其他表一致,`updated_gmt_at` 驱动);不必全量重推。依赖 PAC 侧持久化字典存储(落地中) |
| 私有字典不单独推 | `std_diag`(生产多品牌合计 1.5万~3万+行)/ `std_check_class`:纯翻译字典,**由宿主解析好 inline** 进 `diag[].stdCode` / `med_check.class_name`。既省掉大表全量重推,也省掉 PAC 侧持久化字典存储——PAC 只留跨宿主的 `_shared` 临床字典 |
| 支付通道 | `settlement_modes`(约 24% 结算单多通道拆付)暂不摄入:总值已在结算头 `net_receipts_this`,PAC 当前无支付方式分析需求。将来要"医保占比/分次支付"再摄入通道明细 |
| 测试环境数据特征 | 部分租户为开发沙盒(诊所名如"XX专用诊所勿动"),字典类映射(治疗类别关键词等)待**生产数据**回流后再校准一轮 |
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment