- 27 Jun, 2026 15 commits
-
-
- org-scope:删 JVS_DW_ORG_TREE hardcode,改 buildOrgTree(从配置/数据派生); 实现对所有 host 通用,树数据 3 层本就在数据里(yaml 只为区域等数据外的层) - auth:jvsDwOrgTree() 从 MOCK_PRESETS 派生;exchangeToken + mockLogin 都走 expandOrgScope - mockLogin:数据范围统一 org-scope —— 诊所级(选客服)/品牌级(仅品牌)/集团级(orgLevel=group, sourceUnits=[] 看全部品牌全部诊所);MockLoginRequest 加 orgLevel - 前端:加"以集团身份登录"按钮(跨品牌,验证数据权限最上一层) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
数据权限 = 用户的 org 范围(任意层级:集团/品牌/诊所)。expandOrgScope() 把 org 节点展开成 sourceUnits + clinicIds(已有过滤层不变): 诊所 ref → 该诊所 + 所属品牌;品牌 ref → 该品牌 + 其下全部诊所; 集团 ref / 空 → 不限。多 ref 取并集。 - org-scope.ts:jvs-dw 内存树(ruier-grp→瑞尔/瑞泰→诊所)+ expandOrgScope - 契约 exchangeToken 接 orgScope(优先于显式 sourceUnits/clinicIds)→ 展开 - TokenExchangeUserSchema 加 orgScope 验证:诊所/品牌/集团/跨品牌四级展开均正确。通用态树放 manifest yaml。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
① source_event_id 品牌盲 → 数据丢失(HIGH):synthesizer 的幂等键 ${ctx}:${resource}:${subjectId}:${updatedAt} 不含品牌,两品牌同 subjectId+ updatedAt 撞键被去重跳过 → 丢 transaction/fact。并进 source_unit(re-import 仍幂等)。 ② persona by-id 跨品牌泄漏(HIGH):/patients/:id/persona 的 getCurrent 无 scope 过滤 (Persona 非 source_unit 模型,纵深防御只注 tenantId 不注品牌)。加经 patient 关系的 sourceUnit 过滤;controller + 2 处 MCP 调用传 scope。 ③ MCP by-id 泄漏(HIGH):MCP @Public 无 ALS 上下文,纵深防御不兜; assertPatientInScope / activeRecallPlan 只按 host+tenant,补 sourceUnit 过滤。 ④ exchangeToken 真 host SSO 丢 sourceUnits(latent):TokenExchangeUserSchema 加 source_units + exchangeToken 透传(否则真 host 登录 = 不限品牌)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>luoqi committed -
host→PAC 登录输入规范:host_id + group_id + user{id,name,role} + source_units(品牌数据范围,空=不限)+ clinic_ids;PAC 派生 permissions/ dictionary,signAccessToken 签发新契约 token。mock 与真 host 共用 signAccessToken + 同一 token 形状,差别仅输入来源。含隔离保证映射。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>luoqi committed -
- tenant-context.ts:请求级 AsyncLocalStorage(tenantId/sourceUnits) - tenant-guard.extension.ts:$extends 对 14 张 scoped 表的列表/聚合读查询自动注入 tenantId(+ source_unit 模型注品牌);findUnique 不注(破坏唯一键,by-id 走显式守卫); 无 ALS 上下文(系统任务)不注;$queryRaw 不经扩展(召回引擎自带隔离闸)。env PAC_TENANT_GUARD=warn 可切观察模式 - prisma.service:构造器 return this.$extends(...) 透明接入(services 不改) - tenant-scope.interceptor:handler 在 tenantAls.run 内执行(subscribe 包裹) 验证(已删一次性 CLI):注错 tenant→0、限品牌→该品牌数、系统任务不注、findUnique 不破。 关键:Prisma 惰性查询,await 须在 als.run 内 — interceptor 的 handler 正满足。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
ruier/ruitai 注明为**品牌(source_unit)**,同属集团租户 ruier-grp; 类型 TenantSlug→BrandSlug。功能不变(slug 经后端 MOCK_PRESETS 映射为 tenantId=ruier-grp + sourceUnit)。正式 SSO 对外契约(host_id+group_id+ org_scope)待 host 接入时实现。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
- pipeline-dispatcher:加 identityNamespaceField,patient upsert/index/patientIdResolver 全按 (source_unit,external_id) 复合键(pull/push/reconcile 多命名空间 host 也正确; 单命名空间默认 '' 不变) - reconcile 守卫:除 distinct tenant 外也查 distinct source_unit —— 合集团后 jvs-dw 只剩 1 tenant 但 2 source_unit,旧守卫拦不住会撞号;现多命名空间一律转 cold-import Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
患者详情(reveal/timeline)、plan 详情/分配/回收、plan-aggregate 详情: by-id 取数也按 patient.sourceUnit 圈品牌(findUnique→findFirst + patient 过滤, 命中不到→现有 NotFound 守卫接住)。sourceUnits 空=不限(集团级角色)。 至此 §4.4 数据范围在患者粒度的品牌隔离全覆盖(搜索/列表/by-id)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
- token/scope 加 sourceUnits(用户所属品牌;空=不限,集团级角色) - 数据范围在患者粒度按品牌圈:患者搜索 + plan 列表(patient.sourceUnit,覆盖召回池) - auth mock 预设 tenantId→ruier-grp + sourceUnit;weixin fallback→ruier-grp - mcp/timeline/weixin 手动 scope 补 sourceUnits 至此 P0 代码完整:3 表 source_unit + 摄入 + 集团 slug + 品牌隔离查询。 本地重摄已验证:external_id 261067 → 王辰(瑞尔)/王文彦(瑞泰)两条独立行, facts source_unit 全填,tenant=ruier-grp。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
- schema+migration:patient_facts (host,tenant,source_unit,subject_id,version)、 patient_return_visits (host,tenant,source_unit,external_id) - fact-writer:writeDraft/bulkWrite 的版本链 findFirst + 史表查 + liveLatest map 全按 (source_unit, subject_id) 复合键隔离;create 带 source_unit (集团内 subject_id 品牌级撞 631,不隔离会取错品牌版本=改坏 fact 历史) - parser-pipeline:按 patientId 查患者 source_unit(批内一次取),注入 PrismaService - cold-import:return_visit upsert 带 source_unit - 删旧原地迁移脚本 — 改用"清空重摄"(本地/服务器均可),无原地改 fact 版本链风险 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
实施期 pre-check:patient_facts.subject_id 跨品牌撞 631、patient_return_visits .external_id 撞 611,均品牌级,合 tenant 会撞键。故 source_unit 必须加在 patients + patient_facts + patient_return_visits 三张表;fact-writer 版本链 findFirst 也须按 source_unit 过滤。transactions(撞0)、relations(UUID)免。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
- manifest.schema: 加 identity_namespace_field - tenant-resolver: 加 buildSourceUnitResolver(从 identity_namespace_field 解析) - cold-import: source_unit 从 rawSource 解析,串入 patient upsert / stub / patientIndex(按 (source_unit,external_id) 复合键防撞号)/ patientIdResolver - manifest.yaml: 删写死 tenant_map UUID,改 tenant_id: ruier-grp(集团 slug)+ identity_namespace_field: brand - 加数据迁移脚本(未执行)
⚠ ️ 前置审发现 patient_facts.subject_id(撞631)、patient_return_visits.external_id (撞611)也是品牌级,合 tenant 会撞键 — 这俩也需 source_unit。迁移待补这两表后再跑。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>luoqi committed -
- patients.source_unit(通用命名空间,NOT NULL 默认 ''):各宿主"在哪层发患者号" 不同,jvs-dw=品牌;'' 非 null 防唯一索引 NULL-distinct 失效 - 唯一键 (host,tenant,external_id) → (host,tenant,source_unit,external_id); 存量 source_unit='' 常量,新键与旧键唯一性等价,迁移安全(95k 患者完整) - 3 处患者 upsert + 2 CLI 改新键(过渡用 sourceUnit:'';stub 与真主档同 '' 不双行) - patientReturnVisit 的 (host,tenant,external_id) 键未动(只改 patients) 下一步:source_unit 真填值(assembler sourceUnit:brand)+ tenant→集团 slug remap。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
澄清:无独立隔离策略,一切由数据范围控制;现状隔离=代码 where(tenant_id), 非 RLS/非 schema。brand 从 tenant_id 槽搬到 source_unit 槽后,品牌隔离的 where 判别列随之 tenant_id→source_unit。数据范围两粒度:plan 按诊所、 患者按品牌(source_unit),同源于 org 位置。默认本品牌(复刻现状),P1 可配置。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
核查摄入/画像/召回全链后重写计划: - 关键发现:画像&召回计算零改动(重算驱动是 distinct tenantId 循环 + per-patient,tenant=集团自动适配;召回 SQL 仅 scope 过滤) - tenant=集团用稳定 slug(ruier-grp),删 4 处写死 DW UUID - brand→source_unit(发证命名空间,进键);换槽位不合并、472撞号仍分开 - org_tree 最简一行 yaml,不建表;子表不冗余 - 改动集中:schema+摄入(4处upsert)+去写死UUID(4处)+少数隔离查询面 (患者搜索/召回池NULL-clinic/by-id guard 加 source_unit 默认过滤) - 迁移前置:审 subject_id 跨品牌不撞;一刀完成 品牌→集团+UUID→slug Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed
-
- 26 Jun, 2026 7 commits
-
-
- 新增 §7.5 权限模型:功能权限(角色,代码级,保持)/ 数据范围(应绑 org 子树, 非角色逃生门)/ 数据共享策略(集团级结构配置)三者正交,现状把前两者搅在一起 - org_units 整体推到 P2:P0/P1 用 source_unit 字符串列 + 集团级品牌共享策略即可, 不需要建树;org_units 只在多级组织/层级数据范围/rollup 时才引入 - 子表不冗余 source_unit:召回 SQL 与 plan 列表本就 join patient,过滤近乎免费 - scope 分期标注:brandSharingPolicy=P1,orgUnitSubtree=P2 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
- 患者命名空间限定符 brand → 通用 source_unit(manifest 声明源字段,brand 仅瑞尔实例) - org_units.unit_type 字符串枚举且 ≠ 层级:层级靠 parent_id 树,支持多级区域/无品牌等任意形状 - host:集团=1:N 确认,现有 schema 已支持,无需改 - 集团 ID 三来源:宿主 group_id 透传 / PAC 配 tenant_map→集团 / 必填定义;集团 UUID 新发 - 纵深防御定稿:Prisma $extends + AsyncLocalStorage,RLS 作 P2+ 硬化 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
设计稿(未动代码)。核心:tenant_id 语义 品牌→集团,brand 降为患者键 命名空间限定符 + org_units 节点,品牌共享改为可配置策略;引入 org_units 组织树。含迁移核心洞察(换槽位不加信息、472 撞号不合并)、四层影响面、 schema/摄入/认证/查询隔离/clinic 各改动点、一次性迁移步骤、P0-P3 分期、 待决策项、关键文件改动清单。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
persona 重算 16 特征是 Node 单线程 CPU 计算,实测 conc=8 不提速反略慢; 加注释解释为何保持串行(真要提速需 profile 或多进程/worker)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
关键词搜索 OR 增 medicalRecordNumber 模糊匹配;左栏 placeholder 「患者号」→「病历号」。注:externalId 非病历号,medical_record_number 才是。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
reason.leadTrigger 透传到话术/召回简报:lead=建议(无诊断)→ 病种名用 建议名(如「建议种植」),不套「缺失牙」;诊断/影像仍以诊断为准。 召回简报 prompt 增来源标注【医生建议·非确诊缺失】+ 硬规则 + 建议示例, 修复张宇晨这类"仅建议"被 LLM 说成"缺牙空了X个月"。 reason-line 前端 subLabel 同步触发感知。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
诊断 1.0 / 建议 0.8 / 影像AI 0.5 三源置信度直用为打分因子(下限0.5), 取代旧 0.75/0.9/1.0 分档;triggers 按 诊断>建议>影像 排序定 lead, reason 文案由 lead 来源驱动(建议为首不再套子场景诊断词)。 priority-hover 提示同步为「诊断1.0/建议0.8/影像0.5」。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed
-
- 25 Jun, 2026 6 commits
-
-
上一版加错位置。改到 RawJson 控制行右侧:全屏时 JSON 块 fixed inset-0 覆盖全屏、<pre> 去 max-h-80 改 flex-1 overflow-auto 撑满可滚,Esc 退出。便于看全大段原始报文 JSON。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
为什么召·证据链(T0)面板右上角加全屏切换(Maximize2/Minimize2);CSS 固定覆盖式全屏(fixed inset-0 z-50,内容区 overflow-auto 可滚),Esc 退出。便于看长 JSON 原始报文。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
10 个子场景(K00-K09)查询彼此独立,合并/去重与顺序无关。新增 PAC_RECALL_SUBSCENARIO_CONCURRENCY env(>1 开分块 Promise.all 并行,默认 1 串行、行为不变)。83K 患者本地实测:串行 50s→并行(conc=4)31s(warm 1.6×)/ cold 123s→47s(2.6×),固定 now 下两路 59032 hits 逐 hit 完全一致(等价性证实)。规则零改动,仅改执行方式。prod 建议设 =4。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
EXPLAIN 定位:selectHits 的 sig 信号扫描 + gap resolvedTeeth 各子查询都按 (patient_id,type,status) 过滤,原仅 (patient_id,status) 索引 → type 走内存 Filter,facts/患者多时 heap fetch 超线性膨胀(本地单条 K08 查询读 1.3GB 页面产 81 行)。加复合索引后所有子查询命中 Bitmap Index Scan。本地 selectHits warm 7.3s→2.0s(~3.6×),prod 13万患者收益更大。 迁移用 CREATE INDEX IF NOT EXISTS:prod 大表可先手动 CREATE INDEX CONCURRENTLY 预建免锁表,再 deploy 时本句 no-op。规则零改动、纯加速。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
新增 plan-engine-batch.spec.ts:忠实内存 mock 端到端验证批量路径 5 种结局(create/unchanged/superseded/suppressed/stale-close)+ 混合并发 + createMany 日志,与逐患者语义等价。修 plan-engine-stale-close.spec.ts 过时 mock(status:{in}匹配、加 persona.findMany/createMany)与返回形态断言(toMatchObject);assigned 0命中关闭对齐 2026-06 决策。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>luoqi committed -
夜间全 host plan 重算的 upsert 段原为逐患者串行(每人 2 读 latest/snoozed + persona + 2 日志写),13万患者 ~49min。改为:循环前一次性 bulk 预取 latest(含 reasons)/snooze 抑制集/active persona → 逐患复用同一 upsertPlan 判定(结果等价)→ 写操作分块并发(PAC_PLAN_BATCH_CONCURRENCY 默认 8)→ PlanGenerationLog 收集后 createMany(每患仍一行,口径不变)。selectHits 全表扫不在本次范围(时间规则可改,每轮须全量重选)。单刷 recomputeForPatient 不传 prefetched,行为不变。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed
-
- 24 Jun, 2026 7 commits
-
-
inputSnapshot 实际存字面输入(非 factIds/version 引用)。证据链按'依据什么+能定位问题'收口,不做按源头版本重建;回查触发 fact 走 plan_reason.evidence。纯注释,无结构变更、无需迁移。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
空态(无计划)header 缺用户信息/退出入口,补上(useAuthStore.clear())。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
牙位事实视图缺固定桥几何:修复类同象限基牙间的缺失牙=桥体,补'桥体 · 已由 X-Y 固定桥覆盖'行(teal,对齐既有非修复 note)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
deep 策略 verify 阶段把 issues[] 透传到 stream 事件;前端会话过程区展开每条问题的 段落/问题/修法。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
ReconcileOrchestrator 走单 tenant dispatcher,原写死 t_default 会把真实数据(如 jvs-dw ba67e6cf)写到错 tenant 造重复患者。改为从 host 已有数据解析 tenant:单 tenant 用之;多 tenant(瑞尔+瑞泰)直接 BadRequestException 拒绝并指向 `pnpm sync`(按 brand 派 tenant 的正确补数路径)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
原'加了多少计划'看不懂;改成进出双向统计:进=净新(version=1)+翻版(version>1),出=失效(superseded 无在跑计划)+完成(completed)。persona 重算补 status 明细(含 noop)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
独立 /admin/recall-debug 研发页:为什么召走 plan→reason→fact→transaction 溯源;为什么没召跑引擎 ground-truth + gate 漏斗。支持 ?patientId 深链、姓名搜索(重名)、版本选择、JSON 深解析、rawPayload 懒加载。SUB_SCENARIOS 改 public 供归因交叉核对。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed
-
- 22 Jun, 2026 3 commits
-
-
删 HostsAdminController(/admin/hosts 列表/改任意 host 的裸 API,无 UI 在用):host 管理只走 pnpm pac:host CLI + 自管页 /admin/host/self(按 token hostId 自动 scope,碰不到别家)→ 多 host 天然隔离、免拆权限。自管页去掉 Timezone/Amount Unit/Pull endpoints(真实配置在 manifest.yaml, DB pullConfig 这几项无人消费、会误导),保留凭据轮换/激活停用/运行状态/最近事件。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
计划治疗(treatment_record kind=planned 且未完成)拆成独立筛选 chip「治疗计划」(虚拟键 treatment_plan),sky 标签/「计划」徽标/虚线空心点,跟已做的「治疗」(slate「已完成」)区分; 已做掉的计划归回「治疗 / 已完成」(状态感知 isPlannedTreatment)。筛选 chip 选中色 = 各区块色。 治疗历史详情默认只激活「治疗」。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
新增 DailyHealthReportService:每日 09:00(Asia/Shanghai)把线上状态收口成一条简洁日报推企微 (复用 AlertService webhook,整体级别取最差→图标自动 🟢/🟡/
🔴 )。指标含近24h diff: 摄入+DW延迟、画像/召回重算、数据量(患者/事实/计划增量)、召回池待办、客服执行(按outcome)、 画像覆盖、AI用量。手动触发端点 /internal/health-report/{preview,run}(env PAC_HEALTH_REPORT_DEMO 门控)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>luoqi committed
-
- 17 Jun, 2026 2 commits
-
-
功能成型收口周:整合成一个客服工作台页面(患者列表固定/画像标签分类筛选/小助手内嵌) + 按业务验证反馈校准召回算法 + AI"说人话"打磨。沿用 W5「一页 Demo + 业务语言」结构。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed -
按反馈放开:画像标签、历史联系两处摘要的 prompt 去掉"只输出一句话/≤30-40字"等约束, schema 去掉 .max(80) 与字数说明(保留 .min(4) 防空)。只留"重点提炼不罗列 + 不无中生有"取向。 promptVersion bump 到 -d,旧缓存已清,重生成不再被掐短。召回简报不动。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
luoqi committed
-