Commit 8ebe45ab by luoqi

refactor(sync/friday): 宿主字段零改名 — 撤销 tenant_id→brand_id 别名,差异由 PAC 适配层消化

原则修正(用户指出):要求宿主把 tenant_id 别名成 brand_id 是把 PAC 的概念洁癖转嫁给
宿主;字段名差异的消化本就是适配层职责。宿主(导出与将来 push)一列不改名。

- export.sh:撤销全部 AS brand_id;Mongo 平铺同步 tenant_id
- manifest:identity_namespace_field: tenant_id(指向宿主原生列)。无功能冲突:PAC 租户
  由 manifest 静态 tenant_id: friday-market 决定,StaticTenantResolver 不读行,行级
  tenant_id(品牌 GUID)仅作 source_unit 命名空间源
- push 契约文档:brand_id → tenant_id(宿主原生列),通用约定写明概念区分责任在 PAC

零数据翻腾证明:幂等键/患者唯一键用 source_unit 的值(品牌 GUID),列名不参与 ——
原生列名重导+重摄实测:0 新 txn/357,931 全量幂等命中/0 新 fact/failed=0,
source_unit 分布逐品牌不变。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parent 638d27fb
Pipeline #3394 failed in 0 seconds
...@@ -24,7 +24,7 @@ icon: FileJson ...@@ -24,7 +24,7 @@ icon: FileJson
|---|---| |---|---|
| **id 类字段一律字符串** | `patient_id` / `id` / `appointment_id` 等统一 String(数值型会被 PAC 校验拒收——存量摄入实测踩过的坑) | | **id 类字段一律字符串** | `patient_id` / `id` / `appointment_id` 等统一 String(数值型会被 PAC 校验拒收——存量摄入实测踩过的坑) |
| **时间格式** | `"YYYY-MM-DD HH:mm:ss"` 或 ISO8601;裸时间按 `Asia/Shanghai` 解释 | | **时间格式** | `"YYYY-MM-DD HH:mm:ss"` 或 ISO8601;裸时间按 `Asia/Shanghai` 解释 |
| **`brand_id`** | = FRIDAY 源库的 `tenant_id` 列**改名**(避免与 PAC 租户概念撞名)。品牌 GUID,PAC 用它做集团内患者号消歧 | | **`tenant_id`** | 宿主原生列,**不改名**。品牌 GUID,PAC 用它做集团内患者号消歧(与 PAC 自身租户概念的区分由 PAC 侧适配层负责) |
| **`updated_gmt_at` 必须随行更新 bump** | 它是幂等键的一半:不 bump,该行的更新会被永久去重丢弃 | | **`updated_gmt_at` 必须随行更新 bump** | 它是幂等键的一半:不 bump,该行的更新会被永久去重丢弃 |
| **空值** | 传 `null` 或省略字段;不要传 `"NULL"` 字符串 | | **空值** | 传 `null` 或省略字段;不要传 `"NULL"` 字符串 |
| **金额单位** | 元(decimal 原值);PAC 侧转分 | | **金额单位** | 元(decimal 原值);PAC 侧转分 |
...@@ -45,7 +45,7 @@ icon: FileJson ...@@ -45,7 +45,7 @@ icon: FileJson
| `sex` | string | | `1`=男 `2`=女,其余置空 | | `sex` | string | | `1`=男 `2`=女,其余置空 |
| `birthday` | string(date) | | 生日 | | `birthday` | string(date) | | 生日 |
| `file_number` | string | | 病历号/档案号(客服沟通用) | | `file_number` | string | | 病历号/档案号(客服沟通用) |
| `brand_id` | string | ✅ | 品牌 GUID(源 tenant_id) | | `tenant_id` | string | ✅ | 品牌 GUID(宿主原生列) |
| `organization_id` | string | | 建档诊所 | | `organization_id` | string | | 建档诊所 |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | 建档/更新时间 | | `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | 建档/更新时间 |
...@@ -66,7 +66,7 @@ icon: FileJson ...@@ -66,7 +66,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 行主键 | | `id` | string | ✅ | 行主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | | 诊所 | | `organization_id` | string | | 诊所 |
| `customer_id` | string | ✅ | 本人患者 id | | `customer_id` | string | ✅ | 本人患者 id |
| `referee_patient_id` | string | ✅ | 关系人患者 id(也是在册患者) | | `referee_patient_id` | string | ✅ | 关系人患者 id(也是在册患者) |
...@@ -85,7 +85,7 @@ icon: FileJson ...@@ -85,7 +85,7 @@ icon: FileJson
| `id` | string | ✅ | 预约主键 | | `id` | string | ✅ | 预约主键 |
| `patient_appointment_id` | string | ✅ | → 患者 id | | `patient_appointment_id` | string | ✅ | → 患者 id |
| `organization_id` | string | ✅ | 诊所 | | `organization_id` | string | ✅ | 诊所 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `appointment_date` | string(date) | ✅ | 预约日期 | | `appointment_date` | string(date) | ✅ | 预约日期 |
| `appointment_start` | string(time) | ✅ | 开始时刻(与 date 拼成预约时刻) | | `appointment_start` | string(time) | ✅ | 开始时刻(与 date 拼成预约时刻) |
| `appointment_status` | string | ✅ | `1`正常 `2`改约 `3`取消 `4`到诊 `5`接诊 `6`结算 `8`walkin `9`爽约;`10`草稿(推了也会被 PAC 丢弃) | | `appointment_status` | string | ✅ | `1`正常 `2`改约 `3`取消 `4`到诊 `5`接诊 `6`结算 `8`walkin `9`爽约;`10`草稿(推了也会被 PAC 丢弃) |
...@@ -107,7 +107,7 @@ icon: FileJson ...@@ -107,7 +107,7 @@ icon: FileJson
| `emr_sub_id` | string | ✅ | 小病历号 uuid(病历主键;临床事实同诊聚合锚) | | `emr_sub_id` | string | ✅ | 小病历号 uuid(病历主键;临床事实同诊聚合锚) |
| `emr_id` | string | ✅ | 病历号(如 `JY0A000231`;影像 `med_check.emr_id` 指向它) | | `emr_id` | string | ✅ | 病历号(如 `JY0A000231`;影像 `med_check.emr_id` 指向它) |
| `appointment_id` | string | | 关联预约 id(有则挂回预约链) | | `appointment_id` | string | | 关联预约 id(有则挂回预约链) |
| `brand_id` | string | ✅ | 品牌 GUID(源 tenantId) | | `tenant_id` | string | ✅ | 品牌 GUID(宿主原生 tenantId) |
| `organization_id` | string | ✅ | 诊所 | | `organization_id` | string | ✅ | 诊所 |
| `patient_id` | string | ✅ | → 患者 id | | `patient_id` | string | ✅ | → 患者 id |
| `user_id` / `user_name` | string | | 接诊医生 id / 姓名 | | `user_id` / `user_name` | string | | 接诊医生 id / 姓名 |
...@@ -140,7 +140,7 @@ icon: FileJson ...@@ -140,7 +140,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 行主键 | | `id` | string | ✅ | 行主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | ✅ | 诊所 | | `organization_id` | string | ✅ | 诊所 |
| `patient_id` | string | ✅ | → 患者 id | | `patient_id` | string | ✅ | → 患者 id |
| `emr_id` | string | | → 病历号(`med_emr_info.emr_id`) | | `emr_id` | string | | → 病历号(`med_emr_info.emr_id`) |
...@@ -151,7 +151,7 @@ icon: FileJson ...@@ -151,7 +151,7 @@ icon: FileJson
| `shooting_time` | string(datetime) | ✅ | 拍摄时间 | | `shooting_time` | string(datetime) | ✅ | 拍摄时间 |
| `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | | | `created_gmt_at` / `updated_gmt_at` | string(datetime) | ✅ | |
配套字典 **`std_check_class`**(低频):`class_code`(主键) / `class_name`(口内像照片、小牙片、全景片…) / `brand_id`。 配套字典 **`std_check_class`**(低频):`class_code`(主键) / `class_name`(口内像照片、小牙片、全景片…) / `tenant_id`。
--- ---
...@@ -167,7 +167,7 @@ icon: FileJson ...@@ -167,7 +167,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `uuid` | string | ✅ | 结算单主键 | | `uuid` | string | ✅ | 结算单主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | ✅ | 诊所 | | `organization_id` | string | ✅ | 诊所 |
| `patient_id` | string | ✅ | → 患者 id | | `patient_id` | string | ✅ | → 患者 id |
| `doctor_id` | string | | 开单医生 | | `doctor_id` | string | | 开单医生 |
...@@ -195,7 +195,7 @@ icon: FileJson ...@@ -195,7 +195,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 明细行主键 | | `id` | string | ✅ | 明细行主键 |
| `brand_id` / `organization_id` / `patient_id` | string | ✅ | 同上 | | `tenant_id` / `organization_id` / `patient_id` | string | ✅ | 同上 |
| `settlement_id` | string | ✅ | 所属结算单 uuid(退费挂回原消费) | | `settlement_id` | string | ✅ | 所属结算单 uuid(退费挂回原消费) |
| `cure_name` / `service_project_name` | string | | 被退项目名 | | `cure_name` / `service_project_name` | string | | 被退项目名 |
| `receivable_this` / `net_receipts_this` | number(元) | ✅ | 被退金额(正值) | | `receivable_this` / `net_receipts_this` | number(元) | ✅ | 被退金额(正值) |
...@@ -207,7 +207,7 @@ icon: FileJson ...@@ -207,7 +207,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 行主键 | | `id` | string | ✅ | 行主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `settlement_id` | string | ✅ | → 结算单 uuid | | `settlement_id` | string | ✅ | → 结算单 uuid |
| `modes_name` | string | ✅ | 通道名(现金支付/微信支付/刷卡支付/医保支付…原样即可) | | `modes_name` | string | ✅ | 通道名(现金支付/微信支付/刷卡支付/医保支付…原样即可) |
| `money` | number(元) | ✅ | 该通道金额(PAC 取金额最大者为主导通道) | | `money` | number(元) | ✅ | 该通道金额(PAC 取金额最大者为主导通道) |
...@@ -222,7 +222,7 @@ icon: FileJson ...@@ -222,7 +222,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 计划主键 | | `id` | string | ✅ | 计划主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | ✅ | 诊所(**行项靠头表拿诊所,缺失该行会被丢弃**) | | `organization_id` | string | ✅ | 诊所(**行项靠头表拿诊所,缺失该行会被丢弃**) |
| `customer_id` | string | ✅ | → 患者 id | | `customer_id` | string | ✅ | → 患者 id |
| `plan_group_id` / `plan_group_num` | string | | 方案分组(多方案对比) | | `plan_group_id` / `plan_group_num` | string | | 方案分组(多方案对比) |
...@@ -236,7 +236,7 @@ icon: FileJson ...@@ -236,7 +236,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 行主键 | | `id` | string | ✅ | 行主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `customer_id` | string | ✅ | → 患者 id | | `customer_id` | string | ✅ | → 患者 id |
| `treat_plan_id` | string | ✅ | → 计划头 id | | `treat_plan_id` | string | ✅ | → 计划头 id |
| `tooth_position` | string | | 牙位 | | `tooth_position` | string | | 牙位 |
...@@ -249,7 +249,7 @@ icon: FileJson ...@@ -249,7 +249,7 @@ icon: FileJson
| 字段 | 类型 | 必填 | 说明 | | 字段 | 类型 | 必填 | 说明 |
|---|---|---|---| |---|---|---|---|
| `id` | string | ✅ | 咨询主键 | | `id` | string | ✅ | 咨询主键 |
| `brand_id` | string | ✅ | 品牌 GUID | | `tenant_id` | string | ✅ | 品牌 GUID |
| `organization_id` | string | ✅ | 诊所 | | `organization_id` | string | ✅ | 诊所 |
| `customer_id` | string | ✅ | → 患者 id | | `customer_id` | string | ✅ | → 患者 id |
| `task_director_id` / `task_director` | string | | 跟进人 id / 姓名 | | `task_director_id` / `task_director` | string | | 跟进人 id / 姓名 |
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# FRIDAY SaaS 测试环境 → PAC cold-import 导出(等价"host 侧单表 dump") # FRIDAY SaaS 测试环境 → PAC cold-import 导出(等价"host 侧单表 dump")
# #
# 纪律(同 jvs-dw SQL 朴素化):每条导出 = 列选 + WHERE,零 join/零变换; # 纪律(同 jvs-dw SQL 朴素化):每条导出 = 列选 + WHERE,零 join/零变换;
# 唯一例外是 tenant_id AS brand_id 别名(避免与 PAC tenant 概念撞名,与既有 CSV 一致)。 # (2026-07 对齐:一列都不改名 —— 宿主原生字段直出;与 PAC 租户概念的区分由 PAC 适配层消化。)
# 形态改造(拆 JSON 数组/字典 join/K 码截取)全部在 PAC transforms 层做。 # 形态改造(拆 JSON 数组/字典 join/K 码截取)全部在 PAC transforms 层做。
# #
# 凭据走 env(不入 git): # 凭据走 env(不入 git):
...@@ -42,34 +42,34 @@ mysql_csv() { ...@@ -42,34 +42,34 @@ mysql_csv() {
echo "── MySQL 导出 ──" echo "── MySQL 导出 ──"
# 患者主档(全量;既有 450 行样本 → 扩全量,EMR 覆盖 ~1.65 万患者的前置) # 患者主档(全量;既有 450 行样本 → 扩全量,EMR 覆盖 ~1.65 万患者的前置)
mysql_csv "SELECT id,name,sex,birthday,file_number,tenant_id AS brand_id,organization_id,created_gmt_at,updated_gmt_at FROM customer.customer_basic_info" customer_basic_info.csv mysql_csv "SELECT id,name,sex,birthday,file_number,tenant_id,organization_id,created_gmt_at,updated_gmt_at FROM customer.customer_basic_info" customer_basic_info.csv
# 联系方式 1:N(lookup 挑默认号 → patient.phone) # 联系方式 1:N(lookup 挑默认号 → patient.phone)
mysql_csv "SELECT id,customer_id,contacts_tel,is_default,contacts_type,tel_type,relationship FROM customer.customer_contacts" customer_contacts.csv mysql_csv "SELECT id,customer_id,contacts_tel,is_default,contacts_type,tel_type,relationship FROM customer.customer_contacts" customer_contacts.csv
# 预约(全状态;transforms 丢草稿 10) # 预约(全状态;transforms 丢草稿 10)
mysql_csv "SELECT id,patient_appointment_id,organization_id,tenant_id AS brand_id,appointment_date,appointment_start,appointment_status,doctor_user_id,appointment_time_length,in_time,created_gmt_at,updated_gmt_at FROM \`arrail-appointment-server\`.appointment_base" appointment_base.csv mysql_csv "SELECT id,patient_appointment_id,organization_id,tenant_id,appointment_date,appointment_start,appointment_status,doctor_user_id,appointment_time_length,in_time,created_gmt_at,updated_gmt_at FROM \`arrail-appointment-server\`.appointment_base" appointment_base.csv
# 影像档案(挂 emr_id 病历号;modality 经 std_check_class 字典翻) # 影像档案(挂 emr_id 病历号;modality 经 std_check_class 字典翻)
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,patient_id,emr_id,class_code,file_name,file_type,file_url,files_size,shooting_time,created_gmt_at,updated_gmt_at FROM emr.med_check" med_check.csv mysql_csv "SELECT id,tenant_id,organization_id,patient_id,emr_id,class_code,file_name,file_type,file_url,files_size,shooting_time,created_gmt_at,updated_gmt_at FROM emr.med_check" med_check.csv
# 影像类型字典(class_code UUID 全局唯一,lookup 不需 tenant 限定) # 影像类型字典(class_code UUID 全局唯一,lookup 不需 tenant 限定)
mysql_csv "SELECT class_code,class_name,tenant_id AS brand_id FROM emr.std_check_class" std_check_class.csv mysql_csv "SELECT class_code,class_name,tenant_id FROM emr.std_check_class" std_check_class.csv
# 诊断字典(linkCode → std_code;K 码用,非 K 落自由文本) # 诊断字典(linkCode → std_code;K 码用,非 K 落自由文本)
mysql_csv "SELECT diag_code,diag_name,std_code FROM emr.std_diag" std_diag.csv mysql_csv "SELECT diag_code,diag_name,std_code FROM emr.std_diag" std_diag.csv
# 治疗计划(头:方案名/期望;行:牙位/术式/价格区间)→ treatment_planned # 治疗计划(头:方案名/期望;行:牙位/术式/价格区间)→ treatment_planned
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,customer_id,plan_group_id,plan_name,desired_effect,emergency_urgency,expect_cost,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan" customer_treat_plan.csv mysql_csv "SELECT id,tenant_id,organization_id,customer_id,plan_group_id,plan_name,desired_effect,emergency_urgency,expect_cost,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan" customer_treat_plan.csv
mysql_csv "SELECT id,tenant_id AS brand_id,customer_id,treat_plan_id,tooth_position,mode_name,charge_min,charge_max,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan_item" customer_treat_plan_item.csv mysql_csv "SELECT id,tenant_id,customer_id,treat_plan_id,tooth_position,mode_name,charge_min,charge_max,created_gmt_at,updated_gmt_at FROM customer.customer_treat_plan_item" customer_treat_plan_item.csv
# 结算(消费/退费)。status 语义(2026-07-18 实测):1=已结算 3=含退费行的单 4=整单反向冲减(负额+ref 挂原单)。 # 结算(消费/退费)。status 语义(2026-07-18 实测):1=已结算 3=含退费行的单 4=整单反向冲减(负额+ref 挂原单)。
# ⚠️ 2ac96f6d 品牌不用 status=4:整单冲减直接记 status=3 负金额(实测 200 行)→ 按金额正负切分: # ⚠️ 2ac96f6d 品牌不用 status=4:整单冲减直接记 status=3 负金额(实测 200 行)→ 按金额正负切分:
# 消费 = status∈{1,3} 且金额≥0;整单退费 = status=4 或 status=3 负金额(退费第三表达)。 # 消费 = status∈{1,3} 且金额≥0;整单退费 = status=4 或 status=3 负金额(退费第三表达)。
# 其余 status(0 草稿/2/5/6/7/8)语义未明,先不收 → WHERE 收窄(host 等价 dump 允许的过滤) # 其余 status(0 草稿/2/5/6/7/8)语义未明,先不收 → WHERE 收窄(host 等价 dump 允许的过滤)
mysql_csv "SELECT uuid,tenant_id AS brand_id,organization_id,patient_id,doctor_id,status,receivable_this,net_receipts_this,billing_date,registration_id,ref_settlement_id,settlement_serial_num,reason,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement WHERE status IN (1,3) AND receivable_this >= 0" patient_settlement.csv mysql_csv "SELECT uuid,tenant_id,organization_id,patient_id,doctor_id,status,receivable_this,net_receipts_this,billing_date,registration_id,ref_settlement_id,settlement_serial_num,reason,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement WHERE status IN (1,3) AND receivable_this >= 0" patient_settlement.csv
mysql_csv "SELECT uuid,tenant_id AS brand_id,organization_id,patient_id,doctor_id,status,receivable_this,net_receipts_this,billing_date,registration_id,ref_settlement_id,settlement_serial_num,reason,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement WHERE status=4 OR (status=3 AND receivable_this < 0)" patient_settlement_refund.csv mysql_csv "SELECT uuid,tenant_id,organization_id,patient_id,doctor_id,status,receivable_this,net_receipts_this,billing_date,registration_id,ref_settlement_id,settlement_serial_num,reason,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement WHERE status=4 OR (status=3 AND receivable_this < 0)" patient_settlement_refund.csv
# 退费行级明细(部分退费轨道:is_refund=1 全部归属 status=3 头单) # 退费行级明细(部分退费轨道:is_refund=1 全部归属 status=3 头单)
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,patient_id,settlement_id,cure_name,service_project_name,receivable_this,net_receipts_this,is_refund,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement_spec WHERE is_refund=1" patient_settlement_spec_refund.csv mysql_csv "SELECT id,tenant_id,organization_id,patient_id,settlement_id,cure_name,service_project_name,receivable_this,net_receipts_this,is_refund,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.patient_settlement_spec WHERE is_refund=1" patient_settlement_spec_refund.csv
# 支付通道长表(每单×通道一行;lookup 挑金额最大者为主导通道) # 支付通道长表(每单×通道一行;lookup 挑金额最大者为主导通道)
mysql_csv "SELECT id,tenant_id AS brand_id,settlement_id,modes_name,money,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.settlement_modes" settlement_modes.csv mysql_csv "SELECT id,tenant_id,settlement_id,modes_name,money,created_gmt_at,updated_gmt_at FROM \`arrail-settlement-server\`.settlement_modes" settlement_modes.csv
# 转介绍圈(患者-患者关系边,双向成对存;referee_relationship 为宿主字典 id,PAC 侧统计推断解码) # 转介绍圈(患者-患者关系边,双向成对存;referee_relationship 为宿主字典 id,PAC 侧统计推断解码)
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,customer_id,referee_patient_id,referee_relationship,type,created_gmt_at,updated_gmt_at FROM customer.customer_referee_circle" customer_referee_circle.csv mysql_csv "SELECT id,tenant_id,organization_id,customer_id,referee_patient_id,referee_relationship,type,created_gmt_at,updated_gmt_at FROM customer.customer_referee_circle" customer_referee_circle.csv
# 咨询(意向 potential_treatment/未成交原因;测试库仅 45 行,结构真实) # 咨询(意向 potential_treatment/未成交原因;测试库仅 45 行,结构真实)
mysql_csv "SELECT id,tenant_id AS brand_id,organization_id,customer_id,task_director_id,task_director,treatment_plan,preferential_way,unsettled_reason,unsettled_reason_description,other_conditions,potential_treatment,data_sources,created_gmt_at,updated_gmt_at FROM customer.customer_consult" customer_consult.csv mysql_csv "SELECT id,tenant_id,organization_id,customer_id,task_director_id,task_director,treatment_plan,preferential_way,unsettled_reason,unsettled_reason_description,other_conditions,potential_treatment,data_sources,created_gmt_at,updated_gmt_at FROM customer.customer_consult" customer_consult.csv
echo "── Mongo 导出(med_emr_info,status∈{3,4} 正式病历)──" echo "── Mongo 导出(med_emr_info,status∈{3,4} 正式病历)──"
# 不用 mongoexport:Extended JSON 会把 Date/Long 包成 {$date}/{$numberLong} 对象,破坏平铺契约。 # 不用 mongoexport:Extended JSON 会把 Date/Long 包成 {$date}/{$numberLong} 对象,破坏平铺契约。
...@@ -88,7 +88,7 @@ docker run --rm mongo:7 mongosh "$FRIDAY_MONGO_URI" --quiet --eval ' ...@@ -88,7 +88,7 @@ docker run --rm mongo:7 mongosh "$FRIDAY_MONGO_URI" --quiet --eval '
const o = { const o = {
emr_sub_id: sid(d.emrSubId), emr_id: sid(d.emrId), emr_sub_id: sid(d.emrSubId), emr_id: sid(d.emrId),
appointment_id: sid(d.appointmentId), appointment_id: sid(d.appointmentId),
brand_id: sid(d.tenantId), organization_id: sid(d.organizationId), tenant_id: sid(d.tenantId), organization_id: sid(d.organizationId),
patient_id: sid(d.patientId), user_id: sid(d.userId), user_name: flat(d.userName), patient_id: sid(d.patientId), user_id: sid(d.userId), user_name: flat(d.userName),
clinic_time: flat(d.clinicTime), visit_indicator: flat(d.visitIndicator), status: flat(d.status), clinic_time: flat(d.clinicTime), visit_indicator: flat(d.visitIndicator), status: flat(d.status),
diag: d.diag ?? [], treat: d.treat ?? [], dispose: d.dispose ?? [], examine: d.examine ?? [], diag: d.diag ?? [], treat: d.treat ?? [], dispose: d.dispose ?? [], examine: d.examine ?? [],
......
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
# ── 方案 B:合成"市场"集团 tenant;品牌降为 source_unit 命名空间 ── # ── 方案 B:合成"市场"集团 tenant;品牌降为 source_unit 命名空间 ──
# FRIDAY 是多品牌 SaaS(30+ 独立品牌 tenant_id,各含 1-8 诊所 organization_id)。 # FRIDAY 是多品牌 SaaS(30+ 独立品牌 tenant_id,各含 1-8 诊所 organization_id)。
# PAC tenant = 合成 friday-market(整个市场一个租户,便于 FRIDAY 作为运营方跨品牌召回); # PAC tenant = 合成 friday-market(整个市场一个租户,便于 FRIDAY 作为运营方跨品牌召回);
# 品牌(源 brand_id 列)→ patients.source_unit(集团内给 external_id 消歧:同号不同品牌=不同人); # 品牌(源 tenant_id 列,宿主原生名)→ patients.source_unit(集团内给 external_id 消歧:同号不同品牌=不同人);
# 诊所 organization_id → 后续 orgScope 隔离维度。 # 诊所 organization_id → 后续 orgScope 隔离维度。
# ⚠️ 隔离靠 orgScope/source_unit,非 tenant 边界 → 生产必须「禁止空 orgScope」。 # ⚠️ 隔离靠 orgScope/source_unit,非 tenant 边界 → 生产必须「禁止空 orgScope」。
# 若要品牌级硬隔离,改为 tenant_field: brand_id(每品牌一个 PAC tenant)。 # 若要品牌级硬隔离,改为 tenant_field: tenant_id + tenant_map(每品牌一个 PAC tenant)。
# #
# 跑法: # 跑法:
# pnpm sync -- --dir=./data/friday --dry-run # 看翻译效果,不写库 # pnpm sync -- --dir=./data/friday --dry-run # 看翻译效果,不写库
...@@ -22,7 +22,7 @@ display_name: FRIDAY SaaS(多品牌市场) ...@@ -22,7 +22,7 @@ display_name: FRIDAY SaaS(多品牌市场)
auto_sync: false auto_sync: false
tenant_id: friday-market # PAC 租户 = 合成市场根(静态) tenant_id: friday-market # PAC 租户 = 合成市场根(静态)
identity_namespace_field: brand_id # patients.source_unit ← 源品牌列(customer.tenant_id 导出别名) identity_namespace_field: tenant_id # patients.source_unit ← 源品牌列(宿主原生列名;与 PAC 租户概念的区分在 PAC 侧,宿主不改名)
amount_unit: yuan amount_unit: yuan
timezone: Asia/Shanghai timezone: Asia/Shanghai
...@@ -125,7 +125,7 @@ transforms: ...@@ -125,7 +125,7 @@ transforms:
parent_keys: parent_keys:
emr_sub_id: emr_sub_id emr_sub_id: emr_sub_id
emr_id: emr_id emr_id: emr_id
brand_id: brand_id tenant_id: tenant_id
organization_id: organization_id organization_id: organization_id
patient_id: patient_id patient_id: patient_id
user_id: user_id user_id: user_id
...@@ -187,7 +187,7 @@ transforms: ...@@ -187,7 +187,7 @@ transforms:
parent_keys: parent_keys:
emr_sub_id: emr_sub_id emr_sub_id: emr_sub_id
emr_id: emr_id emr_id: emr_id
brand_id: brand_id tenant_id: tenant_id
organization_id: organization_id organization_id: organization_id
patient_id: patient_id patient_id: patient_id
user_id: user_id user_id: user_id
......
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