Commit 15d08d44 by luoqi

docs: archive operational records and architecture discussions

parent c1e09831
Pipeline #3861 failed in 0 seconds
...@@ -22,6 +22,8 @@ PAC 客户召回与 FridayAI 的正式产品、原理和接口文档统一维护 ...@@ -22,6 +22,8 @@ PAC 客户召回与 FridayAI 的正式产品、原理和接口文档统一维护
临时规划、旧流程、环境快照、验收报告和重复销售稿移入 [_archive/](_archive/README.md),保留原文件名、引用与移动清单。 临时规划、旧流程、环境快照、验收报告和重复销售稿移入 [_archive/](_archive/README.md),保留原文件名、引用与移动清单。
2026 年 10 月新增归档:[美亚与患者事实开发记录](_archive/2026-10-meyer-and-patient-facts/README.md)、[运维验收与架构讨论](_archive/2026-10-operations-and-design/README.md)。
设计准则、行为埋点和架构决策已全部归档至 [_archive/design/](_archive/design/) 与 [_archive/adr/](_archive/adr/)。 设计准则、行为埋点和架构决策已全部归档至 [_archive/design/](_archive/design/) 与 [_archive/adr/](_archive/adr/)。
Claude Code 的编号资料见 [FridayAI 开发档案](_archive/friday-ai/docs/README.md)。未结事项见[跟进清单](qa/follow-ups.md),归档不表示解决。环境现状需要重新查询;当前行为以代码和正式文档为准。 Claude Code 的编号资料见 [FridayAI 开发档案](_archive/friday-ai/docs/README.md)。未结事项见[跟进清单](qa/follow-ups.md),归档不表示解决。环境现状需要重新查询;当前行为以代码和正式文档为准。
# Push 关键路径优化与排障(本地) # Push 关键路径优化与排障(本地)
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
分支 `codex/push-latency-fix`,基于 main `99fb2648cacdafcd0f26ec8540d04c8465ecbb87`。独立 worktree,主目录及正在运行的本地服务未变。已提交并部署测试;生产未改动。 分支 `codex/push-latency-fix`,基于 main `99fb2648cacdafcd0f26ec8540d04c8465ecbb87`。独立 worktree,主目录及正在运行的本地服务未变。已提交并部署测试;生产未改动。
## 最终边界 ## 最终边界
...@@ -60,3 +62,23 @@ ...@@ -60,3 +62,23 @@
- 历史字段审计在后台完成 20ms,不阻塞响应。同期主档请求 195ms。健康 JSON status=ok。 - 历史字段审计在后台完成 20ms,不阻塞响应。同期主档请求 195ms。健康 JSON status=ok。
- 本条真实预约没有慢环节,确认业务落库后毫秒级返回;它不能证明此前分钟级超时的具体根因,也不是宿主建预约到消费响应的端到端计时。 - 本条真实预约没有慢环节,确认业务落库后毫秒级返回;它不能证明此前分钟级超时的具体根因,也不是宿主建预约到消费响应的端到端计时。
- 已获得真实预约样本,暂停本轮定时跟踪。生产未修改。 - 已获得真实预约样本,暂停本轮定时跟踪。生产未修改。
## 生产发布准备(2026-10-14)
- 用户验收测试并授权合 main、部署生产;检查发现 4 个召回主查询及其并行进程运行中,用户进一步明确允许中断本轮后部署。
- main 快进到 `584bd3dd34c2ed20f313d31c476b7f14220f4a88`;相比测试的业务代码相同,增加测试验收记录。没有将 test 的其他提交合入 main。
- 生产原版本 `99fb264`,可用内存约 11GiB、/data 可用134GiB,旧服务健康。队列为空但召回SQL活跃,不能据队列断言空闲。
- 有一条13:03:41开始的病历 push 仍标 running,早于原容器13:03:42启动;未将其状态改成功/失败。
- 回退目录 `/data/backups/pac-release/584bd3d-20261014`:原源码SHA、PAC旧镜像及回退标签、私密配置副本、Compose校验值、迁移元数据、AI/ingress原镜像和启动时间、构建/部署日志与退出标记。配置/镜像备份不是业务数据备份。
- 生产镜像构建退出0。使用 COMPOSE_MANAGED=1、固定SHA、标准发布脚本 --no-pull,只发布PAC;本次唯一数据库变更为并发索引,不重放数据。
## 生产发布验收
- 发布时间北京时间 19:02:51—19:10:29,固定 main@584bd3d,标准部署脚本退出0。
- 并发索引扫描/校验完成后等待旧快照;按用户本轮明确授权,仅取消了4条已核对SQL形态的旧召回主查询(1540/1556/1621/1554),随后迁移成功。没有取消其他查询或手工标记业务任务成功。
- 索引迁移19:10:12完成,ready/valid均true,索引350MB;Prisma无pending。
- 实际运行镜像与构建产物一致:PAC service `271291ef75ee`,web `b88c9fbdf169`,docs `2fb22de20fd0`。
- 公网 https://pac.friday.tech/health 返回JSON status=ok;公网/plans为200;loopback及私网health/web通过;docs `/docs/integration/channel-push` 本机和私网200。
- service/web env逐字未变,Compose校验值一致;FridayAI service/web及ingress镜像和启动时间均与发布前一致。
- 首次验收期间生产Friday尚无新push,未声称生产真实推送性能已验证;测试真实预约167ms的结果见上节。
- 主目录原有未跟踪AGENTS.md/output保持原样,本地服务未操作。
# 测试回访推送修复验收
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
- 功能提交:dca8663;test 合并并部署:a627d29cbf75321c88f2a58b89ea174119ac62ff。
- 仅测试环境;未合入 main、未部署生产。主目录已有文件未改。
- 根因:回访/患者关系仍加载整个租户患者索引,138772 条查询结果通过 push(...rows) 展开触发 Maximum call stack size exceeded。
- 修复:两条链路按本批引用患者、tenant、sourceUnit 查询(关系包含本人和关系人),每块1000个ID;逐条合并结果,索引查询禁止省略引用范围。
- 同类检查:摄入模块其余查询展开为固定50条;CLI患者查询已有20000条分块;未发现另一处相同的无界租户查询展开。
- 本地:5 suites / 46 tests 通过;service 两组 type-check 通过。新工作区先构建 types/utils/host-connector 和 Prisma client。
- 部署退出0,迁移无pending,运行镜像校验通过,/health JSON status=ok。
- 回退资料:测试机 /root/pac-ops/return-visit-fix-20261014,旧service/web镜像已打回退标签。
## 单条原文重放
- 原失败 syncLog:5e6bcd20-2edc-4847-8d31-f54f348ef829。
- 原证据:afc4d32c-721c-4493-9443-6c494f272a30。
- 原文保持不变,经 HMAC 签名调用正常 /pac/v1/push/rows;严格限定 Friday、customer_return_visit、1条、回访267076、患者700687。
- 成功 syncLog:2edf876a-adad-419f-83cf-534107223b07。
- HTTP200 / code0 / hasFailures=false / failed=0 / factsFailed=0 / stubs=0。
- 请求396ms;lookup-transform9ms、upsert34ms、touched8ms。
- 该回访已落 patient_return_visits:患者与祥云小镇诊所匹配,已回访,执行人5992。
- 直接调用部署版本 AgentRosterService 验证:5992在该诊所名册,recentVisits=1,inRoster=true。
- 回访为独立资源,正常 transactionsWritten=0、personaEnqueued=0;未修改事实或重算召回。
- 未重放其他回访,未读写5i5ya业务数据。
## 生产发布(用户测试确认后授权)
- main 合并版本:fa09e5ff75aa4e9414e679166b492ad98a533375。
- 一并发布 main 原有未部署改动:FridayAI侧栏导航保持会话和诊所状态(a33528b,合并efc2f64)。该修复专项9项测试及ai-web类型检查通过。
- 发布前:同步日志无running,5个业务队列active/waiting/delayed均0;召回筛选查询pid12383/12411/12412已运行约33分钟,用户明确允许中断本轮后发布。
- PAC和FridayAI串行发布均exit0,运行镜像校验通过,无待执行迁移;PAC /health、AI /health/ready、私网页面与AI到PAC连通性通过。
- 发布后旧召回查询已不在pg_stat_activity;本轮未手动重算召回。
- 截至2026-10-14 23:25(上海)未看到发布后新push,不能将测试重放结果当作生产真实回访验收;已确认生产编译代码包含scopedPatientIndexLoader。
- 检查启动后日志未见ERROR/栈溢出;未向生产重放测试回访。
- 回退目录:/data/backups/pac-release/return-visit-20261014(旧镜像标签、环境配置、compose、发布日志和退出码)。
- main主目录未提交文件及本地服务未修改;QA记录保留在隔离工作区,尚未提交。
<!doctype html>
<html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><meta name="description" content="美亚、FridaySaaS 与 PAC 的影像及分析数据方案,供内部评审。"><title>影像与分析数据方案设计 · 美亚 × FridaySaaS × PAC</title><style>
:root{color-scheme:light;--ground:#f4f6fb;--surface:#fff;--sunken:#eaeef6;--ink:#0f1b33;--ink-2:#44506a;--ink-3:#6f7a91;--brand:#0032a0;--brand-soft:#e3eafa;--rule:#dde3ee;--note:#f5f7fc;--warn-bg:#fff9ed;--warn-rule:#d6ae63;--serif:"Noto Serif SC","Songti SC","STSong",serif;--sans:"Noto Sans SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;--mono:"IBM Plex Mono",ui-monospace,"SFMono-Regular",Menlo,monospace}
:root[data-theme=dark]{color-scheme:dark;--ground:#0a1020;--surface:#121a2d;--sunken:#1a2440;--ink:#e7ecf6;--ink-2:#b3bdd2;--ink-3:#8994ab;--brand:#86a7ff;--brand-soft:#1d2b52;--rule:#2a3550;--note:#172037;--warn-bg:#292518;--warn-rule:#a38a55}
@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--ground:#0a1020;--surface:#121a2d;--sunken:#1a2440;--ink:#e7ecf6;--ink-2:#b3bdd2;--ink-3:#8994ab;--brand:#86a7ff;--brand-soft:#1d2b52;--rule:#2a3550;--note:#172037;--warn-bg:#292518;--warn-rule:#a38a55}}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:16px;line-height:1.9;-webkit-font-smoothing:antialiased}::selection{background:var(--brand-soft);color:var(--ink)}a{color:var(--brand);text-decoration-color:color-mix(in srgb,var(--brand) 35%,transparent);text-underline-offset:4px}a:hover{text-decoration-color:var(--brand)}button{font:inherit}a:focus-visible,button:focus-visible{outline:2px solid var(--brand);outline-offset:4px}
.wrap{max-width:1040px;margin:auto;padding:40px 26px 48px}.document-header{padding:0 8px 28px}.topline{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:16px}.eyebrow{font-size:12px;letter-spacing:.10em;color:var(--brand);font-weight:700}.tools{display:flex;gap:4px}.tools button{border:0;color:var(--ink-3);background:transparent;padding:5px 8px;cursor:pointer;font-size:12px;border-radius:5px;display:flex;align-items:center;gap:5px}.tools button:hover{background:var(--brand-soft);color:var(--brand)}.tools svg{width:15px;height:15px}h1{font-family:var(--serif);font-weight:700;font-size:clamp(30px,3.8vw,42px);line-height:1.35;letter-spacing:.015em;margin:0 0 14px}.meta{display:flex;align-items:center;flex-wrap:wrap;gap:9px;color:var(--ink-3);font-size:12px;margin-bottom:14px}.meta .version{background:var(--brand-soft);color:var(--brand);border-radius:99px;padding:1px 10px;font-weight:500}.meta time{font-family:var(--mono);font-size:12px}.scope{max-width:48em;color:var(--ink-2);font-size:14px;line-height:1.8;margin:0}
main{background:var(--surface);border-radius:14px;padding:42px 58px 40px}p{margin:0 0 18px;color:var(--ink-2)}strong{color:var(--ink);font-weight:600}p:last-child{margin-bottom:0}.boundary{padding:0 0 0 20px;border-left:3px solid var(--brand);font-size:18px;line-height:1.85;margin-bottom:24px}.boundary strong{font-weight:600}.principle{font-size:15.5px;line-height:1.9;margin-bottom:30px}.contents{border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:17px 0 19px;margin:32px 0 0}.contents-label{color:var(--ink-3);font-size:11px;letter-spacing:.14em;display:block;margin-bottom:9px}.contents-links{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px 18px}.contents a{text-decoration:none;color:var(--ink-2);font-size:13px;white-space:nowrap}.contents a:hover{color:var(--brand)}.contents a span{font-family:var(--mono);display:inline-block;width:29px;color:var(--brand);font-size:11px}
.chapter{padding-top:46px;scroll-margin-top:28px}.chapter+.chapter{margin-top:42px;border-top:1px solid var(--rule)}.chapter-head{display:flex;align-items:baseline;gap:15px;margin-bottom:24px}.chapter-num{color:var(--brand);font-family:var(--mono);font-size:15px;line-height:1.3;flex:none}.chapter h2{font-family:var(--serif);font-size:26px;line-height:1.45;font-weight:700;margin:0;text-wrap:pretty}.chapter h3{font-size:18px;line-height:1.6;color:var(--ink);margin:32px 0 14px;font-weight:600}.chapter-head+h3{margin-top:0}.step-heading{display:flex;gap:8px}.step-heading span{color:var(--brand);font-weight:500}.figure-intro{font-size:14px;margin-bottom:12px}ul,ol{padding-left:23px;color:var(--ink-2);margin:14px 0 22px}li{padding-left:3px;margin:7px 0}li::marker{color:var(--brand)}blockquote{margin:24px 0;padding:20px 24px;background:var(--brand-soft);border-left:3px solid var(--brand)}blockquote p{color:var(--ink);font-family:var(--serif);font-size:20px;line-height:1.75;font-weight:600}.consequence{border-left:3px solid var(--warn-rule);background:var(--warn-bg);padding:17px 21px;margin:22px 0}.consequence strong{font-weight:500}.own-business{border-top:1px dashed var(--rule);padding-top:20px;margin-top:24px}.future{margin:28px 0 0;padding:18px 23px;background:var(--note);font-size:14px;border-left:2px solid var(--rule)}.future p{margin-bottom:8px}.future ul{margin:7px 0 0}.future li{margin:4px 0}.duties{list-style:none;padding:0;counter-reset:duty;margin:20px 0 24px}.duties li{counter-increment:duty;position:relative;padding:15px 0 15px 42px;margin:0;border-top:1px solid var(--rule)}.duties li:last-child{border-bottom:1px solid var(--rule)}.duties li::before{content:'0' counter(duty);position:absolute;left:0;color:var(--brand);font:14px var(--mono);top:21px}.questions{padding-left:23px}.questions li{margin:12px 0}.questions strong{color:var(--brand)}
.table-wrap{margin:22px 0 26px}table{width:100%;border-collapse:collapse;font-size:14px;line-height:1.8;text-align:left}th{font-weight:600;color:var(--ink);background:var(--sunken);padding:12px 16px;border-bottom:1px solid var(--rule);vertical-align:top}td{padding:13px 16px;border-bottom:1px solid var(--rule);vertical-align:top;color:var(--ink-2)}tbody td:first-child{font-weight:500;color:var(--ink)}.two-col td:first-child{width:37%}.three-col th:nth-child(1){width:33%}.three-col th:nth-child(2){width:28%}.three-col th:nth-child(3){width:39%}#review td:first-child{width:22%;color:var(--brand);font-weight:600}
figure{margin:0}.flow{padding:20px 24px 22px;border:1px solid var(--rule);border-radius:9px;margin:14px 0 22px;background:var(--note)}figcaption{font-size:13px;font-weight:600;color:var(--ink);display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding-bottom:18px}figcaption>span{font-size:11px;font-family:var(--mono);color:var(--brand);font-weight:400}figcaption>small{font-size:11px;font-weight:400;color:var(--ink-3);margin-left:auto}.flow-grid{display:grid;grid-template-columns:minmax(0,1fr) 104px minmax(0,1.1fr) 65px minmax(0,1fr);grid-template-rows:auto auto auto;align-items:center}.capture{grid-column:1;grid-row:1;text-align:center;font-size:11px;color:var(--ink-3);line-height:1.7;align-self:end;padding:0 0 7px}.capture>span{display:block;color:var(--ink-3);font-size:20px;line-height:1.3}.system{grid-row:2;background:var(--surface);border:1px solid var(--rule);border-top:2px solid var(--brand);padding:16px 8px;text-align:center;align-self:stretch;display:flex;flex-direction:column;justify-content:center;min-width:0}.meyer{grid-column:1}.saas{grid-column:3;background:var(--brand-soft)}.pac{grid-column:5}.system-label{color:var(--ink-3);font-size:10px;letter-spacing:.10em;line-height:1.5;margin-bottom:6px}.system>strong{font-size:18px;line-height:1.5;font-weight:600;white-space:nowrap}.system>small{font-size:11px;color:var(--ink-2);margin-top:6px;line-height:1.7}.connector{grid-row:2;text-align:center;color:var(--brand);display:flex;flex-direction:column;align-items:center;gap:8px;padding:0 5px}.connector.first{grid-column:2}.connector.second{grid-column:4}.connector>span{font-size:11px;line-height:1.6}.connector svg{width:38px;height:12px;flex:none}.connector small{font-size:10px;color:var(--ink-3);line-height:1.5}.storage{grid-column:1;grid-row:3;text-align:center;color:var(--ink-3);font-size:13px}.storage>span{display:block;line-height:1.4;font-size:20px}.storage>div{border:1px dashed var(--rule);background:var(--surface);padding:4px 10px}.storage small{font-size:11px;margin-left:5px}.mobile-only{display:none}.view-path{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:19px 20px;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);margin:18px 0;color:var(--ink);font-size:14px;font-weight:500}.view-path b{color:var(--brand);font-size:18px;font-weight:400;line-height:1}
.sources{margin-top:44px;padding-top:25px;border-top:1px solid var(--rule);scroll-margin-top:28px;font-size:12.5px;color:var(--ink-3);line-height:1.85}.sources h2{font-size:14px;font-weight:600;margin:0 0 12px}.sources p{color:var(--ink-3);margin-bottom:13px}.sources ul{padding-left:19px;margin:14px 0 17px}.sources li{padding-left:1px;margin:8px 0;color:var(--ink-3)}.sources a{font-weight:500}.page-footer{display:flex;justify-content:space-between;gap:12px;color:var(--ink-3);font-size:11px;padding:19px 8px 0}.page-footer a{text-decoration:none;color:var(--ink-3)}.back-top{position:fixed;right:24px;bottom:22px;z-index:10;border:1px solid var(--rule);border-radius:99px;padding:8px 14px;background:var(--surface);color:var(--brand);font-size:12px;text-decoration:none;box-shadow:0 2px 16px #00000006;opacity:0;pointer-events:none;transition:opacity .2s}.back-top.visible{opacity:1;pointer-events:auto}.skip-link{position:absolute;top:-80px;left:20px;background:var(--surface);padding:10px;z-index:20}.skip-link:focus{top:10px}
@media(min-width:1440px){.wrap{padding-top:48px}}
@media(max-width:900px){.wrap{padding:26px 22px 32px}main{padding:34px 35px}.chapter h2{font-size:24px}.flow{padding:18px 16px}.flow-grid{grid-template-columns:minmax(0,1fr) 90px minmax(0,1.1fr) 56px minmax(0,1fr)}.system>strong{font-size:16px}.system>small{font-size:9px}.system-label{font-size:9px}.connector>span{font-size:9px}.connector small{font-size:8px}}
@media(max-width:660px){body{font-size:15px;line-height:1.85}.wrap{padding:22px 15px 28px}.document-header{padding:0 4px 23px}.topline{align-items:flex-start;gap:8px;margin-bottom:13px}.eyebrow{font-size:10px;letter-spacing:.04em;padding-top:7px}.tools{gap:0;flex:none}.tools button{padding:7px}.tools button span{display:none}.tools svg{width:16px;height:16px}h1 span{display:block}h1{font-size:31px;line-height:1.4;max-width:11em;text-wrap:balance;margin-bottom:13px}.meta{font-size:11px;margin-bottom:12px}.meta time{font-size:11px}.scope{font-size:13px;line-height:1.8}main{padding:27px 22px 29px;border-radius:10px}.boundary{font-size:17px;line-height:1.85;padding-left:15px;margin-bottom:21px}.principle{font-size:14px}.contents{margin-top:25px;padding:15px 0 17px}.contents-links{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px 12px}.contents a{font-size:12px}.contents a span{width:25px}.chapter{padding-top:32px;scroll-margin-top:18px}.chapter+.chapter{margin-top:30px}.chapter-head{gap:10px;margin-bottom:21px}.chapter-num{font-size:12px}.chapter h2{font-size:22px;line-height:1.5}.chapter h3{font-size:16px;margin-top:28px}.chapter-head+h3{margin-top:0}.consequence{padding:14px 16px}.chapter blockquote{padding:16px 18px;margin:22px 0}.chapter blockquote p{font-size:18px;line-height:1.8}.table-wrap{margin:22px 0}.table-wrap thead{display:none}.table-wrap table,.table-wrap tbody{display:block}.table-wrap tr{display:block;padding:13px 0;border-bottom:1px solid var(--rule)}.table-wrap tr:first-child{border-top:2px solid var(--brand)}.table-wrap td{display:block;padding:3px 0;border:0;width:auto!important;line-height:1.85;font-size:13px}.table-wrap td:first-child{font-size:14px;font-weight:600;padding:0 0 6px;color:var(--ink)}.three-col td:not(:first-child){display:grid;grid-template-columns:6.4em 1fr;gap:10px}.three-col td:not(:first-child)::before{content:attr(data-label);font-size:11px;color:var(--ink-3);padding-top:2px}#review td:first-child{color:var(--brand)}.flow{padding:16px;margin:13px 0 20px}figcaption{font-size:12px;gap:8px;padding-bottom:18px}figcaption>small{display:block;flex-basis:100%;font-size:10px;margin:0}.flow-grid{display:flex;flex-direction:column;gap:0}.capture{font-size:11px;align-self:center;padding-bottom:4px}.system{align-self:stretch;padding:14px;min-height:95px}.system>strong{font-size:19px}.system>small{font-size:11px}.system-label{font-size:10px;margin-bottom:3px}.connector{padding:10px 0;gap:4px}.connector svg{transform:rotate(90deg);width:28px;height:12px;margin:6px 0}.connector>span{font-size:11px}.connector>span br{display:none}.connector small{font-size:10px}.storage{margin-top:16px;align-self:stretch;font-size:12px}.storage>span{display:none}.storage>div{padding:7px 5px;background:transparent}.storage small{font-size:11px}.mobile-only{display:inline;font-weight:400}.view-path{flex-direction:column;gap:7px;padding:16px;font-size:13px;align-items:flex-start}.view-path b{transform:rotate(90deg);margin-left:7px;font-size:17px;line-height:1.1}.duties li{padding-left:33px}.duties li::before{font-size:12px;top:20px}.future{font-size:13px;padding:15px 17px}.sources{margin-top:32px;font-size:11.5px}.sources h2{font-size:13px}.page-footer{font-size:10px;flex-direction:column;gap:3px;padding:15px 4px 0}.back-top{right:12px;bottom:12px;font-size:11px;padding:6px 11px}}
@media(max-width:350px){.wrap{padding-inline:10px}main{padding-inline:17px}h1{font-size:29px}.eyebrow{font-size:9px}.boundary{font-size:16px}.chapter h2{font-size:20px}.flow{padding-inline:12px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition:none!important}}
@page{size:A4;margin:16mm 17mm 17mm}
@media print{html{scroll-behavior:auto}:root,:root[data-theme=dark]{color-scheme:light;--ground:#fff;--surface:#fff;--sunken:#edf0f6;--ink:#0f1b33;--ink-2:#33415a;--ink-3:#69758a;--brand:#0032a0;--brand-soft:#edf1fa;--rule:#d5dce9;--note:#f8f9fc;--warn-bg:#fffaf0;--warn-rule:#c1a26b}body{background:white;font-size:10pt;line-height:1.75;-webkit-print-color-adjust:exact;print-color-adjust:exact}.wrap{padding:0;max-width:none}.document-header{padding:0 0 17pt}.topline{margin-bottom:9pt}.eyebrow{font-size:8pt}h1{font-size:25pt;margin-bottom:8pt}.meta{margin-bottom:7pt;font-size:8pt}.meta time{font-size:8pt}.scope{font-size:9pt}.tools,.back-top,.skip-link{display:none!important}main{padding:0;border-radius:0}.boundary{font-size:11.5pt;margin-bottom:13pt;padding-left:12pt}.principle{font-size:9.5pt;margin-bottom:17pt}.contents{margin-top:17pt;padding:10pt 0}.contents-links{grid-template-columns:repeat(3,1fr);gap:4pt 10pt}.contents a{font-size:8pt}.contents-label{font-size:7pt;margin-bottom:5pt}.chapter{padding-top:24pt}.chapter+.chapter{margin-top:23pt}.chapter-head{gap:10pt;margin-bottom:13pt;break-after:avoid}.chapter h2{font-size:17pt;line-height:1.45}.chapter-num{font-size:10pt}.chapter h3{font-size:11.5pt;margin:19pt 0 9pt;break-after:avoid}.chapter-head+h3{margin-top:0}p{margin-bottom:10pt;orphans:3;widows:3}li{margin:4pt 0}ul,ol{margin:9pt 0 13pt}blockquote{margin:13pt 0;padding:12pt 16pt;break-inside:avoid}blockquote p{font-size:12pt}.consequence{padding:10pt 14pt;margin:12pt 0;break-inside:avoid}.figure-intro{font-size:9pt;break-after:avoid;margin-bottom:7pt}.flow{margin:8pt 0 13pt;padding:12pt 14pt;break-inside:avoid}.flow-grid{grid-template-columns:minmax(0,1fr) 85px minmax(0,1.1fr) 55px minmax(0,1fr)}figcaption{font-size:8pt;padding-bottom:12pt}figcaption>span{font-size:7pt}figcaption>small{font-size:7pt}.capture{font-size:7pt}.system{padding:10pt 5pt}.system-label{font-size:6.5pt}.system>strong{font-size:12pt}.system>small{font-size:6.5pt}.connector>span{font-size:6.5pt}.connector small{font-size:5.5pt}.storage{font-size:8pt}.storage small{font-size:7pt}.view-path{font-size:8.5pt;padding:12pt 10pt;break-inside:avoid;margin:11pt 0}.table-wrap{margin:13pt 0 16pt;break-inside:avoid}table{font-size:8.5pt;line-height:1.65}th{padding:8pt 10pt}td{padding:8pt 10pt}tr{break-inside:avoid}.duties{break-inside:avoid}.duties li{padding:9pt 0 9pt 29pt}.duties li::before{font-size:9pt;top:13pt}.future{font-size:8.5pt;break-inside:avoid;padding:12pt 15pt;margin-top:17pt}.own-business{padding-top:12pt;margin-top:15pt}.sources{font-size:8pt;line-height:1.75;margin-top:25pt;padding-top:17pt}.sources h2{font-size:9.5pt;break-after:avoid}.sources li{margin:6pt 0}.sources p{margin-bottom:9pt}.page-footer{font-size:7pt;padding-top:15pt}a{color:inherit;text-decoration:none}.sources a{text-decoration:underline;text-decoration-color:#b9c3d8}.questions{break-inside:avoid;break-after:avoid}.review-conclusion{break-before:avoid}.table-wrap:has(+p){break-after:auto}.keep-next{break-after:avoid}}
</style></head>
<body>
<aside role="note" style="padding:12px 20px;background:#fff4da;color:#594100;border-bottom:1px solid #e9cf8d;font:14px/1.7 sans-serif">历史评审稿,2026-10-22 归档。事件推送方案未被采用;现行实现按诊所分页轮询并批量查询分析。<a href="../../../apps/pac-service/src/integrations/meyer/README.md">查看当前采集说明</a></aside><a class="skip-link" href="#main">跳到正文</a><div class="wrap" id="top">
<header class="document-header"><div class="topline"><div class="eyebrow">美亚 × FridaySaaS × PAC</div><div class="tools" aria-label="文档工具"><button type="button" id="theme-button" aria-label="切换深浅色" aria-pressed="false" title="切换深浅色"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 4a8 8 0 0 1 0 16Z" fill="currentColor" stroke="none"/></svg><span>深浅色</span></button><button type="button" id="print-button" aria-label="打印或另存为 PDF" title="打印或另存为 PDF"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 9V3h12v6M6 18H3v-8h18v8h-3M6 14h12v7H6Z"/></svg><span>打印</span></button></div></div><h1><span>影像与分析数据</span><span>方案设计</span></h1><div class="meta"><span class="version">内部评审稿</span><span>v0.2</span><span aria-hidden="true">·</span><time datetime="2026-10-16">2026-10-16</time></div><p class="scope">本轮先确认设计方向与系统边界;字段、表结构、调度周期和开发任务在方案采纳后细化。</p></header>
<main id="main"><div class="opening"><p class="boundary"><strong>建议边界:美亚管理影像资产,FridaySaaS 管理业务归属并负责对外同步,PAC 消费宿主提供的事实。PAC 核心不直接接美亚。</strong></p>
<p class="principle">判断依据是:<strong>三个系统可以保存和使用同一份患者与影像关系,但应明确各自数据的权威来源,并让关联及其变更沿统一链路传递。</strong> FridaySaaS 提供业务患者身份,美亚维护影像资产及其患者映射;SaaS 将两者对应关系校验、留存后提供给 PAC,PAC 据此形成事实和诊断信号。</p></div><nav class="contents" id="contents" aria-label="文档目录"><span class="contents-label">目录</span><div class="contents-links"><a href="#relationship"><span>01</span>整体关系</a><a href="#meyer"><span>02</span>美亚</a><a href="#saas"><span>03</span>FridaySaaS</a><a href="#pac"><span>04</span>PAC</a><a href="#review"><span>05</span>评审与确认</a><a href="#sources"><span>附</span>资料依据</a></div></nav>
<section class="chapter" id="relationship" aria-labelledby="heading-1"><div class="chapter-head"><span class="chapter-num">01</span><h2 id="heading-1">整体关系:数据供给与查看原片分开</h2></div><h3 class="step-heading"><span>①</span>关联基础:先明确影像属于谁</h3>
<p>FridaySaaS 向美亚同步患者、诊所和就诊信息,美亚据此关联影像;SaaS 校验并留存对应关系,再向 PAC 提供。</p>
<h3 class="step-heading"><span>②</span>数据供给:同步影像信息与分析结果</h3>
<p class="figure-intro">以下以启用美亚新影像为例,表示目标链路:</p>
<figure class="flow" aria-labelledby="flow-caption">
<figcaption id="flow-caption"><span>图 01</span>影像与分析的数据供给<small>目标链路 · 新影像启用时</small></figcaption>
<div class="flow-grid">
<div class="capture">诊所设备与前置机<span aria-hidden="true">↓</span></div>
<div class="system meyer"><span class="system-label">影像资产</span><strong>美亚 PACS</strong><small>采集接入 · 影像与分析</small></div>
<div class="connector first"><span>影像信息<br>分析结果及变更</span><svg viewBox="0 0 40 12" fill="none" aria-hidden="true"><path d="M1 6h36m-5-4 5 4-5 4" stroke="currentColor" stroke-width="1.3"></path></svg><small>获取方式待确认</small></div>
<div class="system saas"><span class="system-label">业务归属</span><strong>FridaySaaS</strong><small>校验归属 · 留存 · 同步</small></div>
<div class="connector second"><span>宿主事实</span><svg viewBox="0 0 40 12" fill="none" aria-hidden="true"><path d="M1 6h36m-5-4 5 4-5 4" stroke="currentColor" stroke-width="1.3"></path></svg></div>
<div class="system pac"><span class="system-label">信号应用</span><strong>PAC</strong><small>诊断信号 · 画像与召回</small></div>
<div class="storage"><span aria-hidden="true">↓</span><div><b class="mobile-only">美亚 → </b>OSS <small>原片存储</small></div></div>
</div>
</figure>
<p>原片由美亚管理,SaaS 向 PAC 提供影像业务信息与分析结果。美亚到 SaaS 如何获取变更,仍需确认。</p>
<p>新老影像功能可以保留,实际使用时择一启用;选用旧影像时,也由 SaaS 统一向 PAC 提供数据。</p>
<h3 class="step-heading"><span>③</span>查看原片:用户按需打开宿主入口</h3>
<div class="view-path" role="group" aria-label="查看原片路径"><span>PAC 宿主槽位</span><b aria-hidden="true">→</b><span>FridaySaaS 影像页面</span><b aria-hidden="true">→</b><span>当前选用的影像系统</span></div>
<p>SaaS 负责权限和入口;启用新影像时,由美亚提供阅片服务。<strong>数据同步持续进行,查看原片由用户按需发起。</strong></p>
</section>
<section class="chapter" id="meyer" aria-labelledby="heading-2"><div class="chapter-head"><span class="chapter-num">02</span><h2 id="heading-2">美亚:最重要的承诺是“变化可获取”</h2></div><p>美亚负责采集接入、原片存储、影像关联、阅片,以及其提供的分析。对外不仅要能查询当前数据,还要让 SaaS 知道数据发生了什么变化。</p>
<p class="consequence"><strong>如果只能查新影像列表,SaaS 可以知道“多了一张片”,却未必知道这张片后来分析完成、被改绑到另一位患者,或被撤销。下游就可能继续使用过期甚至归属错误的依据。</strong></p>
<p>因此,对美亚真正要提的要求是:</p>
<blockquote>
<p>提供可追溯、可补拉的影像及分析变更机制,包含新增、修改、撤销和归属变化。</p>
</blockquote>
<div class="table-wrap"><table class="three-col">
<thead>
<tr>
<th scope="col">美亚提供的能力</th>
<th scope="col">FridaySaaS 如何获取</th>
<th scope="col">意味着什么</th>
</tr>
</thead>
<tbody><tr>
<td data-label="美亚提供的能力">有事件通知,并能补查变更</td>
<td data-label="FridaySaaS 如何获取">通知后同步,遗漏时补拉</td>
<td data-label="意味着什么">及时性较好,也能恢复遗漏</td>
</tr>
<tr>
<td data-label="美亚提供的能力">没有通知,有完整变更查询</td>
<td data-label="FridaySaaS 如何获取">定时拉取</td>
<td data-label="意味着什么">可以可靠同步,延迟取决于拉取周期</td>
</tr>
<tr>
<td data-label="美亚提供的能力">只有入库时间列表、逐张查询</td>
<td data-label="FridaySaaS 如何获取">定时发现新片,反复查询分析</td>
<td data-label="意味着什么">能做部分同步,但后续修订、改绑、撤销的完整性没有保障</td>
</tr>
</tbody></table></div>
</section>
<section class="chapter" id="saas" aria-labelledby="heading-3"><div class="chapter-head"><span class="chapter-num">03</span><h2 id="heading-3">FridaySaaS:留业务记录,统一新老来源</h2></div><h3>3.1 为什么需要留新影像数据</h3>
<p><strong>如果 SaaS 只在用户打开页面时代理查询美亚,它承担的是展示功能,无法承担稳定的下游数据供给。</strong> 没人打开页面时,PAC 仍需要知道患者有了新的影像或分析。</p>
<p class="keep-next">既然 PAC 从 SaaS 接收数据,SaaS 就应保存一份能够重试、重推、核对的影像业务记录:</p>
<div class="table-wrap"><table class="two-col">
<thead>
<tr>
<th scope="col">应保存的信息</th>
<th scope="col">用途</th>
</tr>
</thead>
<tbody><tr>
<td data-label="应保存的信息">患者、租户与影像采集诊所</td>
<td data-label="用途">明确业务归属;采集诊所不随患者后续转店而改变</td>
</tr>
<tr>
<td data-label="应保存的信息">影像来源、影像与检查标识</td>
<td data-label="用途">稳定识别、去重和追溯</td>
</tr>
<tr>
<td data-label="应保存的信息">类型、拍摄时间、绑定及有效状态</td>
<td data-label="用途">解释这份影像的业务含义</td>
</tr>
<tr>
<td data-label="应保存的信息">稳定文件引用,如 OSS ID</td>
<td data-label="用途">后续获取原片;临时链接过期后仍可定位</td>
</tr>
<tr>
<td data-label="应保存的信息">分析结果、来源及版本</td>
<td data-label="用途">保留当时依据,支持补推和重放</td>
</tr>
<tr>
<td data-label="应保存的信息">同步进度与失败记录</td>
<td data-label="用途">知道哪些已交付、哪些还需要补齐</td>
</tr>
</tbody></table></div>
<p>原片继续由美亚管理。SaaS 保存索引和结果,不重复建设影像存储;临时签名 URL 不能作为永久地址。</p>
<p><strong>这样即使美亚暂时不可用,SaaS 和 PAC 仍可查询已留存的影像信息和分析结果;原片访问和最新变更同步则可能受影响。</strong> 分析结果会影响后续业务判断,值得留存,而不应仅在查看页面时临时取一次。</p>
<p>美亚接入、获取变更和归属校验由 SaaS 对接层负责;open-connector 从 SaaS 已保存的业务记录向 PAC 推送。供应商协议与下游数据传输各自负责自己的部分。</p>
<p class="own-business">即使不接 PAC,留存业务记录也能支撑 SaaS 自身业务:将影像与就诊、病历、收费关联,用于检查进度跟进、复诊查阅、经营分析,以及追溯当时使用的分析结果。如果不留存,这些业务就需要反复查询美亚并临时关联数据,受其接口可用性和查询能力限制;分析结果更新或撤销后,若美亚不提供历史版本,SaaS 就难以还原当时使用的依据。</p>
<h3>3.2 新老影像怎么归一</h3>
<p class="keep-next"><strong>业务语义归一,来源实现分开。</strong> 新老功能可以保留,实际择一使用;对下游都应能回答同一组问题:</p>
<ul>
<li>影像属于谁、在哪里拍摄,是什么类型、什么时候拍摄;</li>
<li>当前是否有效,怎样查看,有哪些分析结果。</li>
</ul>
<p><strong>如果下游直接依赖“老影像的一套字段”和“美亚的另一套字段”,每切换一次影像系统,下游都要跟着改。</strong> 统一表达后,来源切换主要由 SaaS 处理,PAC 继续按宿主事实消费。</p>
<p>但统一不等于强行写入旧表。美亚有检查、切片、绑定状态和外部文件标识;如果旧结构表达不了,不能为了兼容丢掉它们,也不能把临时链接塞进旧文件地址就算完成。是否复用旧表,是方案采纳后的存储设计选择。</p>
<p>如果未来把历史影像迁入美亚,应保留新旧标识的对应关系。<strong>同一张片换了存储位置,不应被当成一次新的拍摄或重复的分析依据。</strong></p>
</section>
<section class="chapter" id="pac" aria-labelledby="heading-4"><div class="chapter-head"><span class="chapter-num">04</span><h2 id="heading-4">PAC:用分析形成诊断信号,通过宿主查看影像</h2></div><p class="keep-next">PAC 在这条链路中的职责保持两项:</p>
<ol class="duties">
<li><strong>消费影像分析。</strong> 将宿主提供的有效分析结果作为诊断信号源之一,与其他患者事实共同用于画像与召回,并保留来源依据。</li>
<li><strong>提供影像查看入口。</strong> 沿用宿主槽位打开 FridaySaaS,由宿主处理新老影像入口、权限和阅片授权。</li>
</ol>
<p>美亚生成的分析,由 SaaS 接收、留底后推给 PAC。<strong>如果 PAC 每次处理事实都临时向美亚取结果,重放同一份数据时可能拿到不同内容,就无法解释当时为什么得出那个判断。</strong></p>
<p>PAC 可以知道数据来源是美亚,但美亚不应成为 PAC 核心的直接依赖。<strong>否则接入下一家影像供应商时,PAC 又要接一套鉴权、患者映射和同步机制,还可能与 SaaS 的权限及归属规则形成两套判断。</strong> 这些差异应由宿主消化。</p>
<aside class="future" aria-label="后续能力边界"><p class="keep-next">如果将来是 PAC 自己发起分析,那是另一项能力:</p><ul>
<li>PAC 通过宿主获得授权的文件;</li>
<li>PAC 调用自己选择的分析服务;</li>
<li>结果标明由 PAC 发起,保留实际分析服务来源及结果版本,并关联原始影像。</li>
</ul></aside>
</section>
<section class="chapter" id="review" aria-labelledby="heading-5"><div class="chapter-head"><span class="chapter-num">05</span><h2 id="heading-5">评审要确定什么,哪些仍需外部确认</h2></div><p class="keep-next">本轮评审确认的是职责和数据留存方向:</p>
<div class="table-wrap"><table class="two-col">
<thead>
<tr>
<th scope="col">系统</th>
<th scope="col">对下游承担的承诺</th>
</tr>
</thead>
<tbody><tr>
<td data-label="系统">美亚</td>
<td data-label="对下游承担的承诺">影像与分析可查询,变更可获取,原片可授权访问</td>
</tr>
<tr>
<td data-label="系统">FridaySaaS</td>
<td data-label="对下游承担的承诺">患者归属正确,新老影像统一表达,业务数据可留底、补推和核对</td>
</tr>
<tr>
<td data-label="系统">PAC</td>
<td data-label="对下游承担的承诺">消费宿主分析作为诊断信号,通过宿主入口查看影像</td>
</tr>
</tbody></table></div>
<p class="keep-next">方案采纳前,优先向美亚确认两件事:</p>
<ul class="questions">
<li><strong>变更怎样获取</strong>:有无通知;没有通知时,能否完整拉到新增、修订、撤销和归属变化,并补查遗漏。</li>
<li><strong>分析怎样产生和识别</strong>:何时触发,怎样区分未分析、处理中、失败、完成零发现,以及结果后来是否修改。</li>
</ul>
<p class="review-conclusion">这两项决定后续采用通知还是轮询,以及分析能否可靠成为诊断信号。具体字段、存储结构、调度周期和任务拆分,在方向采纳、能力确认后再制定。</p>
</section>
<aside class="sources" id="sources" aria-labelledby="sources-title"><h2 id="sources-title">依据与核对范围</h2><p class="keep-next">本稿依据 2026-10-16 已核对的本地代码、SDK 和以下资料;未验证美亚实际部署能力。接口细节存在版本差异,正式对接仍需双方确认。</p>
<ul>
<li><span title="本机参考文件,未随归档分发">美亚系统集成方案</span>:第 2–3 章职责及信息同步、第 4–5 章设备与前置机、第 6–7 章阅片与患者映射。</li>
<li><span title="本机参考文件,未随归档分发">美亚私有化部署方案</span>:明确规划阿里云 OSS 和算法资源;规划不代表当前能力已启用。</li>
<li><span title="本机参考文件,未随归档分发">美亚接口文档</span>:§6.3 分析查询及空结果含义、§6.4/6.8 文件引用与临时 URL。</li>
<li>SaaS 代码:<span title="本机参考文件,未随归档分发">PACS 接口</span>、<span title="本机参考文件,未随归档分发">同步与查询</span>、<span title="本机参考文件,未随归档分发">新版影像中心</span>。</li>
<li>PAC 代码:<span title="本机参考文件,未随归档分发">影像分析事实</span>、<span title="本机参考文件,未随归档分发">宿主影像入口</span>。</li>
</ul>
<p>资料链接指向本机原件;内部分享时可随报告提供原 PDF。</p>
</aside></main>
<footer class="page-footer"><span>美亚 × FridaySaaS × PAC · 影像与分析数据方案设计</span><a href="#top">内部评审稿 v0.2 · 返回页首 ↑</a></footer></div><a class="back-top" href="#contents" aria-label="返回文档目录">目录 ↑</a>
<script>
(()=>{
const root=document.documentElement, themeButton=document.getElementById('theme-button'), key='imaging-document-theme';
const scheme=matchMedia('(prefers-color-scheme: dark)');
const isDark=()=>root.dataset.theme?root.dataset.theme==='dark':scheme.matches;
const update=()=>themeButton.setAttribute('aria-pressed',String(isDark()));
try{const saved=localStorage.getItem(key);if(saved==='dark'||saved==='light')root.dataset.theme=saved;}catch{}
update(); scheme.addEventListener('change',update);
themeButton.addEventListener('click',()=>{const theme=isDark()?'light':'dark';root.dataset.theme=theme;try{localStorage.setItem(key,theme)}catch{}update()});
document.getElementById('print-button').addEventListener('click',()=>window.print());
const back=document.querySelector('.back-top');const check=()=>{const visible=scrollY>700;back.classList.toggle('visible',visible);back.tabIndex=visible?0:-1;back.setAttribute('aria-hidden',String(!visible))};
addEventListener('scroll',check,{passive:true});check();
})();
</script></body></html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark">
<title>影像与分析数据方案设计 · 美亚 × FridaySaaS × PAC</title>
<meta name="description" content="影像资产、业务归属与诊断信号的三方协作方案。明确美亚、FridaySaaS 与 PAC 的数据流、留存责任与评审事项。">
<script>try{let t=localStorage.getItem('imaging-report-theme');if(t==='dark'||t==='light')document.documentElement.dataset.theme=t;let f=localStorage.getItem('imaging-report-size');if(f==='large')document.documentElement.dataset.size=f}catch{}</script>
<style>
:root{--bg:#f2f1ec;--paper:#fffefb;--ink:#22312f;--heading:#172e2b;--muted:#5c6b66;--subtle:#6e7b75;--line:#dedfd6;--soft:#f5f5ef;--teal:#17665b;--teal-soft:#eaf3ed;--teal-line:#bad3c4;--amber:#80591f;--amber-soft:#faf3e6;--amber-line:#e1cfaa;--blue:#355d80;--blue-soft:#eef3f7;--shadow:0 12px 50px #243c2b06;--font:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;--serif:"Songti SC","Noto Serif CJK SC","STSong","SimSun",serif;color-scheme:light}
@media(prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#151c1b;--paper:#1c2623;--ink:#d6ded6;--heading:#edf3e9;--muted:#a4b3ab;--subtle:#96a79e;--line:#36433c;--soft:#222e28;--teal:#96cbb6;--teal-soft:#243b31;--teal-line:#466b57;--amber:#dec08a;--amber-soft:#382f21;--amber-line:#645235;--blue:#a6c4e0;--blue-soft:#253340;--shadow:none;color-scheme:dark}}
:root[data-theme="dark"]{--bg:#151c1b;--paper:#1c2623;--ink:#d6ded6;--heading:#edf3e9;--muted:#a4b3ab;--subtle:#96a79e;--line:#36433c;--soft:#222e28;--teal:#96cbb6;--teal-soft:#243b31;--teal-line:#466b57;--amber:#dec08a;--amber-soft:#382f21;--amber-line:#645235;--blue:#a6c4e0;--blue-soft:#253340;--shadow:none;color-scheme:dark}
*{box-sizing:border-box}html{scroll-behavior:smooth;scroll-padding-top:100px}body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font);font-size:16px;line-height:1.95;-webkit-font-smoothing:antialiased}a{color:var(--teal);text-decoration:none}button,a,summary{-webkit-tap-highlight-color:transparent}button{font:inherit;cursor:pointer}a:focus-visible,button:focus-visible,summary:focus-visible{outline:2px solid var(--teal);outline-offset:5px}button:hover{background:var(--soft)}a:hover{text-decoration:underline;text-underline-offset:4px}::selection{background:var(--teal-line);color:var(--heading)}h1,h2,h3,p,figure,blockquote{margin:0}strong{font-weight:650;color:var(--heading)}h1,h2,h3{color:var(--heading);text-wrap:pretty}h1{font-family:var(--serif);font-size:52px;line-height:1.28;letter-spacing:-.025em;font-weight:700}h2{font-size:27px;line-height:1.6;font-weight:650;letter-spacing:-.025em}h3{font-size:20px;line-height:1.65;font-weight:600;margin:30px 0 17px}h3:first-child{margin-top:0}.icon{width:20px;height:20px;flex:none;vertical-align:middle}.skip-link{position:fixed;left:20px;top:-70px;background:var(--paper);z-index:99;padding:10px 18px;border:1px solid var(--teal)}.skip-link:focus{top:12px}.page-progress{position:fixed;top:0;left:0;width:100%;height:3px;z-index:100;transform:scaleX(0);transform-origin:left;background:var(--teal)}
.topbar{height:70px;position:sticky;top:0;z-index:30;background:var(--bg);border-bottom:1px solid var(--line)}.topbar-inner{max-width:1300px;height:100%;padding:0 38px;margin:auto;display:flex;align-items:center;justify-content:space-between;gap:20px}.doc-mark{display:flex;align-items:center;gap:12px;color:var(--heading);font-size:13px;font-weight:650;letter-spacing:.025em}.mark-icon{display:grid;place-items:center;width:30px;height:30px;color:var(--teal);border:1px solid var(--teal-line);border-radius:7px}.toolbar{display:flex;align-items:center;gap:5px}.tool{border:0;background:transparent;color:var(--muted);border-radius:6px;min-width:36px;min-height:36px;display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;padding:7px 9px}.tool[data-active="true"]{background:var(--teal-soft);color:var(--teal)}.print-button{border:1px solid var(--line);margin-left:5px}.version{font-size:11px;font-variant-numeric:tabular-nums;color:var(--subtle);margin-right:17px;letter-spacing:.04em}.size-icon{font-family:Georgia,serif;font-size:17px}
.shell{max-width:1300px;margin:0 auto;padding:42px 38px 70px;display:grid;grid-template-columns:206px minmax(0,1fr);gap:40px;align-items:start}.sidebar{position:sticky;top:109px;padding:19px 0;max-height:calc(100vh - 135px);overflow:auto;scrollbar-width:thin}.toc-label{font-size:11px;color:var(--subtle);letter-spacing:.15em;margin:0 0 20px 12px}.toc{display:grid;gap:5px}.toc a{display:flex;gap:12px;padding:12px 12px;border-left:2px solid transparent;border-radius:0 6px 6px 0;font-size:13px;line-height:1.5;color:var(--muted);text-decoration:none}.toc small{font-size:11px;font-weight:400;display:block;margin-top:4px;color:var(--subtle)}.toc-number{font-size:10px;font-variant-numeric:tabular-nums;padding-top:3px;color:var(--subtle);min-width:17px}.toc a.active{background:var(--teal-soft);color:var(--teal);border-color:var(--teal);font-weight:650}.toc a:hover{background:var(--soft)}.rail-note{border-top:1px solid var(--line);margin:27px 12px 0;padding-top:19px;color:var(--subtle);font-size:11px;line-height:1.9}.rail-note b{display:block;font-weight:550;color:var(--muted);margin-bottom:5px}.reading-status{display:flex;justify-content:space-between;margin-top:20px;font-variant-numeric:tabular-nums}.reading-track{height:2px;background:var(--line);margin-top:7px;overflow:hidden}.reading-track span{display:block;height:100%;width:0;background:var(--teal)}
.document{min-width:0;background:var(--paper);border:1px solid var(--line);box-shadow:var(--shadow);border-radius:4px;padding:60px 58px 26px;position:relative}.document:before{content:"";position:absolute;top:-1px;left:58px;width:62px;height:3px;background:var(--teal)}.hero{padding-bottom:44px}.eyebrow{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--teal);letter-spacing:.09em;margin-bottom:23px}.eyebrow .sep{color:var(--line)}.hero h1 span{display:block}.hero-deck{font-family:var(--serif);font-size:21px;color:var(--muted);margin-top:17px;letter-spacing:.02em}.meta{display:flex;gap:15px;align-items:center;flex-wrap:wrap;font-size:11px;color:var(--subtle);margin:24px 0 0}.meta .draft{border:1px solid var(--teal-line);padding:2px 8px;border-radius:3px;color:var(--teal);background:var(--teal-soft)}.hero-scope{color:var(--muted);font-size:13px;line-height:1.9;max-width:650px;margin-top:15px}.boundary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));margin-top:36px;padding:25px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);gap:25px}.boundary>div+div{border-left:1px solid var(--line);padding-left:25px}.boundary .role-name{font-size:13px;font-weight:650;color:var(--teal)}.boundary h2{font-family:var(--serif);font-size:23px;margin-top:6px;font-weight:650;line-height:1.5}.boundary p{font-size:12px;color:var(--muted);line-height:1.8;margin-top:5px}.core-boundary{font-size:12px;margin-top:13px;color:var(--teal);display:flex;gap:7px;align-items:center}.core-boundary .icon{width:15px;height:15px}.principle{padding:24px 0 0;color:var(--muted);font-size:14px;line-height:2}.principle strong{font-family:var(--serif);font-size:20px;line-height:1.85;font-weight:600}.principle p{margin:0}.principle strong{display:block;margin:8px 0 13px}.principle .note-label{margin-bottom:0}
.chapter{padding:40px 0 42px;border-top:1px solid var(--line);scroll-margin-top:0}.chapter-head{display:flex;gap:20px;align-items:flex-start;margin-bottom:26px}.chapter-num{font-family:Georgia,serif;font-size:42px;line-height:1.3;color:var(--teal-line);font-variant-numeric:tabular-nums;font-weight:400;min-width:47px;padding-top:10px}.chapter-kicker{font-size:10px;letter-spacing:.16em;line-height:1.6;color:var(--teal);margin-bottom:4px}.prose p{margin:16px 0}.prose>p:first-child{margin-top:0}.prose p:last-child{margin-bottom:0}.prose ul,.prose ol{padding-left:24px;margin:18px 0}.prose li{padding-left:3px;margin:7px 0}.prose li::marker{color:var(--teal)}.prose>h3:not(:first-child){padding-top:15px;margin-top:34px;border-top:1px dashed var(--line)}.step-heading{font-size:16px;font-weight:600;color:var(--teal);margin-top:28px!important}.step-heading strong{color:var(--teal)}.figure-intro{font-size:13px;color:var(--muted);margin-bottom:13px!important}.emphasis{border-left:3px solid var(--teal);padding:8px 0 8px 19px;font-size:16px}.consequence{background:var(--amber-soft);border:1px solid var(--amber-line);border-radius:4px;padding:19px 22px;font-size:15px;line-height:1.95}.consequence strong{font-weight:500;color:var(--ink)}.note-label{display:block;font-size:11px;font-weight:600;letter-spacing:.06em;line-height:1.5;margin-bottom:10px;color:var(--teal)}.consequence .note-label{color:var(--amber)}.requirement{margin:20px 0 25px;padding:21px 25px;border-left:3px solid var(--teal);background:var(--teal-soft);font-family:var(--serif);font-size:22px;line-height:1.8;color:var(--heading)}.requirement p{margin:0}.continuity{border-left:2px solid var(--teal-line);padding-left:19px;font-size:15px}.continuity strong{font-weight:600}.own-business{background:var(--soft);padding:21px 23px;border-radius:4px;font-size:14px;color:var(--muted);line-height:2}.footnote-callout{border-top:1px solid var(--line);padding-top:17px;font-size:14px;color:var(--muted)}
.flow-figure{margin:17px 0 23px;padding:22px 22px 24px;background-color:var(--soft);background-image:radial-gradient(var(--line) .7px,transparent .7px);background-size:15px 15px;border:1px solid var(--line);border-radius:5px}.flow-figure figcaption{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:12px;line-height:1.7;margin-bottom:21px}.figure-number{font-size:9px;letter-spacing:.09em;color:var(--subtle)}.state-badge{font-size:10px;color:var(--muted);margin-left:auto}.flow-grid{display:grid;grid-template-columns:minmax(0,1fr) 85px minmax(0,1fr) 65px minmax(0,1fr);align-items:stretch}.system{background:var(--paper);border:1px solid var(--line);border-radius:5px;min-width:0;display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;padding:19px 7px;min-height:125px}.system.saas{background:var(--teal-soft);border-color:var(--teal-line)}.system-kicker{font-size:10px;color:var(--subtle);letter-spacing:.08em;margin-bottom:5px}.system strong{font-size:17px;color:var(--heading);font-weight:650;line-height:1.5}.system p{font-size:10px!important;line-height:1.8;color:var(--muted);margin:8px 0 0!important}.connector{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--muted);gap:5px;padding:2px 5px;font-size:10px;line-height:1.65}.connector .icon{height:20px;width:34px;color:var(--teal)}.connector small{font-size:9px;color:var(--amber)}.flow-top{width:calc((100% - 150px)/3);display:flex;flex-direction:column;align-items:center;gap:3px;margin-bottom:3px}.capture{display:flex;align-items:center;gap:5px;font-size:10px;line-height:1.65;white-space:nowrap;color:var(--muted)}.capture .icon{width:14px;height:14px}.capture-arrow{font-size:20px;color:var(--subtle);line-height:1.1}.flow-bottom{width:calc((100% - 150px)/3);display:flex;justify-content:center}.storage{position:relative;padding-top:23px;display:flex;align-items:center;gap:7px;color:var(--muted);font-size:13px}.storage .icon{width:16px;height:16px}.storage small{font-size:10px;margin-left:4px}.storage-line{height:17px;border-left:1px solid var(--subtle);position:absolute;top:0;left:50%}.storage-line:after{content:"";position:absolute;bottom:0;left:-3px;border:solid var(--subtle);border-width:0 1px 1px 0;padding:2px;transform:rotate(45deg)}.view-path{display:flex;align-items:center;justify-content:space-between;gap:7px;padding:18px 17px;background:var(--blue-soft);border-radius:4px;font-size:12px;font-weight:550;color:var(--blue);margin:16px 0}.view-path>span{display:flex;gap:7px;align-items:center}.view-path>.icon{width:17px;height:17px;opacity:.7}.view-path>span>.icon{width:17px;height:17px}
.table-wrap{margin:23px 0;overflow:hidden;border:1px solid var(--line);border-radius:4px}table{width:100%;border-collapse:collapse;font-size:14px;line-height:1.85;text-align:left}th{font-weight:600;font-size:12px;color:var(--muted);background:var(--soft);padding:12px 16px;border-bottom:1px solid var(--line)}td{padding:15px 16px;border-bottom:1px solid var(--line);vertical-align:top}tbody tr:last-child td{border-bottom:0}td:first-child{font-weight:550;color:var(--heading);width:37%}#meyer td:first-child{width:31%}#meyer td:nth-child(2){width:26%}#review td:first-child{width:23%}tbody tr:hover{background:var(--soft)}.responsibilities{display:grid;grid-template-columns:1fr 1fr;gap:20px;list-style:none;padding:0!important;margin:22px 0!important}.responsibilities li{position:relative;margin:0;padding:22px 22px 20px;background:var(--teal-soft);border:1px solid var(--teal-line);border-radius:4px;font-size:14px;line-height:1.95}.responsibilities li>strong{display:block;font-size:18px;margin:12px 0 5px}.responsibility-icon{display:inline-flex;color:var(--teal)}.responsibility-icon .icon{width:24px;height:24px}.future{margin-top:27px;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:15px;padding:20px 0;font-size:15px;font-weight:550;color:var(--heading)}summary::-webkit-details-marker{display:none}summary .note-label{font-size:10px;margin-bottom:4px;color:var(--subtle)}summary>.icon{width:17px;height:17px;transition:transform .18s}details[open] summary>.icon{transform:rotate(90deg)}.detail-body{font-size:14px;color:var(--muted);padding-bottom:17px}.detail-body>p:first-child{margin-top:0}.detail-body>ul:last-child{margin-bottom:0}.open-questions{list-style:none;padding:0!important;display:grid;gap:12px;margin:24px 0!important}.open-questions li{position:relative;margin:0;padding:19px 22px 19px 62px;background:var(--amber-soft);border:1px solid var(--amber-line);border-radius:4px;font-size:14px;line-height:1.9}.open-questions strong{display:block;font-size:17px;margin-bottom:4px}.question-no{position:absolute;left:20px;top:22px;font-size:14px;font-family:Georgia,serif;color:var(--amber)}
.sources-section{padding:29px 0 18px;border-top:1px solid var(--line);scroll-margin-top:0}.sources-section>details>summary{padding:5px 0 16px}.sources-title{display:block;font-size:20px;line-height:1.6}.sources-intro{display:block;font-size:12px;color:var(--subtle);margin-top:4px}.sources-content{font-size:13px;color:var(--muted);line-height:1.95}.sources-content p{margin:14px 0}.sources-content ul{padding-left:18px}.sources-content li{margin:12px 0;padding-left:3px}.sources-content a{text-decoration:underline;text-decoration-color:var(--teal-line);text-underline-offset:4px}.document-footer{border-top:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:20px;padding-top:22px;font-size:10px;color:var(--subtle);letter-spacing:.02em}.document-footer a{white-space:nowrap}.toast{position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:60;background:var(--heading);color:var(--paper);padding:9px 17px;border-radius:6px;font-size:12px;box-shadow:0 5px 20px #0001;max-width:90vw;text-align:center;pointer-events:none}.toast[hidden]{display:none}.source-note{font-size:10px!important;color:var(--subtle)}
:root[data-size="large"] .prose{font-size:18px}:root[data-size="large"] .prose table{font-size:16px}:root[data-size="large"] .prose .own-business,:root[data-size="large"] .prose .continuity,:root[data-size="large"] .prose .consequence,:root[data-size="large"] .prose .responsibilities li{font-size:16px}
@media(min-width:1500px){.shell{gap:52px;grid-template-columns:218px minmax(0,1fr)}.document{padding-left:68px;padding-right:68px}}
@media(max-width:1180px){.shell{padding:26px 24px 50px;grid-template-columns:170px minmax(0,1fr);gap:25px}.document{padding:45px 35px 25px}.topbar-inner{padding:0 24px}.sidebar{top:95px}.toc a{padding-left:8px;gap:8px;font-size:12px}.toc small{font-size:10px}.flow-grid{grid-template-columns:minmax(0,1fr) 70px minmax(0,1fr) 55px minmax(0,1fr)}.flow-top,.flow-bottom{width:calc((100% - 125px)/3)}.system strong{font-size:15px}.system p{font-size:9px!important}.flow-figure{padding:18px 16px}.capture{font-size:9px}.boundary{gap:18px}.boundary>div+div{padding-left:18px}.boundary h2{font-size:21px}h1{font-size:46px}h2{font-size:25px}}
@media(max-width:960px){.shell{display:block;padding:0 24px 45px}.sidebar{position:sticky;top:70px;z-index:20;max-height:none;background:var(--bg);padding:10px 0;border-bottom:1px solid var(--line);margin-bottom:25px;overflow:visible}.toc-label,.rail-note{display:none}.toc{display:flex;overflow:auto;scrollbar-width:none;gap:5px}.toc::-webkit-scrollbar{display:none}.toc a{flex:none;align-items:center;padding:8px 13px;border:0;border-bottom:2px solid transparent;border-radius:5px;font-size:12px;white-space:nowrap;gap:7px}.toc a.active{border-bottom-color:var(--teal)}.toc small{display:none}.toc-number{padding:0;font-size:9px}.document{padding:45px 48px 25px;max-width:830px;margin:auto}.document:before{left:48px}html{scroll-padding-top:145px}.chapter,.sources-section{scroll-margin-top:0}.flow-grid{grid-template-columns:minmax(0,1fr) 85px minmax(0,1fr) 65px minmax(0,1fr)}.flow-top,.flow-bottom{width:calc((100% - 150px)/3)}.system strong{font-size:17px}.system p{font-size:10px!important}.capture{font-size:10px}.chapter-head{gap:17px}}
@media(max-width:640px){body{font-size:15px;line-height:1.95}.topbar{height:59px}.topbar-inner{padding:0 16px;gap:6px}.doc-mark{font-size:11px;gap:7px}.mark-icon{width:27px;height:27px}.mark-icon .icon{width:17px;height:17px}.version,.print-label{display:none}.toolbar{gap:0}.tool{min-width:33px;min-height:34px;padding:6px}.print-button{margin-left:2px;border:0}.shell{padding:0 13px 22px}.sidebar{top:59px;padding:8px 0;margin-bottom:15px}.toc a{font-size:11px;padding:7px 11px}.document{padding:34px 22px 22px;border-radius:3px}.document:before{left:22px;width:46px}.eyebrow{font-size:10px;gap:6px;margin-bottom:20px;letter-spacing:.025em}h1{font-size:37px;line-height:1.35}.hero-deck{font-size:17px;margin-top:13px}.meta{font-size:10px;gap:10px;margin-top:20px}.hero-scope{font-size:12px;margin-top:13px}.hero{padding-bottom:29px}.boundary{margin-top:28px;gap:11px;padding:20px 0}.boundary>div+div{padding-left:11px}.boundary .role-name{font-size:10px}.boundary h2{font-size:17px;line-height:1.7;margin-top:5px}.boundary p{font-size:10px}.core-boundary{font-size:10px}.principle{font-size:13px;padding-top:22px;line-height:1.95}.principle strong{font-size:18px}.chapter{padding:28px 0 30px;scroll-margin-top:0}.chapter-head{gap:12px;margin-bottom:21px}.chapter-num{font-size:30px;min-width:34px;padding-top:13px}h2{font-size:22px;line-height:1.6}.chapter-kicker{font-size:9px}.prose p{margin:15px 0}h3{font-size:18px}.step-heading{font-size:15px}.flow-figure{padding:16px;margin:17px -3px 21px}.flow-figure figcaption{font-size:11px;gap:6px;margin-bottom:20px}.figure-number{font-size:8px}.state-badge{display:block;flex-basis:100%;margin-left:0;font-size:10px}.flow-grid{display:flex;flex-direction:column;align-items:stretch;gap:0}.flow-top{width:100%;margin-bottom:7px}.capture{font-size:11px}.system{min-height:101px;padding:16px 10px}.system strong{font-size:19px}.system p{font-size:11px!important;margin-top:5px!important}.system-kicker{font-size:10px;margin-bottom:2px}.connector{padding:12px 0;min-height:78px;display:grid;grid-template-columns:1fr 22px 1fr;gap:7px;text-align:right;font-size:11px}.connector .icon{transform:rotate(90deg);width:23px;height:23px}.connector small{font-size:9px;text-align:left;max-width:70px}.connector:not(:has(small)):after{content:""}.connector br{display:none}.flow-bottom{width:100%;justify-content:flex-start;margin-top:14px}.storage{padding:0;font-size:11px}.storage-line{display:none}.storage:before{content:"美亚 →";font-size:10px;color:var(--subtle);margin-right:2px}.storage small{font-size:10px}.view-path{flex-direction:column;align-items:flex-start;gap:8px;padding:18px 20px;font-size:12px}.view-path>.icon{transform:rotate(90deg);margin-left:2px}.consequence{padding:17px 18px;font-size:14px}.requirement{padding:17px 19px;font-size:19px;margin:19px 0}.emphasis{font-size:15px;padding-left:15px}.table-wrap{border:0;border-top:1px solid var(--line);border-radius:0;margin:20px 0}table,tbody,tr,td{display:block}thead{display:none}tr{padding:15px 0;border-bottom:1px solid var(--line)}td{padding:4px 0;border:0;font-size:13px;line-height:1.9;width:auto!important}td:first-child{font-size:14px;font-weight:650;margin-bottom:5px}td:not(:first-child):before{content:attr(data-label);color:var(--subtle);font-size:10px;display:block;letter-spacing:.025em}#meyer td:nth-child(2){width:auto}tbody tr:hover{background:transparent}.own-business{font-size:13px;padding:18px}.continuity{font-size:14px;padding-left:15px}.responsibilities{grid-template-columns:1fr;gap:12px}.responsibilities li{font-size:14px;padding:20px}.responsibilities li>strong{font-size:17px;margin-top:9px}.open-questions li{padding:16px 17px 16px 49px;font-size:13px}.question-no{left:16px;top:19px;font-size:12px}.open-questions strong{font-size:16px}.sources-section{scroll-margin-top:0}.sources-content{font-size:12px;overflow-wrap:anywhere}.document-footer{font-size:9px;gap:12px;align-items:flex-start}.document-footer span{max-width:220px}.source-note{font-size:9px!important}html{scroll-padding-top:126px}}
@media(max-width:640px){.boundary{grid-template-columns:1fr;gap:13px;padding:19px 0}.boundary>div{display:grid;grid-template-columns:92px 1fr;column-gap:12px;align-items:baseline}.boundary>div+div{border-left:0;border-top:1px solid var(--line);padding:12px 0 0}.boundary .role-name{grid-row:1 / 3;font-size:11px}.boundary h2{font-size:18px;margin:0;line-height:1.5}.boundary p{grid-column:2;margin-top:3px;font-size:11px}.principle strong{margin-bottom:10px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*,*:before,*:after{transition:none!important;animation:none!important}}
@media print{html{scroll-behavior:auto;color-scheme:light!important}:root,:root[data-theme="dark"],:root:not([data-theme="light"]){--bg:#fff;--paper:#fff;--ink:#25322e;--heading:#172e2b;--muted:#53645c;--subtle:#65736c;--line:#d5dbd3;--soft:#f4f6f0;--teal:#17665b;--teal-soft:#edf4ed;--teal-line:#bad3c4;--amber:#80591f;--amber-soft:#faf4e8;--amber-line:#e1cfaa;--blue:#355d80;--blue-soft:#eef3f7}body{background:white;font-size:10pt;line-height:1.75;-webkit-print-color-adjust:exact;print-color-adjust:exact}.topbar,.sidebar,.page-progress,.toast,.skip-link{display:none!important}.shell{display:block;max-width:none;margin:0;padding:0}.document{padding:0;border:0;border-radius:0;box-shadow:none;max-width:none}.document:before{display:none}.hero{padding:0 0 22px}h1{font-size:32pt}.hero-deck{font-size:15pt}.eyebrow{font-size:9pt}.meta,.hero-scope{font-size:8pt}.boundary{margin-top:20px;padding:15px 0;break-inside:avoid}.boundary h2{font-size:16pt}.boundary .role-name{font-size:9pt}.boundary p{font-size:8pt}.principle{font-size:9pt}.principle strong{font-size:13pt}.chapter{padding:24px 0;break-before:auto}.chapter-head{break-after:avoid;margin-bottom:15px}.chapter-num{font-size:28pt}h2{font-size:18pt}h3{font-size:13pt;break-after:avoid}.prose p{margin:12px 0;orphans:3;widows:3}.prose ul,.prose ol{margin:12px 0}.flow-figure{break-inside:avoid;background-image:none;padding:18px}.system{min-height:100px}.flow-grid{display:grid;grid-template-columns:minmax(0,1fr) 85px minmax(0,1fr) 65px minmax(0,1fr)}.flow-top,.flow-bottom{width:calc((100% - 150px)/3)}.system strong{font-size:12pt}.system p{font-size:7pt!important}.table-wrap{overflow:visible;break-inside:avoid}table{font-size:9pt}th{font-size:8pt}td,th{padding:9px 12px}tr{break-inside:avoid}thead{display:table-header-group}.consequence,.requirement,.own-business,.continuity,.responsibilities li,.open-questions li{break-inside:avoid}.consequence,.emphasis,.continuity{font-size:10pt}.requirement{font-size:14pt}.own-business,.footnote-callout{font-size:9pt}.responsibilities li{font-size:9pt}.responsibilities li>strong{font-size:12pt}.future{break-inside:avoid}details>.detail-body,details>.sources-content{display:block!important}details::details-content{content-visibility:visible!important;height:auto!important}summary .icon{display:none}.open-questions li{font-size:9pt}.open-questions strong{font-size:12pt}.sources-content{font-size:8pt}.sources-section{break-inside:avoid}.sources-content a{color:var(--ink)}.document-footer{font-size:7pt;margin-top:15px}.document-footer a{display:none}a{text-decoration:none}.step-heading,.figure-intro,.prose>p:first-child,.prose>p:has(+.table-wrap),.prose>p:has(+blockquote),.prose>p:has(+.responsibilities),.prose>p:has(+.open-questions){break-after:avoid}.sources-title{font-size:13pt}@page{size:A4;margin:17mm 16mm 18mm}}
</style>
</head>
<body>
<aside role="note" style="padding:12px 20px;background:#fff4da;color:#594100;border-bottom:1px solid #e9cf8d;font:14px/1.7 sans-serif">历史评审稿,2026-10-22 归档。事件推送方案未被采用;现行实现按诊所分页轮询并批量查询分析。<a href="../../../apps/pac-service/src/integrations/meyer/README.md">查看当前采集说明</a></aside>
<a class="skip-link" href="#document">跳到正文</a><div class="page-progress" aria-hidden="true"></div>
<header class="topbar"><div class="topbar-inner"><a class="doc-mark" href="#document"><span class="mark-icon"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3 10 5-10 5L2 8l10-5ZM2 12l10 5 10-5M2 16l10 5 10-5"/></svg></span><span>影像与分析 · 方案设计</span></a><div class="toolbar"><span class="version">内部评审 · v0.2</span><button class="tool" id="font-button" aria-label="切换较大字号" aria-pressed="false" title="切换字号"><span class="size-icon" aria-hidden="true">Aa</span></button><button class="tool" id="theme-button" aria-label="切换深色模式" title="切换深浅色"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1.5 1.5m11 11L19 19M5 19l1.5-1.5m11-11L19 5"/></svg></button><button class="tool print-button" id="print-button" aria-label="打印或保存为 PDF"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9V3h12v6M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><path d="M6 14h12v8H6zM18 12h.01"/></svg><span class="print-label">打印 / PDF</span></button></div></div></header>
<div class="shell">
<aside class="sidebar" aria-label="文档目录"><p class="toc-label">阅读导航</p><nav class="toc"><a href="#relationship" class="active" aria-current="location"><span class="toc-number">01</span><span>整体关系<small>数据供给与原片查看</small></span></a><a href="#meyer" ><span class="toc-number">02</span><span>美亚 PACS<small>让变化可获取</small></span></a><a href="#saas" ><span class="toc-number">03</span><span>FridaySaaS<small>留业务记录,统一来源</small></span></a><a href="#pac" ><span class="toc-number">04</span><span>PAC<small>消费信号,打开影像</small></span></a><a href="#review" ><span class="toc-number">05</span><span>评审与确认<small>方向与待确认能力</small></span></a><a href="#sources" ><span class="toc-number">↗</span><span>资料依据<small>范围与原始出处</small></span></a></nav><div class="rail-note"><b>先确定边界,再细化实现</b>本稿讨论设计方向。接口、存储和开发任务在方案采纳后展开。<div class="reading-status"><span>阅读进度</span><span id="progress-value">0%</span></div><div class="reading-track" aria-hidden="true"><span></span></div></div></aside>
<main class="document" id="document">
<header class="hero"><p class="eyebrow">美亚 PACS <span class="sep">×</span> FridaySaaS <span class="sep">×</span> PAC</p><h1><span>影像与分析数据</span><span>方案设计</span></h1><p class="hero-deck">让影像资产、业务归属与诊断信号各有承接。</p><div class="meta"><span class="draft">内部评审稿</span><span>v0.2</span><time datetime="2026-10-16">2026.10.16</time></div><p class="hero-scope">本轮先确认设计方向与系统边界;字段、表结构、调度周期和开发任务在方案采纳后细化。</p>
<div class="boundary" aria-label="建议的三方职责"><div><span class="role-name">美亚 PACS</span><h2>管理影像资产</h2><p>影像与分析 · 原片访问</p></div><div><span class="role-name">FridaySaaS</span><h2>管理业务归属</h2><p>关系校验 · 留存与同步</p></div><div><span class="role-name">PAC</span><h2>消费宿主事实</h2><p>诊断信号 · 画像与召回</p></div></div><p class="core-boundary"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m5 12 4 4L19 6"/></svg>PAC 核心不直接接美亚。</p><div class="principle"><p><span class="note-label">判断依据</span><strong>三个系统可以保存和使用同一份患者与影像关系,但应明确各自数据的权威来源,并让关联及其变更沿统一链路传递。</strong> FridaySaaS 提供业务患者身份,美亚维护影像资产及其患者映射;SaaS 将两者对应关系校验、留存后提供给 PAC,PAC 据此形成事实和诊断信号。</p>
</div></header>
<section class="chapter" id="relationship" aria-labelledby="heading-relationship"><header class="chapter-head"><span class="chapter-num" aria-hidden="true">01</span><div><p class="chapter-kicker">RELATIONSHIP</p><h2 id="heading-relationship">整体关系:数据供给与查看原片分开</h2></div></header><div class="prose"><p class="step-heading"><strong>① 关联基础:先明确影像属于谁</strong></p>
<p>FridaySaaS 向美亚同步患者、诊所和就诊信息,美亚据此关联影像;SaaS 校验并留存对应关系,再向 PAC 提供。</p>
<p class="step-heading"><strong>② 数据供给:同步影像信息与分析结果</strong></p>
<p class="figure-intro">以下以启用美亚新影像为例,表示目标链路:</p>
<figure class="flow-figure" aria-labelledby="flow-caption">
<figcaption id="flow-caption"><span class="figure-number">FIG. 01</span><strong>影像与分析的数据供给</strong><span class="state-badge">目标链路 · 新影像启用时</span></figcaption>
<div class="flow-top"><span class="capture"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3 10 5-10 5L2 8l10-5ZM2 12l10 5 10-5M2 16l10 5 10-5"></path></svg>诊所设备与前置机</span><span class="capture-arrow" aria-hidden="true">↓</span></div>
<div class="flow-grid">
<div class="system meyer"><span class="system-kicker">影像资产</span><strong>美亚 PACS</strong><p>采集接入 · 影像与分析</p></div>
<div class="connector"><span>影像信息<br>分析结果及变更</span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16m-6-6 6 6-6 6"></path></svg><small>获取方式待确认</small></div>
<div class="system saas"><span class="system-kicker">业务归属</span><strong>FridaySaaS</strong><p>校验归属 · 留存 · 同步</p></div>
<div class="connector"><span>宿主事实</span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16m-6-6 6 6-6 6"></path></svg></div>
<div class="system pac"><span class="system-kicker">信号应用</span><strong>PAC</strong><p>诊断信号 · 画像与召回</p></div>
</div>
<div class="flow-bottom"><div class="storage"><span class="storage-line" aria-hidden="true"></span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3 10 5-10 5L2 8l10-5ZM2 12l10 5 10-5M2 16l10 5 10-5"></path></svg><span>OSS <small>原片存储</small></span></div></div>
</figure>
<p>原片由美亚管理,SaaS 向 PAC 提供影像业务信息与分析结果。美亚到 SaaS 如何获取变更,仍需确认。</p>
<p>新老影像功能可以保留,实际使用时择一启用;选用旧影像时,也由 SaaS 统一向 PAC 提供数据。</p>
<p class="step-heading"><strong>③ 查看原片:用户按需打开宿主入口</strong></p>
<div class="view-path" role="group" aria-label="查看原片路径"><span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m10 13 4-4m-6 6-2 2a4 4 0 0 1-6-6l5-5a4 4 0 0 1 6 0m2 3 2-2a4 4 0 0 1 6 6l-5 5a4 4 0 0 1-6 0" transform="translate(1 1) scale(.9)"></path></svg>PAC 宿主槽位</span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16m-6-6 6 6-6 6"></path></svg><span>FridaySaaS 影像页面</span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16m-6-6 6 6-6 6"></path></svg><span>当前选用的影像系统</span></div>
<p>SaaS 负责权限和入口;启用新影像时,由美亚提供阅片服务。<strong>数据同步持续进行,查看原片由用户按需发起。</strong></p>
</div></section>
<section class="chapter" id="meyer" aria-labelledby="heading-meyer"><header class="chapter-head"><span class="chapter-num" aria-hidden="true">02</span><div><p class="chapter-kicker">MEYER PACS</p><h2 id="heading-meyer">美亚:最重要的承诺是“变化可获取”</h2></div></header><div class="prose"><p>美亚负责采集接入、原片存储、影像关联、阅片,以及其提供的分析。对外不仅要能查询当前数据,还要让 SaaS 知道数据发生了什么变化。</p>
<p class="consequence"><span class="note-label">只发现新增,会漏掉什么</span><strong>如果只能查新影像列表,SaaS 可以知道“多了一张片”,却未必知道这张片后来分析完成、被改绑到另一位患者,或被撤销。下游就可能继续使用过期甚至归属错误的依据。</strong></p>
<p>因此,对美亚真正要提的要求是:</p>
<blockquote class="requirement">
<p>提供可追溯、可补拉的影像及分析变更机制,包含新增、修改、撤销和归属变化。</p>
</blockquote>
<div class="table-wrap"><table>
<thead>
<tr>
<th scope="col">美亚提供的能力</th>
<th scope="col">FridaySaaS 如何获取</th>
<th scope="col">意味着什么</th>
</tr>
</thead>
<tbody><tr>
<td data-label="美亚提供的能力">有事件通知,并能补查变更</td>
<td data-label="FridaySaaS 如何获取">通知后同步,遗漏时补拉</td>
<td data-label="意味着什么">及时性较好,也能恢复遗漏</td>
</tr>
<tr>
<td data-label="美亚提供的能力">没有通知,有完整变更查询</td>
<td data-label="FridaySaaS 如何获取">定时拉取</td>
<td data-label="意味着什么">可以可靠同步,延迟取决于拉取周期</td>
</tr>
<tr>
<td data-label="美亚提供的能力">只有入库时间列表、逐张查询</td>
<td data-label="FridaySaaS 如何获取">定时发现新片,反复查询分析</td>
<td data-label="意味着什么">能做部分同步,但后续修订、改绑、撤销的完整性没有保障</td>
</tr>
</tbody></table></div>
</div></section>
<section class="chapter" id="saas" aria-labelledby="heading-saas"><header class="chapter-head"><span class="chapter-num" aria-hidden="true">03</span><div><p class="chapter-kicker">FRIDAY SAAS</p><h2 id="heading-saas">FridaySaaS:留业务记录,统一新老来源</h2></div></header><div class="prose"><h3>3.1 为什么需要留新影像数据</h3>
<p class="emphasis"><strong>如果 SaaS 只在用户打开页面时代理查询美亚,它承担的是展示功能,无法承担稳定的下游数据供给。</strong> 没人打开页面时,PAC 仍需要知道患者有了新的影像或分析。</p>
<p>既然 PAC 从 SaaS 接收数据,SaaS 就应保存一份能够重试、重推、核对的影像业务记录:</p>
<div class="table-wrap"><table>
<thead>
<tr>
<th scope="col">应保存的信息</th>
<th scope="col">用途</th>
</tr>
</thead>
<tbody><tr>
<td data-label="应保存的信息">患者、租户与影像采集诊所</td>
<td data-label="用途">明确业务归属;采集诊所不随患者后续转店而改变</td>
</tr>
<tr>
<td data-label="应保存的信息">影像来源、影像与检查标识</td>
<td data-label="用途">稳定识别、去重和追溯</td>
</tr>
<tr>
<td data-label="应保存的信息">类型、拍摄时间、绑定及有效状态</td>
<td data-label="用途">解释这份影像的业务含义</td>
</tr>
<tr>
<td data-label="应保存的信息">稳定文件引用,如 OSS ID</td>
<td data-label="用途">后续获取原片;临时链接过期后仍可定位</td>
</tr>
<tr>
<td data-label="应保存的信息">分析结果、来源及版本</td>
<td data-label="用途">保留当时依据,支持补推和重放</td>
</tr>
<tr>
<td data-label="应保存的信息">同步进度与失败记录</td>
<td data-label="用途">知道哪些已交付、哪些还需要补齐</td>
</tr>
</tbody></table></div>
<p>原片继续由美亚管理。SaaS 保存索引和结果,不重复建设影像存储;临时签名 URL 不能作为永久地址。</p>
<p class="continuity"><strong>这样即使美亚暂时不可用,SaaS 和 PAC 仍可查询已留存的影像信息和分析结果;原片访问和最新变更同步则可能受影响。</strong> 分析结果会影响后续业务判断,值得留存,而不应仅在查看页面时临时取一次。</p>
<p>美亚接入、获取变更和归属校验由 SaaS 对接层负责;open-connector 从 SaaS 已保存的业务记录向 PAC 推送。供应商协议与下游数据传输各自负责自己的部分。</p>
<p class="own-business"><span class="note-label">SaaS 自身业务同样受益</span>即使不接 PAC,留存业务记录也能支撑 SaaS 自身业务:将影像与就诊、病历、收费关联,用于检查进度跟进、复诊查阅、经营分析,以及追溯当时使用的分析结果。如果不留存,这些业务就需要反复查询美亚并临时关联数据,受其接口可用性和查询能力限制;分析结果更新或撤销后,若美亚不提供历史版本,SaaS 就难以还原当时使用的依据。</p>
<h3>3.2 新老影像怎么归一</h3>
<p><strong>业务语义归一,来源实现分开。</strong> 新老功能可以保留,实际择一使用;对下游都应能回答同一组问题:</p>
<ul>
<li>影像属于谁、在哪里拍摄,是什么类型、什么时候拍摄;</li>
<li>当前是否有效,怎样查看,有哪些分析结果。</li>
</ul>
<p><strong>如果下游直接依赖“老影像的一套字段”和“美亚的另一套字段”,每切换一次影像系统,下游都要跟着改。</strong> 统一表达后,来源切换主要由 SaaS 处理,PAC 继续按宿主事实消费。</p>
<p>但统一不等于强行写入旧表。美亚有检查、切片、绑定状态和外部文件标识;如果旧结构表达不了,不能为了兼容丢掉它们,也不能把临时链接塞进旧文件地址就算完成。是否复用旧表,是方案采纳后的存储设计选择。</p>
<p class="footnote-callout">如果未来把历史影像迁入美亚,应保留新旧标识的对应关系。<strong>同一张片换了存储位置,不应被当成一次新的拍摄或重复的分析依据。</strong></p>
</div></section>
<section class="chapter" id="pac" aria-labelledby="heading-pac"><header class="chapter-head"><span class="chapter-num" aria-hidden="true">04</span><div><p class="chapter-kicker">PAC</p><h2 id="heading-pac">PAC:用分析形成诊断信号,通过宿主查看影像</h2></div></header><div class="prose"><p>PAC 在这条链路中的职责保持两项:</p>
<ol class="responsibilities">
<li><span class="responsibility-icon"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3 10 5-10 5L2 8l10-5ZM2 12l10 5 10-5M2 16l10 5 10-5"></path></svg></span><strong>消费影像分析。</strong> 将宿主提供的有效分析结果作为诊断信号源之一,与其他患者事实共同用于画像与召回,并保留来源依据。</li>
<li><span class="responsibility-icon"><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m10 13 4-4m-6 6-2 2a4 4 0 0 1-6-6l5-5a4 4 0 0 1 6 0m2 3 2-2a4 4 0 0 1 6 6l-5 5a4 4 0 0 1-6 0" transform="translate(1 1) scale(.9)"></path></svg></span><strong>提供影像查看入口。</strong> 沿用宿主槽位打开 FridaySaaS,由宿主处理新老影像入口、权限和阅片授权。</li>
</ol>
<p>美亚生成的分析,由 SaaS 接收、留底后推给 PAC。<strong>如果 PAC 每次处理事实都临时向美亚取结果,重放同一份数据时可能拿到不同内容,就无法解释当时为什么得出那个判断。</strong></p>
<p>PAC 可以知道数据来源是美亚,但美亚不应成为 PAC 核心的直接依赖。<strong>否则接入下一家影像供应商时,PAC 又要接一套鉴权、患者映射和同步机制,还可能与 SaaS 的权限及归属规则形成两套判断。</strong> 这些差异应由宿主消化。</p>
<details class="future"><summary><span><span class="note-label">未来扩展</span>如果由 PAC 主动发起分析</span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m9 5 7 7-7 7"></path></svg></summary><div class="detail-body"><p>如果将来是 PAC 自己发起分析,那是另一项能力:</p><ul>
<li>PAC 通过宿主获得授权的文件;</li>
<li>PAC 调用自己选择的分析服务;</li>
<li>结果标明由 PAC 发起,保留实际分析服务来源及结果版本,并关联原始影像。</li>
</ul></div></details>
</div></section>
<section class="chapter" id="review" aria-labelledby="heading-review"><header class="chapter-head"><span class="chapter-num" aria-hidden="true">05</span><div><p class="chapter-kicker">REVIEW</p><h2 id="heading-review">评审要确定什么,哪些仍需外部确认</h2></div></header><div class="prose"><p>本轮评审确认的是职责和数据留存方向:</p>
<div class="table-wrap"><table>
<thead>
<tr>
<th scope="col">系统</th>
<th scope="col">对下游承担的承诺</th>
</tr>
</thead>
<tbody><tr>
<td data-label="系统">美亚</td>
<td data-label="对下游承担的承诺">影像与分析可查询,变更可获取,原片可授权访问</td>
</tr>
<tr>
<td data-label="系统">FridaySaaS</td>
<td data-label="对下游承担的承诺">患者归属正确,新老影像统一表达,业务数据可留底、补推和核对</td>
</tr>
<tr>
<td data-label="系统">PAC</td>
<td data-label="对下游承担的承诺">消费宿主分析作为诊断信号,通过宿主入口查看影像</td>
</tr>
</tbody></table></div>
<p>方案采纳前,优先向美亚确认两件事:</p>
<ul class="open-questions">
<li><span class="question-no">01</span><strong>变更怎样获取</strong>有无通知;没有通知时,能否完整拉到新增、修订、撤销和归属变化,并补查遗漏。</li>
<li><span class="question-no">02</span><strong>分析怎样产生和识别</strong>何时触发,怎样区分未分析、处理中、失败、完成零发现,以及结果后来是否修改。</li>
</ul>
<p>这两项决定后续采用通知还是轮询,以及分析能否可靠成为诊断信号。具体字段、存储结构、调度周期和任务拆分,在方向采纳、能力确认后再制定。</p>
</div></section>
<section class="sources-section" id="sources" aria-labelledby="heading-sources"><details open><summary><span><span class="sources-title" id="heading-sources">依据与核对范围</span><span class="sources-intro">本地代码、SDK 与三份美亚资料</span></span><svg class="icon " viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="m9 5 7 7-7 7"/></svg></summary><div class="sources-content"><p>本稿依据 2026-10-16 已核对的本地代码、SDK 和以下资料;未验证美亚实际部署能力。接口细节存在版本差异,正式对接仍需双方确认。</p>
<ul>
<li><span title="本机参考文件,未随归档分发">美亚系统集成方案</span>:第 2–3 章职责及信息同步、第 4–5 章设备与前置机、第 6–7 章阅片与患者映射。</li>
<li><span title="本机参考文件,未随归档分发">美亚私有化部署方案</span>:明确规划阿里云 OSS 和算法资源;规划不代表当前能力已启用。</li>
<li><span title="本机参考文件,未随归档分发">美亚接口文档</span>:§6.3 分析查询及空结果含义、§6.4/6.8 文件引用与临时 URL。</li>
<li>SaaS 代码:<span title="本机参考文件,未随归档分发">PACS 接口</span>、<span title="本机参考文件,未随归档分发">同步与查询</span>、<span title="本机参考文件,未随归档分发">新版影像中心</span>。</li>
<li>PAC 代码:<span title="本机参考文件,未随归档分发">影像分析事实</span>、<span title="本机参考文件,未随归档分发">宿主影像入口</span>。</li>
</ul>
<p>资料链接指向本机原件;内部分享时可随报告提供原 PDF。</p>
</div></details></section>
<footer class="document-footer"><span>美亚 × FridaySaaS × PAC<br>影像与分析数据方案设计 · 内部评审稿</span><a href="#document">回到开头 ↑</a></footer>
</main></div><div class="toast" id="toast" role="status" aria-live="polite" hidden></div>
<script>
(()=>{
const root=document.documentElement,media=window.matchMedia('(prefers-color-scheme:dark)');
const toast=document.getElementById('toast');let toastTimer;
function say(text){toast.textContent=text;toast.hidden=false;clearTimeout(toastTimer);toastTimer=setTimeout(()=>toast.hidden=true,1800)}
function theme(){return root.dataset.theme||(media.matches?'dark':'light')}
function themeLabel(){document.getElementById('theme-button').setAttribute('aria-label',theme()==='dark'?'切换浅色模式':'切换深色模式')}
document.getElementById('theme-button').addEventListener('click',()=>{const next=theme()==='dark'?'light':'dark';root.dataset.theme=next;try{localStorage.setItem('imaging-report-theme',next)}catch{}themeLabel();say(next==='dark'?'已切换深色阅读':'已切换浅色阅读')});themeLabel();media.addEventListener?.('change',themeLabel);
const font=document.getElementById('font-button');function fontState(){const large=root.dataset.size==='large';font.setAttribute('aria-pressed',String(large));font.dataset.active=String(large);font.setAttribute('aria-label',large?'切换标准字号':'切换较大字号')};fontState();
font.addEventListener('click',()=>{const large=root.dataset.size!=='large';root.dataset.size=large?'large':'normal';try{localStorage.setItem('imaging-report-size',root.dataset.size)}catch{}fontState();update();say(large?'已使用较大字号':'已恢复标准字号')});
document.getElementById('print-button').addEventListener('click',()=>window.print());
const printStates=new Map();window.addEventListener('beforeprint',()=>{document.querySelectorAll('details').forEach(d=>{printStates.set(d,d.open);d.open=true})});window.addEventListener('afterprint',()=>{printStates.forEach((open,d)=>d.open=open);printStates.clear()});
const links=[...document.querySelectorAll('.toc a')],sections=links.map(a=>document.querySelector(a.getAttribute('href')));let queued=false;
function update(){const max=document.documentElement.scrollHeight-window.innerHeight;const progress=max>0?Math.min(1,Math.max(0,window.scrollY/max)):0;document.querySelector('.page-progress').style.transform='scaleX('+progress+')';document.querySelector('.reading-track span').style.width=Math.round(progress*100)+'%';document.getElementById('progress-value').textContent=Math.round(progress*100)+'%';let index=0;sections.forEach((s,i)=>{if(s.getBoundingClientRect().top<190)index=i});if(progress>.99)index=links.length-1;links.forEach((a,i)=>{a.classList.toggle('active',i===index);if(i===index)a.setAttribute('aria-current','location');else a.removeAttribute('aria-current')});queued=false}
const queue=()=>{if(!queued){queued=true;requestAnimationFrame(update)}};window.addEventListener('scroll',queue,{passive:true});window.addEventListener('resize',queue);document.querySelectorAll('details').forEach(d=>d.addEventListener('toggle',queue));update();
})();
</script>
</body>
</html>
# 美亚 × FridaySaaS × PAC:影像与分析数据方案设计
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。 原方案中的影像事件推送未被采用,当前实现按诊所分页轮询并批量查询分析。
> 内部评审稿 v0.2 · 2026-10-16
> 本轮先确认设计方向与系统边界;字段、表结构、调度周期和开发任务在方案采纳后细化。
**建议边界:美亚管理影像资产,FridaySaaS 管理业务归属并负责对外同步,PAC 消费宿主提供的事实。PAC 核心不直接接美亚。**
判断依据是:**三个系统可以保存和使用同一份患者与影像关系,但应明确各自数据的权威来源,并让关联及其变更沿统一链路传递。** FridaySaaS 提供业务患者身份,美亚维护影像资产及其患者映射;SaaS 将两者对应关系校验、留存后提供给 PAC,PAC 据此形成事实和诊断信号。
## 1. 整体关系:数据供给与查看原片分开
**① 关联基础:先明确影像属于谁**
FridaySaaS 向美亚同步患者、诊所和就诊信息,美亚据此关联影像;SaaS 校验并留存对应关系,再向 PAC 提供。
**② 数据供给:同步影像信息与分析结果**
以下以启用美亚新影像为例,表示目标链路:
```mermaid
flowchart TB
E[诊所设备与前置机] --> M[美亚 PACS]
M -->|存储原片| O[OSS]
M -->|影像信息、分析结果及变更| S["FridaySaaS<br/>校验归属、留存业务记录、对外同步"]
S -->|宿主事实| P["PAC<br/>诊断信号、画像与召回"]
```
原片由美亚管理,SaaS 向 PAC 提供影像业务信息与分析结果。美亚到 SaaS 如何获取变更,仍需确认。
新老影像功能可以保留,实际使用时择一启用;选用旧影像时,也由 SaaS 统一向 PAC 提供数据。
**③ 查看原片:用户按需打开宿主入口**
PAC 宿主槽位 → FridaySaaS 影像页面 → 当前选用的影像系统。
SaaS 负责权限和入口;启用新影像时,由美亚提供阅片服务。**数据同步持续进行,查看原片由用户按需发起。**
## 2. 美亚:最重要的承诺是“变化可获取”
美亚负责采集接入、原片存储、影像关联、阅片,以及其提供的分析。对外不仅要能查询当前数据,还要让 SaaS 知道数据发生了什么变化。
**如果只能查新影像列表,SaaS 可以知道“多了一张片”,却未必知道这张片后来分析完成、被改绑到另一位患者,或被撤销。下游就可能继续使用过期甚至归属错误的依据。**
因此,对美亚真正要提的要求是:
> 提供可追溯、可补拉的影像及分析变更机制,包含新增、修改、撤销和归属变化。
| 美亚提供的能力 | FridaySaaS 如何获取 | 意味着什么 |
|---|---|---|
| 有事件通知,并能补查变更 | 通知后同步,遗漏时补拉 | 及时性较好,也能恢复遗漏 |
| 没有通知,有完整变更查询 | 定时拉取 | 可以可靠同步,延迟取决于拉取周期 |
| 只有入库时间列表、逐张查询 | 定时发现新片,反复查询分析 | 能做部分同步,但后续修订、改绑、撤销的完整性没有保障 |
## 3. FridaySaaS:留业务记录,统一新老来源
### 3.1 为什么需要留新影像数据
**如果 SaaS 只在用户打开页面时代理查询美亚,它承担的是展示功能,无法承担稳定的下游数据供给。** 没人打开页面时,PAC 仍需要知道患者有了新的影像或分析。
既然 PAC 从 SaaS 接收数据,SaaS 就应保存一份能够重试、重推、核对的影像业务记录:
| 应保存的信息 | 用途 |
|---|---|
| 患者、租户与影像采集诊所 | 明确业务归属;采集诊所不随患者后续转店而改变 |
| 影像来源、影像与检查标识 | 稳定识别、去重和追溯 |
| 类型、拍摄时间、绑定及有效状态 | 解释这份影像的业务含义 |
| 稳定文件引用,如 OSS ID | 后续获取原片;临时链接过期后仍可定位 |
| 分析结果、来源及版本 | 保留当时依据,支持补推和重放 |
| 同步进度与失败记录 | 知道哪些已交付、哪些还需要补齐 |
原片继续由美亚管理。SaaS 保存索引和结果,不重复建设影像存储;临时签名 URL 不能作为永久地址。
**这样即使美亚暂时不可用,SaaS 和 PAC 仍可查询已留存的影像信息和分析结果;原片访问和最新变更同步则可能受影响。** 分析结果会影响后续业务判断,值得留存,而不应仅在查看页面时临时取一次。
美亚接入、获取变更和归属校验由 SaaS 对接层负责;open-connector 从 SaaS 已保存的业务记录向 PAC 推送。供应商协议与下游数据传输各自负责自己的部分。
即使不接 PAC,留存业务记录也能支撑 SaaS 自身业务:将影像与就诊、病历、收费关联,用于检查进度跟进、复诊查阅、经营分析,以及追溯当时使用的分析结果。如果不留存,这些业务就需要反复查询美亚并临时关联数据,受其接口可用性和查询能力限制;分析结果更新或撤销后,若美亚不提供历史版本,SaaS 就难以还原当时使用的依据。
### 3.2 新老影像怎么归一
**业务语义归一,来源实现分开。** 新老功能可以保留,实际择一使用;对下游都应能回答同一组问题:
- 影像属于谁、在哪里拍摄,是什么类型、什么时候拍摄;
- 当前是否有效,怎样查看,有哪些分析结果。
**如果下游直接依赖“老影像的一套字段”和“美亚的另一套字段”,每切换一次影像系统,下游都要跟着改。** 统一表达后,来源切换主要由 SaaS 处理,PAC 继续按宿主事实消费。
但统一不等于强行写入旧表。美亚有检查、切片、绑定状态和外部文件标识;如果旧结构表达不了,不能为了兼容丢掉它们,也不能把临时链接塞进旧文件地址就算完成。是否复用旧表,是方案采纳后的存储设计选择。
如果未来把历史影像迁入美亚,应保留新旧标识的对应关系。**同一张片换了存储位置,不应被当成一次新的拍摄或重复的分析依据。**
## 4. PAC:用分析形成诊断信号,通过宿主查看影像
PAC 在这条链路中的职责保持两项:
1. **消费影像分析。** 将宿主提供的有效分析结果作为诊断信号源之一,与其他患者事实共同用于画像与召回,并保留来源依据。
2. **提供影像查看入口。** 沿用宿主槽位打开 FridaySaaS,由宿主处理新老影像入口、权限和阅片授权。
美亚生成的分析,由 SaaS 接收、留底后推给 PAC。**如果 PAC 每次处理事实都临时向美亚取结果,重放同一份数据时可能拿到不同内容,就无法解释当时为什么得出那个判断。**
PAC 可以知道数据来源是美亚,但美亚不应成为 PAC 核心的直接依赖。**否则接入下一家影像供应商时,PAC 又要接一套鉴权、患者映射和同步机制,还可能与 SaaS 的权限及归属规则形成两套判断。** 这些差异应由宿主消化。
如果将来是 PAC 自己发起分析,那是另一项能力:
- PAC 通过宿主获得授权的文件;
- PAC 调用自己选择的分析服务;
- 结果标明由 PAC 发起,保留实际分析服务来源及结果版本,并关联原始影像。
## 5. 评审要确定什么,哪些仍需外部确认
本轮评审确认的是职责和数据留存方向:
| 系统 | 对下游承担的承诺 |
|---|---|
| 美亚 | 影像与分析可查询,变更可获取,原片可授权访问 |
| FridaySaaS | 患者归属正确,新老影像统一表达,业务数据可留底、补推和核对 |
| PAC | 消费宿主分析作为诊断信号,通过宿主入口查看影像 |
方案采纳前,优先向美亚确认两件事:
- **变更怎样获取**:有无通知;没有通知时,能否完整拉到新增、修订、撤销和归属变化,并补查遗漏。
- **分析怎样产生和识别**:何时触发,怎样区分未分析、处理中、失败、完成零发现,以及结果后来是否修改。
这两项决定后续采用通知还是轮询,以及分析能否可靠成为诊断信号。具体字段、存储结构、调度周期和任务拆分,在方向采纳、能力确认后再制定。
## 6. 兜底方案(低优先级)
若 FridaySaaS 暂不留存和同步新影像业务数据,可由 **PAC 宿主适配层直接拉取美亚现有接口**。采用 **主动轮询、快照对账、幂等更新和采集留底**:按入库时间发现新增,周期复查历史影像及分析,再转换为 PAC 标准事实。患者归属与授权沿用 SaaS,查看原片仍走宿主入口。
这条路线无需等待美亚推送或 SaaS 新增业务存储,但采集维护成本转至 PAC 适配层;时效受轮询周期限制,无法保证捕获所有中间变更,也无法仅凭现有空结果或查询不到准确判断分析状态及删除。
---
### 依据与核对范围
本稿依据 2026-10-16 已核对的本地代码、SDK 和以下资料;未验证美亚实际部署能力。接口细节存在版本差异,正式对接仍需双方确认。
- 美亚系统集成方案(本机参考文件 `瑞尔口腔影像中心PACS项目系统集成方案v0.4.pdf`,未随归档分发):第 2–3 章职责及信息同步、第 4–5 章设备与前置机、第 6–7 章阅片与患者映射。
- 美亚私有化部署方案(本机参考文件 `瑞尔PACS影像中心私有化部署方案v0.1.pdf`,未随归档分发):明确规划阿里云 OSS 和算法资源;规划不代表当前能力已启用。
- 美亚接口文档(本机参考文件 `PACS_瑞尔接口对接文档.pdf`,未随归档分发):§6.3 分析查询及空结果含义、§6.4/6.8 文件引用与临时 URL。
- SaaS 代码:PACS 接口(外部仓库:`friday-saas/emr/src/main/java/com/emr/project/medical/controller/PacsController.java`)、同步与查询(外部仓库:`friday-saas/emr/src/main/java/com/emr/project/medical/service/impl/PacsSyncServiceImpl.java`)、新版影像中心(外部仓库:`friday-saas-v2/apps/web/features/patient/components/pacs-image-center.tsx`)。
- PAC 代码:[影像分析事实](../../../apps/pac-service/src/modules/sync/pipeline/parsers/image-analysis.parser.ts)、[宿主影像入口](../../../apps/pac-web/src/lib/image-action-url.ts)。
资料链接指向本机原件;内部分享时可随报告提供原 PDF。
# 下游北京业务日期修复验收(2026-10-18)
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
## 边界与改动
- 时刻继续以 UTC 保存;下游按 `Asia/Shanghai` 解释业务日期。
- 生日、回访任务日、`@db.Date` 保持纯日期语义,不将数据库的 UTC 零点载体当成事件时刻。
- 修复上次到诊派生日期、同日就诊计数、同日病历/医嘱关联、未来回访排除、外院治疗回访日期比较、周岁及生日边界、AI 日期话术、患者详情与批次日期展示。
- 到诊分档按北京自然日稳定划分;原有天数阈值不变。下次回访表单按北京时间提交。
- 摄入、源时区转换、事实字段、数据库结构、召回阈值与按实际时长计算的冷却窗口均未修改。
## 本地验证
- 后端完整回归:145 套、2429 项通过;3 套、24 项按原有条件跳过。
- 前端:5 套、77 项通过;前后端 TypeScript 检查通过。
- 实际 PostgreSQL 在 UTC、北京、洛杉矶会话时区分别验证:同日/前日/次日回访、未来回访、生日年龄均一致;事务只读且回滚。
- Node 三种进程时区验证一致;覆盖北京零点、跨月年、闰日、纯日期、摄入零点锚、到诊 DATE 派生及同日医生关联。
- 两处旧禁忌边界测试改为完整时刻断言:北京 2026-10-28 零点对应 `2026-10-27T16:00:00Z`。
## 存量与发布范围
- 读取时计算的日期随发布生效;已持久化的上次到诊、画像特征和已生成话术不会因代码发布全部自动改写。
- 历史画像须走已有患者定向强制重算;未运行全库重算、未重摄入事实。部署测试后用真实患者定向核验。
- 本次顺序:功能分支 → test → 测试发布与验证 → 同一功能分支独立合入 main。生产不发布。
## 已完成发布与验收
- 功能分支:`codex/business-date-shanghai`,提交 `2e5e22e`。
- test 合并及实际部署:`daff13e`。
- main 独立合并:`b7901c9`;已确认功能提交同时属于 main/test 历史,未将 test 合入 main。
- 测试发布退出码 0,57 个已有迁移无待执行项;实际容器镜像与新构建镜像一致。
- 测试健康接口返回 `status: ok`,网页 HTTP 200;前后端容器运行且重启计数为 0。
- 在部署镜像内验证北京零点、周岁边界通过。
- 选取 Friday 测试宿主 3 位真实患者,调用实际到诊派生字段刷新逻辑;日期分别为 2026-10-16、2026-10-13、2026-09-21,与 PostgreSQL 北京日期计算一致。同日去重计数分别为 1、2、1。
- 3 个样本刷新前后事实行摘要一致,未改摄入数据;这些样本原有末诊日期本就正确,不能据此声称修复了全部历史数据。跨日纠错由本地边界用例验证。
- 仅刷新所选患者的到诊派生字段,未运行全量画像或召回重算;已生成话术未批量重建。
- 生产未部署。主目录已有未提交文件、本地服务和美亚工作区未操作。
服务器验收与回退证据保留于测试机 `/root/pac-release-backups/business-date-20261018/`;本文未包含患者身份与凭据。
# 5i5ya 投诉摄入:生产发布与真实数据验收
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
日期:2026-10-18(Asia/Shanghai)
**结论:已合入 main 并部署生产;34 个真实患者身份对应的 75 张反馈单、184 条跟进,落库与重复摄入核验通过。**
## 版本与发布范围
- 功能提交:`3d29ada`,分支 `codex/jvs-complaint-ingestion`。
- main 合并及生产版本:`1793c1bcdd43ea70d420a5d00c549d1c9503fd59`。
- test 保持已验收版本 `c9360bcb853c3cd7d20ad1201e5e82c1e243a96b`。
- 从功能分支合入 main,没有将 test 上的其他功能带入生产。
- FridaySaaS 投诉未接入,召回规则未修改;本次没有新增数据库迁移。
- 沿用此前同一功能提交的本地测试结果:143 组、2,411 项通过,另行真实样本及隔离 PostgreSQL 验证 26 项通过。本轮执行生产构建及真实数据库验收。
## 发布前任务与部署
发布准备时摄入已结束,队列没有执行中的任务,但数据库仍有召回筛选长查询。不能仅凭摄入账本和队列为空判断系统空闲。用户明确允许中断本轮后,执行应用重建。
构建最初因 Dockerfile 外部解析器镜像下载失败而中止;使用删除首行解析器指令的临时 Dockerfile 副本,交由 Docker 内置解析器完成构建。其余构建指令、源码及生产构建参数保持一致,未修改仓库 Dockerfile。发布采用既有脚本的迁移、强制重建及验收流程,构建步骤替换为校验已构建镜像 ID 和固定提交。
生产约 17:21 完成应用替换:
- 57 份现有迁移,无待执行迁移。
- service 镜像:`1a258da2c107d5c2c2320a8075f27f5feb306791352f454ab3c1f5fbdfb830c3`。
- web 镜像:`96824485987118fba9bac734b1c943134ec64e1b2018f820f5920361358f8283`。
- 两容器实际镜像均与构建结果一致,检查时重启次数均为 0。
- `/health` 返回 `status: ok`;前端本机、私网及生产公网 `/plans` 均为 HTTP 200。
- 使用 managed 配置,只替换 PAC 应用容器,未重启托管 PostgreSQL/Redis。
- 旧版本 `76e7d5b` 和旧镜像保留,私有发布证据:`/data/pac-release-backups/complaint-20261018/`。
## 真实数仓到生产 PAC
发布后通过生产环境连接重新只读查询 `dw_group.fact_complain_out`,使用正式 `sync-incremental` 流程摄入。患者范围限定为 34 个品牌+患者身份,单批 50、并发 1,使用 `--no-recompute`,未另启全量画像或召回计算。
| 验收项 | 结果 |
|---|---:|
| 源投诉及跟进行 | 194 |
| 聚合反馈单 | 75 |
| 有效未完成投诉 | 4 |
| 有效已完成投诉 | 20 |
| 非有效快照 | 51 |
| 跟进记录 | 184 |
| 逐条落库一致 | 75 / 75 |
| 投诉事务 / 事实版本 | 75 / 75 |
| 归属、内容、状态、时间差异 | 0 |
51 张非有效快照包括表扬、中性、未知或草稿等,保留为 `invalidated`,不作为有效投诉信号。
首轮于 17:22:45 完成,cohort 处理 9.392 秒,运行 ID `5c06e2f9-89e4-4712-b923-08ddff41c848`。正式 cohort 会同时处理这些患者的其他已有资源:整批新增 360 条事务、80 条事实,其中投诉为 75 条;整批及事实失败数均为 0。
逐条核对患者外部 ID、租户、品牌、诊所、状态、正文与标准字段、发生时间、来源版本时间和完整跟进;另以显式 `+08:00` 独立转换源时间,75 张反馈单及 184 条跟进均无差异。
第二轮于 17:23:12 完成,cohort 处理 7.333 秒,运行 ID `1a30e0f6-f96f-45ef-8db8-61f72064e969`。整批新增事务为 0、事实新增及替换均为 0;投诉仍为 75 条事务和 75 个事实版本,事实指纹不变,幂等验收通过。
两轮均确认全局增量游标未因抽样验收而推进。原始样本、患者清单和核对证据仅留在私有验收目录,不进入 Git。
## 后续自动摄入与边界
生产已注册 `jvs-dw` 常规调度:`15 0,8-22/2 * * *`,时区 Asia/Shanghai;验收结束后的下一次计划为当日 18:15。投诉历史发现由常规调度继续执行,本次 34 人验收不代表全量投诉已补齐。
最终检查无执行中的摄入、画像或召回账本记录,无活动数据库查询;画像队列另有 1 条延迟任务。未手动启动被中断召回轮次的全量重算。
源端没有 ETL 入仓时间及删除标记,窗口外迟到、时间字段完全不变的原地修订和物理删除仍属于既有采集边界。本次未增加对账机制。
主目录未提交文档、本地服务和美亚工作区未改动。本验收报告留在投诉独立工作区,暂未提交。
# 5i5ya 投诉摄入:测试发布与真实数据验收
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
日期:2026-10-18(Asia/Shanghai)
**结论:已合入 test 并部署测试环境;34 个真实患者身份、75 张反馈单的两轮摄入与逐条核验通过。main 和生产未变更。**
## 发布版本与范围
- 功能分支:`codex/jvs-complaint-ingestion`。
- 功能提交:`3d29ada`。
- test 合并提交及服务器运行版本:`c9360bcb853c3cd7d20ad1201e5e82c1e243a96b`。
- main 保持:`76e7d5bc69e98d9f61d4a967c131c4a58d3d0207`。
- FridaySaaS 投诉未接入;召回规则、画像提取器、免打扰规则未修改。
- 主目录未提交文件和本地服务未改动。美亚工作区未改动。
复查重点:投诉按配置命名空间聚合,沿用宿主患者身份;变化发现与完整跟进读取分开;新资源首轮发现历史患者;北京时间统一转 UTC;非负面、草稿和未知数据保存无效快照;重复和旧快照重放不恢复已撤销的投诉效力。
## 本次本地验证
- 回归测试:143 组、2,411 项通过;24 项按配置跳过。
- 另行显式启用真实源样本和独立 PostgreSQL 验证:2 组、26 项通过;SQL 导出辅助项未启用。
- `@pac/types` 构建通过。
- 后端源码与测试的类型检查通过。
- 提交前差异检查通过。
真实样本及数据库专项验证覆盖同时间分类修订、旧版本重放、跨品牌同号、身份冲突、完整跟进和 UTC 转换。测试库与本地应用数据库隔离。
## 测试发布检查
发布前测试服务器在 test 分支,工作目录干净;健康接口正常,磁盘剩余约 111 GB;摄入账本无 running 任务,上轮摄入已于 16:34:36 完成。
使用现有发布脚本完成镜像构建、迁移检查和应用容器替换:
- 57 份现有迁移,无待执行迁移;本改动无新表和迁移。
- service 镜像:`c5932b8708e0c39d85e5b230435c267745a66f3119d6c96a69c6524f063ba8bd`。
- web 镜像:`15746e42828714c27e8866ba2b6446f778452fff2bb7c0ce561c975c9b8c60ff`。
- 容器实际镜像与构建结果一致;最终检查两容器重启次数均为 0。
- `/health` 返回 `status: ok`,前端 HTTP 200。
- 旧提交和镜像已留存,测试服务器发布证据位于 `/root/pac-release-backups/complaint-20261018/`(私有目录)。
## 真实数仓 → 测试 PAC
从测试容器重新只读查询数仓;不是将本地造数写入测试库。
| 验收内容 | 实际结果 |
|---|---:|
| 患者范围(品牌+患者 ID) | 34 |
| 原始投诉及跟进行 | 194 |
| 聚合后的反馈单 | 75 |
| 有效、未完成投诉 | 4 |
| 有效、已完成投诉 | 20 |
| 非有效投诉快照 | 51 |
| 保留的跟进 | 184 |
| 逐条事实核验一致 | 75 / 75 |
| 投诉事务 | 75 |
| 投诉事实版本 | 75 |
| 核验差异 | 0 |
非有效快照包括表扬、中性、未知或草稿等,均为 `invalidated`、`signal_eligible=false`,不计入有效投诉。有效投诉合计 24 张。
通过正式 `sync-incremental` CLI,使用限定的患者清单、单批 50 人、并发 1、`--no-recompute` 运行两轮。沿用完整宿主 cohort 管线,因此同批患者其他资源也按已有机制正常摄入;没有另开全量画像或召回计算。
首轮:16:47:20 完成,cohort 处理约 9.5 秒;整批失败数和事实失败数均为 0。首轮运行 ID:`d4414cca-4495-42df-9dfc-51d47777471d`。
核对包括:患者外部 ID、租户、品牌、投诉诊所、状态、正文及标准字段、发生时间、版本时间和完整跟进内容。另用显式 `+08:00` 独立转换源时间,75 张反馈单与 184 条跟进全部通过,未依赖服务器默认时区。
第二轮:投诉事务仍为 75,事实版本仍为 75,全部事实的内容指纹与第一轮一致,无重复新增或版本抖动。
两轮均保持原全局增量游标不变,投诉首轮全量发现水位仍未被抽样验收提前推进。其余患者的存量发现由后续常规增量调度处理;本次验收不代表全量投诉已经补齐。
## 已知边界
源端没有 ETL 入仓时间或删除标记。现有回看机制仍无法保证发现窗口外的迟到回填、全部时间字段不变的原地修订或物理删除。本次未扩展为对账任务,也未把投诉信号加入召回决策。
原始数据、患者清单及逐条比对证据保存在私有验收目录,不进入 Git;本报告仅记录汇总和运行证据。
<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="light dark"><meta name="description" content="美亚、FridaySaaS 与 PAC 的影像及患者分析方案,评审修订稿 v0.4。"><title>影像与分析数据方案设计 · v0.4</title><style>
:root{color-scheme:light;--ground:#f4f6fb;--surface:#fff;--sunken:#eaeef6;--ink:#0f1b33;--ink-2:#44506a;--ink-3:#6f7a91;--brand:#0032a0;--brand-soft:#e3eafa;--rule:#dde3ee;--note:#f5f7fc;--warn-bg:#fff9ed;--warn-rule:#d6ae63;--serif:"Noto Serif SC","Songti SC","STSong",serif;--sans:"Noto Sans SC","PingFang SC","Microsoft YaHei",system-ui,sans-serif;--mono:"IBM Plex Mono",ui-monospace,"SFMono-Regular",Menlo,monospace}
:root[data-theme=dark]{color-scheme:dark;--ground:#0a1020;--surface:#121a2d;--sunken:#1a2440;--ink:#e7ecf6;--ink-2:#b3bdd2;--ink-3:#8994ab;--brand:#86a7ff;--brand-soft:#1d2b52;--rule:#2a3550;--note:#172037;--warn-bg:#292518;--warn-rule:#a38a55}
@media(prefers-color-scheme:dark){:root:not([data-theme=light]){color-scheme:dark;--ground:#0a1020;--surface:#121a2d;--sunken:#1a2440;--ink:#e7ecf6;--ink-2:#b3bdd2;--ink-3:#8994ab;--brand:#86a7ff;--brand-soft:#1d2b52;--rule:#2a3550;--note:#172037;--warn-bg:#292518;--warn-rule:#a38a55}}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--ground);color:var(--ink);font-family:var(--sans);font-size:16px;line-height:1.9;-webkit-font-smoothing:antialiased}::selection{background:var(--brand-soft);color:var(--ink)}a{color:var(--brand);text-decoration-color:color-mix(in srgb,var(--brand) 35%,transparent);text-underline-offset:4px}a:hover{text-decoration-color:var(--brand)}button{font:inherit}a:focus-visible,button:focus-visible{outline:2px solid var(--brand);outline-offset:4px}
.wrap{max-width:1040px;margin:auto;padding:40px 26px 48px}.document-header{padding:0 8px 28px}.topline{display:flex;justify-content:space-between;gap:16px;align-items:center;margin-bottom:16px}.eyebrow{font-size:12px;letter-spacing:.10em;color:var(--brand);font-weight:700}.tools{display:flex;gap:4px}.tools button{border:0;color:var(--ink-3);background:transparent;padding:5px 8px;cursor:pointer;font-size:12px;border-radius:5px;display:flex;align-items:center;gap:5px}.tools button:hover{background:var(--brand-soft);color:var(--brand)}.tools svg{width:15px;height:15px}h1{font-family:var(--serif);font-weight:700;font-size:clamp(30px,3.8vw,42px);line-height:1.35;letter-spacing:.015em;margin:0 0 14px}.meta{display:flex;align-items:center;flex-wrap:wrap;gap:9px;color:var(--ink-3);font-size:12px;margin-bottom:14px}.meta .version{background:var(--brand-soft);color:var(--brand);border-radius:99px;padding:1px 10px;font-weight:500}.meta time{font-family:var(--mono);font-size:12px}.scope{max-width:48em;color:var(--ink-2);font-size:14px;line-height:1.8;margin:0}
main{background:var(--surface);border-radius:14px;padding:42px 58px 40px}p{margin:0 0 18px;color:var(--ink-2)}strong{color:var(--ink);font-weight:600}p:last-child{margin-bottom:0}.boundary{padding:0 0 0 20px;border-left:3px solid var(--brand);font-size:18px;line-height:1.85;margin-bottom:24px}.boundary strong{font-weight:600}.principle{font-size:15.5px;line-height:1.9;margin-bottom:30px}.contents{border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:17px 0 19px;margin:32px 0 0}.contents-label{color:var(--ink-3);font-size:11px;letter-spacing:.14em;display:block;margin-bottom:9px}.contents-links{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px 18px}.contents a{text-decoration:none;color:var(--ink-2);font-size:13px;white-space:nowrap}.contents a:hover{color:var(--brand)}.contents a span{font-family:var(--mono);display:inline-block;width:29px;color:var(--brand);font-size:11px}
.chapter{padding-top:46px;scroll-margin-top:28px}.chapter+.chapter{margin-top:42px;border-top:1px solid var(--rule)}.chapter-head{display:flex;align-items:baseline;gap:15px;margin-bottom:24px}.chapter-num{color:var(--brand);font-family:var(--mono);font-size:15px;line-height:1.3;flex:none}.chapter h2{font-family:var(--serif);font-size:26px;line-height:1.45;font-weight:700;margin:0;text-wrap:pretty}.chapter h3{font-size:18px;line-height:1.6;color:var(--ink);margin:32px 0 14px;font-weight:600}.chapter-head+h3{margin-top:0}.step-heading{display:flex;gap:8px}.step-heading span{color:var(--brand);font-weight:500}.figure-intro{font-size:14px;margin-bottom:12px}ul,ol{padding-left:23px;color:var(--ink-2);margin:14px 0 22px}li{padding-left:3px;margin:7px 0}li::marker{color:var(--brand)}blockquote{margin:24px 0;padding:20px 24px;background:var(--brand-soft);border-left:3px solid var(--brand)}blockquote p{color:var(--ink);font-family:var(--serif);font-size:20px;line-height:1.75;font-weight:600}.consequence{border-left:3px solid var(--warn-rule);background:var(--warn-bg);padding:17px 21px;margin:22px 0}.consequence strong{font-weight:500}.own-business{border-top:1px dashed var(--rule);padding-top:20px;margin-top:24px}.future{margin:28px 0 0;padding:18px 23px;background:var(--note);font-size:14px;border-left:2px solid var(--rule)}.future p{margin-bottom:8px}.future ul{margin:7px 0 0}.future li{margin:4px 0}.duties{list-style:none;padding:0;counter-reset:duty;margin:20px 0 24px}.duties li{counter-increment:duty;position:relative;padding:15px 0 15px 42px;margin:0;border-top:1px solid var(--rule)}.duties li:last-child{border-bottom:1px solid var(--rule)}.duties li::before{content:'0' counter(duty);position:absolute;left:0;color:var(--brand);font:14px var(--mono);top:21px}.questions{padding-left:23px}.questions li{margin:12px 0}.questions strong{color:var(--brand)}
.table-wrap{margin:22px 0 26px}table{width:100%;border-collapse:collapse;font-size:14px;line-height:1.8;text-align:left}th{font-weight:600;color:var(--ink);background:var(--sunken);padding:12px 16px;border-bottom:1px solid var(--rule);vertical-align:top}td{padding:13px 16px;border-bottom:1px solid var(--rule);vertical-align:top;color:var(--ink-2)}tbody td:first-child{font-weight:500;color:var(--ink)}.two-col td:first-child{width:37%}.three-col th:nth-child(1){width:33%}.three-col th:nth-child(2){width:28%}.three-col th:nth-child(3){width:39%}#review td:first-child{width:22%;color:var(--brand);font-weight:600}
figure{margin:0}.flow{padding:20px 24px 22px;border:1px solid var(--rule);border-radius:9px;margin:14px 0 22px;background:var(--note)}figcaption{font-size:13px;font-weight:600;color:var(--ink);display:flex;gap:10px;align-items:center;flex-wrap:wrap;padding-bottom:18px}figcaption>span{font-size:11px;font-family:var(--mono);color:var(--brand);font-weight:400}figcaption>small{font-size:11px;font-weight:400;color:var(--ink-3);margin-left:auto}.flow-grid{display:grid;grid-template-columns:minmax(0,1fr) 104px minmax(0,1.1fr) 65px minmax(0,1fr);grid-template-rows:auto auto auto;align-items:center}.capture{grid-column:1;grid-row:1;text-align:center;font-size:11px;color:var(--ink-3);line-height:1.7;align-self:end;padding:0 0 7px}.capture>span{display:block;color:var(--ink-3);font-size:20px;line-height:1.3}.system{grid-row:2;background:var(--surface);border:1px solid var(--rule);border-top:2px solid var(--brand);padding:16px 8px;text-align:center;align-self:stretch;display:flex;flex-direction:column;justify-content:center;min-width:0}.meyer{grid-column:1}.saas{grid-column:3;background:var(--brand-soft)}.pac{grid-column:5}.system-label{color:var(--ink-3);font-size:10px;letter-spacing:.10em;line-height:1.5;margin-bottom:6px}.system>strong{font-size:18px;line-height:1.5;font-weight:600;white-space:nowrap}.system>small{font-size:11px;color:var(--ink-2);margin-top:6px;line-height:1.7}.connector{grid-row:2;text-align:center;color:var(--brand);display:flex;flex-direction:column;align-items:center;gap:8px;padding:0 5px}.connector.first{grid-column:2}.connector.second{grid-column:4}.connector>span{font-size:11px;line-height:1.6}.connector svg{width:38px;height:12px;flex:none}.connector small{font-size:10px;color:var(--ink-3);line-height:1.5}.storage{grid-column:1;grid-row:3;text-align:center;color:var(--ink-3);font-size:13px}.storage>span{display:block;line-height:1.4;font-size:20px}.storage>div{border:1px dashed var(--rule);background:var(--surface);padding:4px 10px}.storage small{font-size:11px;margin-left:5px}.mobile-only{display:none}.view-path{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:19px 20px;border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);margin:18px 0;color:var(--ink);font-size:14px;font-weight:500}.view-path b{color:var(--brand);font-size:18px;font-weight:400;line-height:1}
.sources{margin-top:44px;padding-top:25px;border-top:1px solid var(--rule);scroll-margin-top:28px;font-size:12.5px;color:var(--ink-3);line-height:1.85}.sources h2{font-size:14px;font-weight:600;margin:0 0 12px}.sources p{color:var(--ink-3);margin-bottom:13px}.sources ul{padding-left:19px;margin:14px 0 17px}.sources li{padding-left:1px;margin:8px 0;color:var(--ink-3)}.sources a{font-weight:500}.page-footer{display:flex;justify-content:space-between;gap:12px;color:var(--ink-3);font-size:11px;padding:19px 8px 0}.page-footer a{text-decoration:none;color:var(--ink-3)}.back-top{position:fixed;right:24px;bottom:22px;z-index:10;border:1px solid var(--rule);border-radius:99px;padding:8px 14px;background:var(--surface);color:var(--brand);font-size:12px;text-decoration:none;box-shadow:0 2px 16px #00000006;opacity:0;pointer-events:none;transition:opacity .2s}.back-top.visible{opacity:1;pointer-events:auto}.skip-link{position:absolute;top:-80px;left:20px;background:var(--surface);padding:10px;z-index:20}.skip-link:focus{top:10px}
@media(min-width:1440px){.wrap{padding-top:48px}}
@media(max-width:900px){.wrap{padding:26px 22px 32px}main{padding:34px 35px}.chapter h2{font-size:24px}.flow{padding:18px 16px}.flow-grid{grid-template-columns:minmax(0,1fr) 90px minmax(0,1.1fr) 56px minmax(0,1fr)}.system>strong{font-size:16px}.system>small{font-size:9px}.system-label{font-size:9px}.connector>span{font-size:9px}.connector small{font-size:8px}}
@media(max-width:660px){body{font-size:15px;line-height:1.85}.wrap{padding:22px 15px 28px}.document-header{padding:0 4px 23px}.topline{align-items:flex-start;gap:8px;margin-bottom:13px}.eyebrow{font-size:10px;letter-spacing:.04em;padding-top:7px}.tools{gap:0;flex:none}.tools button{padding:7px}.tools button span{display:none}.tools svg{width:16px;height:16px}h1 span{display:block}h1{font-size:31px;line-height:1.4;max-width:11em;text-wrap:balance;margin-bottom:13px}.meta{font-size:11px;margin-bottom:12px}.meta time{font-size:11px}.scope{font-size:13px;line-height:1.8}main{padding:27px 22px 29px;border-radius:10px}.boundary{font-size:17px;line-height:1.85;padding-left:15px;margin-bottom:21px}.principle{font-size:14px}.contents{margin-top:25px;padding:15px 0 17px}.contents-links{grid-template-columns:repeat(2,minmax(0,1fr));gap:7px 12px}.contents a{font-size:12px}.contents a span{width:25px}.chapter{padding-top:32px;scroll-margin-top:18px}.chapter+.chapter{margin-top:30px}.chapter-head{gap:10px;margin-bottom:21px}.chapter-num{font-size:12px}.chapter h2{font-size:22px;line-height:1.5}.chapter h3{font-size:16px;margin-top:28px}.chapter-head+h3{margin-top:0}.consequence{padding:14px 16px}.chapter blockquote{padding:16px 18px;margin:22px 0}.chapter blockquote p{font-size:18px;line-height:1.8}.table-wrap{margin:22px 0}.table-wrap thead{display:none}.table-wrap table,.table-wrap tbody{display:block}.table-wrap tr{display:block;padding:13px 0;border-bottom:1px solid var(--rule)}.table-wrap tr:first-child{border-top:2px solid var(--brand)}.table-wrap td{display:block;padding:3px 0;border:0;width:auto!important;line-height:1.85;font-size:13px}.table-wrap td:first-child{font-size:14px;font-weight:600;padding:0 0 6px;color:var(--ink)}.three-col td:not(:first-child){display:grid;grid-template-columns:6.4em 1fr;gap:10px}.three-col td:not(:first-child)::before{content:attr(data-label);font-size:11px;color:var(--ink-3);padding-top:2px}#review td:first-child{color:var(--brand)}.flow{padding:16px;margin:13px 0 20px}figcaption{font-size:12px;gap:8px;padding-bottom:18px}figcaption>small{display:block;flex-basis:100%;font-size:10px;margin:0}.flow-grid{display:flex;flex-direction:column;gap:0}.capture{font-size:11px;align-self:center;padding-bottom:4px}.system{align-self:stretch;padding:14px;min-height:95px}.system>strong{font-size:19px}.system>small{font-size:11px}.system-label{font-size:10px;margin-bottom:3px}.connector{padding:10px 0;gap:4px}.connector svg{transform:rotate(90deg);width:28px;height:12px;margin:6px 0}.connector>span{font-size:11px}.connector>span br{display:none}.connector small{font-size:10px}.storage{margin-top:16px;align-self:stretch;font-size:12px}.storage>span{display:none}.storage>div{padding:7px 5px;background:transparent}.storage small{font-size:11px}.mobile-only{display:inline;font-weight:400}.view-path{flex-direction:column;gap:7px;padding:16px;font-size:13px;align-items:flex-start}.view-path b{transform:rotate(90deg);margin-left:7px;font-size:17px;line-height:1.1}.duties li{padding-left:33px}.duties li::before{font-size:12px;top:20px}.future{font-size:13px;padding:15px 17px}.sources{margin-top:32px;font-size:11.5px}.sources h2{font-size:13px}.page-footer{font-size:10px;flex-direction:column;gap:3px;padding:15px 4px 0}.back-top{right:12px;bottom:12px;font-size:11px;padding:6px 11px}}
@media(max-width:350px){.wrap{padding-inline:10px}main{padding-inline:17px}h1{font-size:29px}.eyebrow{font-size:9px}.boundary{font-size:16px}.chapter h2{font-size:20px}.flow{padding-inline:12px}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition:none!important}}
@page{size:A4;margin:16mm 17mm 17mm}
@media print{html{scroll-behavior:auto}:root,:root[data-theme=dark]{color-scheme:light;--ground:#fff;--surface:#fff;--sunken:#edf0f6;--ink:#0f1b33;--ink-2:#33415a;--ink-3:#69758a;--brand:#0032a0;--brand-soft:#edf1fa;--rule:#d5dce9;--note:#f8f9fc;--warn-bg:#fffaf0;--warn-rule:#c1a26b}body{background:white;font-size:10pt;line-height:1.75;-webkit-print-color-adjust:exact;print-color-adjust:exact}.wrap{padding:0;max-width:none}.document-header{padding:0 0 17pt}.topline{margin-bottom:9pt}.eyebrow{font-size:8pt}h1{font-size:25pt;margin-bottom:8pt}.meta{margin-bottom:7pt;font-size:8pt}.meta time{font-size:8pt}.scope{font-size:9pt}.tools,.back-top,.skip-link{display:none!important}main{padding:0;border-radius:0}.boundary{font-size:11.5pt;margin-bottom:13pt;padding-left:12pt}.principle{font-size:9.5pt;margin-bottom:17pt}.contents{margin-top:17pt;padding:10pt 0}.contents-links{grid-template-columns:repeat(3,1fr);gap:4pt 10pt}.contents a{font-size:8pt}.contents-label{font-size:7pt;margin-bottom:5pt}.chapter{padding-top:24pt}.chapter+.chapter{margin-top:23pt}.chapter-head{gap:10pt;margin-bottom:13pt;break-after:avoid}.chapter h2{font-size:17pt;line-height:1.45}.chapter-num{font-size:10pt}.chapter h3{font-size:11.5pt;margin:19pt 0 9pt;break-after:avoid}.chapter-head+h3{margin-top:0}p{margin-bottom:10pt;orphans:3;widows:3}li{margin:4pt 0}ul,ol{margin:9pt 0 13pt}blockquote{margin:13pt 0;padding:12pt 16pt;break-inside:avoid}blockquote p{font-size:12pt}.consequence{padding:10pt 14pt;margin:12pt 0;break-inside:avoid}.figure-intro{font-size:9pt;break-after:avoid;margin-bottom:7pt}.flow{margin:8pt 0 13pt;padding:12pt 14pt;break-inside:avoid}.flow-grid{grid-template-columns:minmax(0,1fr) 85px minmax(0,1.1fr) 55px minmax(0,1fr)}figcaption{font-size:8pt;padding-bottom:12pt}figcaption>span{font-size:7pt}figcaption>small{font-size:7pt}.capture{font-size:7pt}.system{padding:10pt 5pt}.system-label{font-size:6.5pt}.system>strong{font-size:12pt}.system>small{font-size:6.5pt}.connector>span{font-size:6.5pt}.connector small{font-size:5.5pt}.storage{font-size:8pt}.storage small{font-size:7pt}.view-path{font-size:8.5pt;padding:12pt 10pt;break-inside:avoid;margin:11pt 0}.table-wrap{margin:13pt 0 16pt;break-inside:avoid}table{font-size:8.5pt;line-height:1.65}th{padding:8pt 10pt}td{padding:8pt 10pt}tr{break-inside:avoid}.duties{break-inside:avoid}.duties li{padding:9pt 0 9pt 29pt}.duties li::before{font-size:9pt;top:13pt}.future{font-size:8.5pt;break-inside:avoid;padding:12pt 15pt;margin-top:17pt}.own-business{padding-top:12pt;margin-top:15pt}.sources{font-size:8pt;line-height:1.75;margin-top:25pt;padding-top:17pt}.sources h2{font-size:9.5pt;break-after:avoid}.sources li{margin:6pt 0}.sources p{margin-bottom:9pt}.page-footer{font-size:7pt;padding-top:15pt}a{color:inherit;text-decoration:none}.sources a{text-decoration:underline;text-decoration-color:#b9c3d8}.questions{break-inside:avoid;break-after:avoid}.review-conclusion{break-before:avoid}.table-wrap:has(+p){break-after:auto}.keep-next{break-after:avoid}}
.diagram-desktop{display:block;width:100%;height:auto;color:var(--ink);font-family:var(--sans)}
.diagram-desktop .node{fill:var(--surface);stroke:var(--rule);stroke-width:1.3}
.diagram-desktop .hub{fill:var(--brand-soft);stroke:var(--brand)}
.diagram-desktop .edge{stroke:var(--brand);stroke-width:1.5;fill:none;marker-end:url(#arrow)}
.diagram-desktop .title{fill:var(--ink);font-size:19px;font-weight:600}
.diagram-desktop .sub{fill:var(--ink-2);font-size:12px}
.diagram-desktop .label{fill:var(--ink-2);font-size:13px}
.diagram-mobile{display:none}.contents a{white-space:normal}.sources a{overflow-wrap:anywhere}
@media screen and (max-width:660px){.diagram-desktop{display:none}.diagram-mobile{display:block}.route{padding:13px 0;border-top:1px solid var(--rule);font-size:13px;line-height:1.85}.route:first-child{padding-top:0;border-top:0}.route:last-child{padding-bottom:0}.route strong{display:block;color:var(--brand);font-size:14px;margin-bottom:3px}.route span{color:var(--ink-2)}.table-wrap td+td:before{content:attr(data-label) ":";color:var(--ink-3);font-size:11px}.chapter h2{font-size:21px}}
@media print{body{font-size:9.5pt;line-height:1.7}.chapter{padding-top:16pt}.chapter+.chapter{margin-top:14pt}.sources{margin-top:14pt;padding-top:10pt}.sources ul{margin:7pt 0}.sources li{margin:3pt 0}.sources p{margin-bottom:6pt}.chapter p{margin-bottom:8pt}.chapter h3{margin-top:14pt}.chapter-head{margin-bottom:10pt}.diagram-desktop{display:block!important;max-height:190pt}.diagram-mobile{display:none!important}.contents{break-inside:avoid}.sources{break-inside:avoid}.chapter-head,h3{break-after:avoid}.chapter h2{font-size:16pt}.flow{break-inside:avoid}.two-col tr{break-inside:avoid}}
</style></head><body>
<aside role="note" style="padding:12px 20px;background:#fff4da;color:#594100;border-bottom:1px solid #e9cf8d;font:14px/1.7 sans-serif">历史评审稿,2026-10-22 归档。事件推送方案未被采用;现行实现按诊所分页轮询并批量查询分析。<a href="../../../apps/pac-service/src/integrations/meyer/README.md">查看当前采集说明</a></aside><a class="skip-link" href="#main">跳到正文</a><div class="wrap" id="top">
<header class="document-header"><div class="topline"><div class="eyebrow">美亚 × FridaySaaS × PAC</div><div class="tools" aria-label="文档工具"><button type="button" id="theme-button" aria-label="切换深浅色" aria-pressed="false" title="切换深浅色"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 4a8 8 0 0 1 0 16Z" fill="currentColor" stroke="none"/></svg><span>深浅色</span></button><button type="button" id="print-button" aria-label="打印或另存为 PDF" title="打印或另存为 PDF"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M6 9V3h12v6M6 18H3v-8h18v8h-3M6 14h12v7H6Z"/></svg><span>打印</span></button></div></div><h1><span>影像与分析数据</span><span>方案设计</span></h1><div class="meta"><span class="version">评审修订稿</span><span>v0.4</span><span aria-hidden="true">·</span><time datetime="2026-10-19">2026-10-19</time></div><p class="scope">本稿确认方案方向与系统边界,具体实现另行设计。</p></header>
<main id="main"><div class="opening"><p class="boundary"><strong>整体边界:美亚管理影像资产并提供影像算法能力,PAC 承担患者分析层,FridaySaaS 承担应用消费层。PAC 直接对接美亚的授权和数据接口,向 FridaySaaS 开放统一的患者分析能力。</strong></p><p class="principle">判断依据是:<strong>数据由各自的权威系统负责,分析由 PAC 统一组织,应用围绕结果开展业务。</strong> FridaySaaS 定义业务患者和组织归属,美亚维护影像资产及绑定关系,PAC 校验对应关系、留存依据并形成分析。三个系统可以使用同一份关联,但不能各自猜测患者身份或独立修正归属。</p></div><nav class="contents" id="contents" aria-label="文档目录"><span class="contents-label">目录</span><div class="contents-links"><a href="#relationship"><span>01</span>整体关系</a><a href="#meyer"><span>02</span>美亚</a><a href="#saas"><span>03</span>FridaySaaS</a><a href="#pac"><span>04</span>PAC</a><a href="#review"><span>05</span>当前方案与范围</a><a href="#sources"><span>附</span>依据与范围</a></div></nav><section class="chapter" id="relationship" aria-labelledby="heading-1"><div class="chapter-head"><span class="chapter-num">01</span><h2 id="heading-1">整体关系:采集呈现、患者分析、业务应用分工</h2></div><p>FridaySaaS 沿用现有美亚接入,同步患者、诊所和就诊信息,配合影像采集并提供阅片入口。PAC 直接获取美亚影像与分析,结合病历、治疗等患者事实,向 SaaS 输出分析能力。</p><figure aria-labelledby="flow-caption" class="flow"><figcaption id="flow-caption"><span>图 01</span>采集、分析与应用的关系<small>目标链路 · 美亚新影像启用时</small></figcaption>
<svg aria-labelledby="diagram-title diagram-desc" class="diagram-desktop" role="img" viewbox="0 45 840 380">
<title id="diagram-title">美亚、FridaySaaS 与 PAC 的职责及数据流</title><desc id="diagram-desc">诊所设备向美亚采集影像,美亚使用 OSS 存储原片。FridaySaaS 向美亚同步患者、诊所与就诊,向 PAC 提供患者身份与业务数据。美亚向 PAC 实时推送新增影像通知。PAC 直接授权访问美亚影像、批量查询分析,并向 SaaS 输出分析结果、依据与状态。</desc>
<defs><marker id="arrow" markerheight="6" markerwidth="6" orient="auto-start-reverse" refx="9" refy="5" viewbox="0 0 10 10"><path d="M1 1L9 5L1 9" fill="none" stroke="var(--brand)" stroke-width="1.5"></path></marker></defs>
<path class="edge" d="M180 115H325"></path><path class="edge" d="M515 115H660"></path>
<text class="label" text-anchor="middle" x="252" y="101">影像采集</text><text class="label" text-anchor="middle" x="588" y="101">原片存储</text>
<path class="edge" d="M175 300L365 160"></path><path class="edge" d="M625 300L435 160"></path><path class="edge" d="M510 160L700 300"></path>
<text class="label" text-anchor="middle" x="183" y="218"><tspan x="183">同步患者、诊所</tspan><tspan dy="20" x="183">与就诊</tspan></text>
<text class="label" text-anchor="middle" x="430" y="240"><tspan x="430">授权访问影像</tspan><tspan dy="20" x="430">批量查询分析</tspan></text><text class="label" text-anchor="middle" x="716" y="208"><tspan x="716">实时推送</tspan><tspan dy="20" x="716">新增影像通知</tspan></text>
<path class="edge" d="M290 325H550"></path><path class="edge" d="M550 382H290"></path>
<text class="label" text-anchor="middle" x="420" y="311">患者身份与业务数据</text><text class="label" text-anchor="middle" x="420" y="368">分析结果、依据与状态</text>
<rect class="node" height="90" rx="6" width="160" x="20" y="70"></rect><text class="title" style="font-size:16px" text-anchor="middle" x="100" y="110">诊所设备</text><text class="sub" text-anchor="middle" x="100" y="135">与前置机</text>
<rect class="node" height="90" rx="6" width="190" x="325" y="70"></rect><text class="title" text-anchor="middle" x="420" y="110">美亚 PACS</text><text class="sub" text-anchor="middle" x="420" y="135">影像资产 · 阅片 · 影像算法</text>
<rect class="node" height="90" rx="6" width="160" x="660" y="70"></rect><text class="title" text-anchor="middle" x="740" y="110">OSS</text><text class="sub" text-anchor="middle" x="740" y="135">原片存储</text>
<rect class="node" height="102" rx="6" width="230" x="60" y="300"></rect><text class="title" text-anchor="middle" x="175" y="344">FridaySaaS</text><text class="sub" text-anchor="middle" x="175" y="372">业务管理 · 影像呈现 · 应用消费</text>
<rect class="node hub" height="102" rx="6" width="230" x="550" y="300"></rect><text class="title" text-anchor="middle" x="665" y="344">PAC</text><text class="sub" text-anchor="middle" x="665" y="372">数据接入 · 患者分析 · 开放输出</text>
</svg>
<div aria-label="系统关系" class="diagram-mobile"><div class="route"><strong>诊所设备 → 美亚 → OSS</strong><span>采集影像,管理与存储原片</span></div><div class="route"><strong>FridaySaaS → 美亚</strong><span>同步患者、诊所与就诊</span></div><div class="route"><strong>FridaySaaS → PAC</strong><span>提供患者身份与业务数据</span></div><div class="route"><strong>美亚 → PAC</strong><span>实时推送新增影像通知</span></div><div class="route"><strong>PAC → 美亚</strong><span>授权访问影像,批量查询分析</span></div><div class="route"><strong>PAC → FridaySaaS</strong><span>输出分析结果、依据与状态</span></div></div></figure><p>FridaySaaS 在患者详情、接诊、客服等场景使用 PAC 的分析。<strong>召回只是其中一个场景,患者是否进入召回计划不应决定其能否获得分析。</strong></p><p>查看原片继续走 SaaS 阅片入口,PAC 工作台可沿用宿主槽位;PAC 为分析取片则直接访问美亚。<strong>如果分析依赖用户打开页面,没人查看的影像就可能被漏掉;如果每次打开页面才取数并计算,响应又会受外部服务和算法耗时影响。</strong> 因此,后台持续获取和分析,页面按需读取结果、查看原片。</p></section><section class="chapter" id="meyer" aria-labelledby="heading-2"><div class="chapter-head"><span class="chapter-num">02</span><h2 id="heading-2">美亚:实时通知新增影像,分析结果延后获取</h2></div><p>根据美亚联调回复及后续沟通,已确认:</p><div class="table-wrap"><table class="two-col">
<thead>
<tr>
<th scope="col">已确认信息</th>
<th scope="col">对方案的影响</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="已确认信息">影像数据只创建,不修改、不删除</td>
<td data-label="对方案的影响">按新增采集与去重,不设计影像修改、删除的同步链路</td>
</tr>
<tr>
<td data-label="已确认信息">影像生成后实时推送,接收方提供回调地址</td>
<td data-label="对方案的影响">PAC 提供回调入口,直接接收新增影像通知</td>
</tr>
<tr>
<td data-label="已确认信息">上传后后台识别病症,通常约 3–5 分钟,高峰预计仍为分钟级</td>
<td data-label="对方案的影响">影像通知与分析结果并非同时到达;该时间不是完成时限承诺</td>
</tr>
<tr>
<td data-label="已确认信息">分析接口将支持批量查询;正常查询无数据时,美亚说明算法仍在处理中</td>
<td data-label="对方案的影响">批量获取结果,未取得结果的后续补拉,不要求完整分析状态接口</td>
</tr>
<tr>
<td data-label="已确认信息">病症分析目前仅支持全景片,CBCT 暂不支持</td>
<td data-label="对方案的影响">对不支持的类型不反复补拉病症分析</td>
</tr>
</tbody>
</table></div><p><strong>实时通知解决“发现新影像”,延后补拉解决“取得晚到分析”。</strong> 如果收到通知时只查一次,尚未生成的分析就可能被漏掉;没有取得结果,也不能解释为没有发现问题。</p></section><section class="chapter" id="saas" aria-labelledby="heading-3"><div class="chapter-head"><span class="chapter-num">03</span><h2 id="heading-3">FridaySaaS:做好业务身份、影像呈现和分析消费</h2></div><p>SaaS 负责采集接入和呈现,向 PAC 提供患者业务数据及授权上下文,再消费分析结果。<strong>无需为了转交 PAC,再建设一套美亚分析采集和重推链路。</strong> 否则同一份分析要经过两套同步过程,既重复维护,也增加故障定位的环节。</p><p>SaaS 保留自身业务所需的关联和操作记录。医生采纳建议、客服据此跟进时,应记录引用的分析版本及必要内容。<strong>否则分析更新后,就难以还原当时为什么做出那次业务操作。</strong> 分析依据和版本由 PAC 管理,业务执行由 SaaS 管理。</p><p>新老影像功能可以保留,实际择一启用:旧影像沿用 SaaS 数据通路,美亚影像由 PAC 直连获取,来源差异由 PAC 接入层统一。<strong>应用不应随影像来源切换而重新适配;同一张片迁入美亚,也不应被当成两份独立依据。</strong></p></section><section class="chapter" id="pac" aria-labelledby="heading-4"><div class="chapter-head"><span class="chapter-num">04</span><h2 id="heading-4">PAC:统一分析,留存依据,对应用负责</h2></div><h3>① 接入归一,身份与权限沿用业务边界</h3><p>美亚接入由 PAC 独立适配层负责,转换为 PAC 标准数据后用于分析。患者对应关系以 SaaS 业务身份和美亚绑定为依据,缺失或冲突时不猜测匹配。</p><p>PAC 负责美亚服务授权;用户能查看哪些患者和分析,仍依据 SaaS 的业务授权,由 PAC 校验执行。<strong>服务能读取多家诊所,不代表每个调用方都有权访问这些患者。</strong></p><h3>② 留存分析依据,原片继续由美亚管理</h3><p>PAC 保存影像关联、原始分析依据和自身分析结果,并保留来源、版本及数据时效。<strong>如果每次都临时向美亚取结果,同一份业务数据重放时可能取得不同内容,就无法解释当时为什么得出那个判断。</strong></p><p>原片仍存于美亚/OSS,由 PAC 按需授权访问。美亚暂时不可用时,PAC 仍能提供已留存的结果及依据,并说明数据截至时间;原片访问和最新分析获取则可能受影响。</p><h3>③ 区分来源,开放统一的患者分析能力</h3><p>PAC 可以使用美亚已有的算法结果,也可按需要获取原片、调用其他分析服务,再结合患者事实形成综合分析。承担分析层不要求底层影像算法全部自研。</p><p><strong>美亚发现了什么、PAC 综合判断了什么、医生确认了什么,应分别标明来源和依据。</strong> 否则算法发现容易被误当成医生诊断,原始结果变化时也难以追溯受影响的结论。</p><p>对已接入且获授权的患者,PAC 向应用提供分析结论、依据、版本和状态。<strong>未取得分析结果不代表没有发现问题;PAC 只表达已知的结果可用性与能力范围,不推断美亚内部处理状态。</strong> SaaS 使用这些结果开展业务;结果回流时也应保留来源,避免同一结论被重复当成独立依据。</p></section><section class="chapter" id="review" aria-labelledby="heading-5"><div class="chapter-head"><span class="chapter-num">05</span><h2 id="heading-5">当前方案与范围</h2></div><p><strong>新增影像实时通知 PAC → 留存影像记录 → 批量查询分析 → 有结果保存,无结果延后补拉。</strong> 回调确认以通知可靠落库为界,不等待分析完成。接入前的历史影像另做首次采集。</p></section><aside class="sources" id="sources" aria-labelledby="sources-title"><h2 id="sources-title">依据与范围</h2><p>本稿依据本轮评审原则、2026-10-19 美亚联调回复及后续确认,以及既有代码和本地联调记录。直连取数已有验证基础,完整分析服务仍需后续设计与实现。</p><p>参考资料:<span title="本机参考文件,未随归档分发">系统集成方案</span>、<span title="本机参考文件,未随归档分发">私有化部署方案</span>、<span title="本机参考文件,未随归档分发">接口对接文档</span>。</p><p>参考资料链接指向本机原件;分享本文时可一并提供原 PDF。</p></aside></main><footer class="page-footer"><span>美亚 × FridaySaaS × PAC · 影像与分析数据方案设计</span><a href="#top">评审修订稿 v0.4 · 返回页首 ↑</a></footer></div><a class="back-top" href="#contents" aria-label="返回文档目录">目录 ↑</a>
<script>
(()=>{
const root=document.documentElement, themeButton=document.getElementById('theme-button'), key='imaging-document-theme';
const scheme=matchMedia('(prefers-color-scheme: dark)');
const isDark=()=>root.dataset.theme?root.dataset.theme==='dark':scheme.matches;
const update=()=>themeButton.setAttribute('aria-pressed',String(isDark()));
try{const saved=localStorage.getItem(key);if(saved==='dark'||saved==='light')root.dataset.theme=saved;}catch{}
update(); scheme.addEventListener('change',update);
themeButton.addEventListener('click',()=>{const theme=isDark()?'light':'dark';root.dataset.theme=theme;try{localStorage.setItem(key,theme)}catch{}update()});
document.getElementById('print-button').addEventListener('click',()=>window.print());
const back=document.querySelector('.back-top');const check=()=>{const visible=scrollY>700;back.classList.toggle('visible',visible);back.tabIndex=visible?0:-1;back.setAttribute('aria-hidden',String(!visible))};
addEventListener('scroll',check,{passive:true});check();
})();
</script></body></html>
# 美亚 × FridaySaaS × PAC:影像与分析数据方案设计
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。 原方案中的影像事件推送未被采用,当前实现按诊所分页轮询并批量查询分析。
> 评审修订稿 v0.4 · 2026-10-19
> 本稿确认方案方向与系统边界,具体实现另行设计。
**整体边界:美亚管理影像资产并提供影像算法能力,PAC 承担患者分析层,FridaySaaS 承担应用消费层。PAC 直接对接美亚的授权和数据接口,向 FridaySaaS 开放统一的患者分析能力。**
判断依据是:**数据由各自的权威系统负责,分析由 PAC 统一组织,应用围绕结果开展业务。** FridaySaaS 定义业务患者和组织归属,美亚维护影像资产及绑定关系,PAC 校验对应关系、留存依据并形成分析。三个系统可以使用同一份关联,但不能各自猜测患者身份或独立修正归属。
## 1. 整体关系:采集呈现、患者分析、业务应用分工
FridaySaaS 沿用现有美亚接入,同步患者、诊所和就诊信息,配合影像采集并提供阅片入口。PAC 直接获取美亚影像与分析,结合病历、治疗等患者事实,向 SaaS 输出分析能力。
```mermaid
flowchart TB
E[诊所设备与前置机] --> M["美亚 PACS<br/>影像资产、阅片、影像算法"]
M --> O[OSS 原片存储]
S["FridaySaaS<br/>业务管理、影像呈现、应用消费"] -->|同步患者、诊所与就诊| M
S -->|患者身份与业务数据| P["PAC<br/>数据接入、患者分析、开放输出"]
M -->|实时推送新增影像通知| P
P -->|直接授权访问影像、批量查询分析| M
P -->|分析结果、依据与状态| S
```
FridaySaaS 在患者详情、接诊、客服等场景使用 PAC 的分析。**召回只是其中一个场景,患者是否进入召回计划不应决定其能否获得分析。**
查看原片继续走 SaaS 阅片入口,PAC 工作台可沿用宿主槽位;PAC 为分析取片则直接访问美亚。**如果分析依赖用户打开页面,没人查看的影像就可能被漏掉;如果每次打开页面才取数并计算,响应又会受外部服务和算法耗时影响。** 因此,后台持续获取和分析,页面按需读取结果、查看原片。
## 2. 美亚:实时通知新增影像,分析结果延后获取
根据美亚联调回复及后续沟通,已确认:
| 已确认信息 | 对方案的影响 |
|---|---|
| 影像数据只创建,不修改、不删除 | 按新增采集与去重,不设计影像修改、删除的同步链路 |
| 影像生成后实时推送,接收方提供回调地址 | PAC 提供回调入口,直接接收新增影像通知 |
| 上传后后台识别病症,通常约 3–5 分钟,高峰预计仍为分钟级 | 影像通知与分析结果并非同时到达;该时间不是完成时限承诺 |
| 分析接口将支持批量查询;正常查询无数据时,美亚说明算法仍在处理中 | 批量获取结果,未取得结果的后续补拉,不要求完整分析状态接口 |
| 病症分析目前仅支持全景片,CBCT 暂不支持 | 对不支持的类型不反复补拉病症分析 |
**实时通知解决“发现新影像”,延后补拉解决“取得晚到分析”。** 如果收到通知时只查一次,尚未生成的分析就可能被漏掉;没有取得结果,也不能解释为没有发现问题。
## 3. FridaySaaS:做好业务身份、影像呈现和分析消费
SaaS 负责采集接入和呈现,向 PAC 提供患者业务数据及授权上下文,再消费分析结果。**无需为了转交 PAC,再建设一套美亚分析采集和重推链路。** 否则同一份分析要经过两套同步过程,既重复维护,也增加故障定位的环节。
SaaS 保留自身业务所需的关联和操作记录。医生采纳建议、客服据此跟进时,应记录引用的分析版本及必要内容。**否则分析更新后,就难以还原当时为什么做出那次业务操作。** 分析依据和版本由 PAC 管理,业务执行由 SaaS 管理。
新老影像功能可以保留,实际择一启用:旧影像沿用 SaaS 数据通路,美亚影像由 PAC 直连获取,来源差异由 PAC 接入层统一。**应用不应随影像来源切换而重新适配;同一张片迁入美亚,也不应被当成两份独立依据。**
## 4. PAC:统一分析,留存依据,对应用负责
**① 接入归一,身份与权限沿用业务边界**
美亚接入由 PAC 独立适配层负责,转换为 PAC 标准数据后用于分析。患者对应关系以 SaaS 业务身份和美亚绑定为依据,缺失或冲突时不猜测匹配。
PAC 负责美亚服务授权;用户能查看哪些患者和分析,仍依据 SaaS 的业务授权,由 PAC 校验执行。**服务能读取多家诊所,不代表每个调用方都有权访问这些患者。**
**② 留存分析依据,原片继续由美亚管理**
PAC 保存影像关联、原始分析依据和自身分析结果,并保留来源、版本及数据时效。**如果每次都临时向美亚取结果,同一份业务数据重放时可能取得不同内容,就无法解释当时为什么得出那个判断。**
原片仍存于美亚/OSS,由 PAC 按需授权访问。美亚暂时不可用时,PAC 仍能提供已留存的结果及依据,并说明数据截至时间;原片访问和最新分析获取则可能受影响。
**③ 区分来源,开放统一的患者分析能力**
PAC 可以使用美亚已有的算法结果,也可按需要获取原片、调用其他分析服务,再结合患者事实形成综合分析。承担分析层不要求底层影像算法全部自研。
**美亚发现了什么、PAC 综合判断了什么、医生确认了什么,应分别标明来源和依据。** 否则算法发现容易被误当成医生诊断,原始结果变化时也难以追溯受影响的结论。
对已接入且获授权的患者,PAC 向应用提供分析结论、依据、版本和状态。**未取得分析结果不代表没有发现问题;PAC 只表达已知的结果可用性与能力范围,不推断美亚内部处理状态。** SaaS 使用这些结果开展业务;结果回流时也应保留来源,避免同一结论被重复当成独立依据。
## 5. 当前方案与范围
**新增影像实时通知 PAC → 留存影像记录 → 批量查询分析 → 有结果保存,无结果延后补拉。** 回调确认以通知可靠落库为界,不等待分析完成。接入前的历史影像另做首次采集。
---
### 依据与范围
本稿依据本轮评审原则、2026-10-19 美亚联调回复及后续确认,以及既有代码和本地联调记录。直连取数已有验证基础,完整分析服务仍需后续设计与实现。
参考资料:系统集成方案(本机参考文件 `瑞尔口腔影像中心PACS项目系统集成方案v0.4.pdf`,未随归档分发)、私有化部署方案(本机参考文件 `瑞尔PACS影像中心私有化部署方案v0.1.pdf`,未随归档分发)、接口对接文档(本机参考文件 `PACS_瑞尔接口对接文档.pdf`,未随归档分发)。
# 公司数仓的定位与 PAC 的职责边界
> 历史归档(2026-10-22):保留原记录日期的方案、样本和验收结论,不代表当前运行状态;现行入口见本目录索引。
> 架构讨论稿 · 2026-10-20
**公司需要独立、可复用的数据能力。以 PAC 兼任公司级数据底座,是满足当前业务的过渡方案,不能作为长期的公司数仓定位。**
过渡的是 PAC 代为承担的公共数据职责;患者分析、行动判断与执行协作,仍然是 PAC 可以长期发展的产品能力。
## 1. 数仓是什么:公司的公共数据基础
数仓持续整合不同系统、不同业务的数据,形成**定义一致、来源可追溯、质量可核对、能够重复使用**的公共数据,服务经营分析、报表、算法和业务应用。
它的价值体现在三个方面:
- **整合**:患者、诊疗、收费、营销、人员、门店等数据能够关联使用。
- **一致**:身份、时间、状态和指标有明确口径,减少各部门各算一套。
- **复用**:一次可靠接入和公共加工,可以支持多个消费者。
数仓需要独立的数据模型和治理责任。把业务库集中复制到另一个数据库,只完成了数据汇集;还需要整合语义、明确质量和使用规则。
业务系统继续维护自己的记录并办理业务。数仓通常通过同步取得数据,不要求预约、收费、写病历等日常操作经过数仓。
## 2. 公司为什么需要:让数据服务多个业务
公司需要回答的问题已经超出单一患者场景:渠道带来的患者是否到诊、治疗和收费如何衔接、不同门店和人员的表现是否可比。这些问题需要跨系统的数据和共同口径。
如果每个产品独立取数、清洗和解释,同一份数据就会产生多套加工逻辑。新增应用、源系统变更和历史补数,都会重复付出成本;结果不一致时,也难以确定谁负责。
**建设时机取决于复用和治理需求,不只取决于数据量。** 多个消费者反复使用同一批数据、口径冲突持续出现、跨系统分析成为日常工作时,就应明确公共数据能力的建设责任。
这不意味着立即建设覆盖全公司的大型平台。可以从已有重复需求开始,逐步形成公共能力;前提是有人持续负责定义、质量和交付。
## 3. PAC 当前承担了什么:为患者应用补齐数据条件
PAC 已包含多源接入、字段与语义归一、来源留存、事实版本、画像及计划更新等能力,具备部分数据仓储与治理特征。当前主要业务落点是客户召回。
这些能力首先服务于 PAC:把已接入的患者记录转化为可解释的事实,支持画像、机会判断、工作分配和跟进。
**有数据加工和事实存储,不等于具备公司级数仓的覆盖范围与服务责任。** PAC 中某条记录可供召回判断,也不意味着它已经满足财务统计、经营分析或其他产品的全部要求。
## 4. 为什么只能过渡:应用边界不能替代公司数据边界
| 局限 | 对公司的影响 |
|---|---|
| 数据覆盖随患者应用需求选择 | PAC 已接入的数据,不能代表全公司的业务数据已完整覆盖 |
| 数据语义和加工围绕患者判断组织 | 其他业务仍需核对粒度、状态与统计口径,不能直接照用应用结果 |
| 原文与版本留存在已采集范围内 | 重放可以重处理已有记录,无法恢复从未接入的数据 |
| 数据交付与应用运行相互耦合 | 多个消费者长期依赖后,公共补数、质量和变更管理会挤占产品迭代,并扩大故障影响 |
继续无边界扩充 PAC,会使其同时承担公共数据供应和患者业务交付。两类责任的消费者、覆盖范围、质量要求和变更节奏不同,需要分别管理。
## 5. 长期边界:记录、公共数据与业务判断分别负责
| 角色 | 核心责任 |
|---|---|
| **源业务系统** | 维护权威业务记录,办理业务操作,明确数据及其变更含义 |
| **公司数仓/公共数据能力** | 可靠整合、公共身份与口径、历史留存、来源追溯、质量核对及共享数据交付 |
| **PAC** | 患者事实的领域解释、画像、机会与优先级判断、行动计划、分配和反馈 |
“单一可信源”应落实为明确的权威分工:业务事实以对应源系统为准,公共分析使用经过治理的数据和指标,PAC 的判断与行动状态由 PAC 管理。无需把所有读写集中到同一个数据库。
公共数据模型应表达可复用的业务含义;源系统差异在接入与加工中处理,应用特有判断留在应用边界内。公共模型可以演进,但不应随某个来源的表结构或某个应用的临时需求任意变化。
数据完整性和正确性也需要分工:源系统负责提供明确、可靠的记录,公共数据能力负责同步与加工质量,PAC 负责自身判断及证据使用。数仓无法自动消除源端缺失或含义不明的问题。
## 6. 过渡原则:沉淀公共能力,保留产品价值
- **当前可继续交付**:PAC 在明确数据范围和质量条件下提供患者分析与召回能力,不必等待完整数仓建成。
- **公共能力逐步独立**:优先沉淀被多个消费者重复需要的接入、归一、追溯和质量核对,明确责任人与交付约定。
- **迁移按数据范围推进**:公共数据具备可验证的完整性、时效和语义后,PAC 再逐步切换,避免同一数据长期存在相互冲突的加工路径。
- **产品职责持续保留**:数仓完善后,PAC 仍维护自己的分析、计划和执行状态,并对患者相关判断负责。
外部公司的同类数据也按此原则接入:主要供 PAC 使用时,可以直接进入其接入流程;需要跨产品复用时,应纳入公共数据能力,并保留来源、授权范围及组织隔离。
**目标是让公司获得稳定的数据资产,让 PAC 集中解决患者相关的判断与行动问题。是否独立部署、采用何种数据库及如何建表,属于后续设计。**
---
### 依据
- 当前 PAC 的[架构总览](../../../apps/pac-docs/content/docs/architecture/overview.mdx)、[三层模型](../../../apps/pac-docs/content/docs/architecture/three-layer-model.mdx)与[产品概述](../../../apps/pac-docs/content/docs/start/what-is-pac.mdx)。
- [DataWorks 数仓分层](https://www.alibabacloud.com/help/en/dataworks/user-guide/data-warehouse-layering):源数据、公共加工与应用服务的职责区分。
# 2026 年 10 月运维验收与架构讨论归档
2026-10-22 整理。保存 11 份独有文档,包含历史发布记录、数仓定位讨论及影像方案的不同评审版本。
## 现行入口
- [美亚采集器](../../../apps/pac-service/src/integrations/meyer/README.md)
- [患者事实查询 API](../../../apps/pac-docs/content/docs/api/open/PatientFactsLookupController_lookup.mdx)
- [PAC 产品概述](../../../apps/pac-docs/content/docs/start/what-is-pac.mdx)
- [运维说明](../../operations/README.md)
- [美亚与患者事实开发历史](../2026-10-meyer-and-patient-facts/README.md)
## 归档清单
| 文件 | 内容 |
| --- | --- |
| [2026-10-14-push-latency-local.md](2026-10-14-push-latency-local.md) | Push 优化及测试、生产验收;含此前未提交的生产验收补充 |
| [2026-10-14-return-visit-push-fix-test.md](2026-10-14-return-visit-push-fix-test.md) | 回访推送修复、单条重放和发布验收 |
| [2026-10-18-business-date-shanghai-test-validation.md](2026-10-18-business-date-shanghai-test-validation.md) | 北京业务日期修复及跨时区验证 |
| [2026-10-18-jvs-complaint-ingestion-test-validation.md](2026-10-18-jvs-complaint-ingestion-test-validation.md) | 投诉摄入测试发布与真实样本验收 |
| [2026-10-18-jvs-complaint-ingestion-prod-validation.md](2026-10-18-jvs-complaint-ingestion-prod-validation.md) | 投诉摄入生产发布与真实样本验收 |
| [2026-10-20-data-warehouse-and-pac-positioning.md](2026-10-20-data-warehouse-and-pac-positioning.md) | 数仓与 PAC 的职责边界讨论 |
| [2026-10-16-meyer-friday-pac-imaging-review.md](2026-10-16-meyer-friday-pac-imaging-review.md) | 影像早期评审稿 v0.2 |
| [2026-10-16-meyer-friday-pac-imaging-review-document.html](2026-10-16-meyer-friday-pac-imaging-review-document.html) | v0.2 独立文档版 HTML |
| [2026-10-16-meyer-friday-pac-imaging-review.html](2026-10-16-meyer-friday-pac-imaging-review.html) | v0.2 展示版 HTML |
| [2026-10-19-meyer-friday-pac-imaging-review.md](2026-10-19-meyer-friday-pac-imaging-review.md) | 影像修订评审稿 v0.4 |
| [2026-10-19-meyer-friday-pac-imaging-review-document.html](2026-10-19-meyer-friday-pac-imaging-review-document.html) | v0.4 独立文档版 HTML |
## 阅读边界
- 环境状态、版本、数据量、耗时和发布结果均为原记录日期的证据;本次没有重新查询服务器。
- 两版影像方案保存了不同阶段的职责划分,早期事件推送建议未被采用。当前按诊所分页轮询影像、批量查询分析,具体行为以现行代码为准。
- 数仓文档是架构讨论,不表示公司数仓已经建成,也不改变 PAC 现有业务职责。
- 不在此复制患者查询原文、临时访问地址、生产备份或运行凭据。内部联调资料单独备份,不纳入 Git。
- 原本机 PDF 及外部仓库源码仅保留引用说明,未作为附件发布;本仓库链接已按新位置修正。
[移动与校验清单](manifest.json)记录原路径、新路径及整理前后摘要。原始文档另有完整可恢复备份。
{
"archived_on": "2026-10-22",
"files": [
{
"from": "docs/qa/2026-10-14-push-latency-local.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-14-push-latency-local.md",
"original_sha256": "9dbe13cb926a54834dcb35a4d013f6bb4297e46668cd40d91beb47cc83a7eb73",
"archived_sha256": "ad369f52632c4f7b118429f78864a6e19594f864072297cd4c8c0ef5e59f63a5",
"category": "historical_validation"
},
{
"from": "docs/qa/2026-10-14-return-visit-push-fix-test.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-14-return-visit-push-fix-test.md",
"original_sha256": "6e92dfeeade2ce23c28b0a5e09a0429c38453ba6efadb6d5c27c8381dd82a162",
"archived_sha256": "fa0d03f1009093bd744810c38adb9c5c2c3911cc93ba030007a582d071b18bb5",
"category": "historical_validation"
},
{
"from": "docs/qa/2026-10-16-meyer-friday-pac-imaging-review-document.html",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-16-meyer-friday-pac-imaging-review-document.html",
"original_sha256": "794cd8b72fb6fd75259f4cb63715d1f6f95e9f3e31ea555f43b1c6766a1373de",
"archived_sha256": "a3387fdf95b8156838b06a875d4c35cd2a5138010b6f44bb7087999a0f0cdf40",
"category": "historical_design"
},
{
"from": "docs/qa/2026-10-16-meyer-friday-pac-imaging-review.html",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-16-meyer-friday-pac-imaging-review.html",
"original_sha256": "0adb5e5adfe6674ca7cd15b0f62e12407b57e606628a1074c139e21c4c250765",
"archived_sha256": "b9bcbb7d3fff38d3bd22c33191d3106653e37f128a5d8e8c242c7fd41fa6c467",
"category": "historical_design"
},
{
"from": "docs/qa/2026-10-16-meyer-friday-pac-imaging-review.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-16-meyer-friday-pac-imaging-review.md",
"original_sha256": "2679e80c6546802bc9d29d130a684e2b3696e1b86c79a85c5ccff92808f2332d",
"archived_sha256": "e659a0769012faa8c6e090e0dc622b0a5f86dd9adcab9c4fe6c206474b759879",
"category": "historical_design"
},
{
"from": "docs/qa/2026-10-18-business-date-shanghai-test-validation.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-18-business-date-shanghai-test-validation.md",
"original_sha256": "fff7acd4aea01673487cc8b2e96b299d877081412f3e619bdd85d69ab0a26b32",
"archived_sha256": "99be312617b0445866ea5e193d9708658940a862adf4db4d9af6c113eb98ade7",
"category": "historical_validation"
},
{
"from": "docs/qa/2026-10-18-jvs-complaint-ingestion-prod-validation.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-18-jvs-complaint-ingestion-prod-validation.md",
"original_sha256": "ddee388593323a72b30d75388f534767db88370824b362f40d7946f7d0302edc",
"archived_sha256": "64af94eb97d52140f76113c28be8193a34a9236cf930e228b0ebf9822611ecc5",
"category": "historical_validation"
},
{
"from": "docs/qa/2026-10-18-jvs-complaint-ingestion-test-validation.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-18-jvs-complaint-ingestion-test-validation.md",
"original_sha256": "ba7149068b9b7e9fe7e9dde3e40d47c464007e156e72d542da3b95dee09cc64f",
"archived_sha256": "8c3116cddafd0d03464183beccd0841a062ceda2f44d763a2afd44a18baac42f",
"category": "historical_validation"
},
{
"from": "docs/qa/2026-10-19-meyer-friday-pac-imaging-review-document.html",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-19-meyer-friday-pac-imaging-review-document.html",
"original_sha256": "aebf50c50fd912e51c4aeea1d1dd78aa1b80658d61f1c73fe4889794ea7a78a3",
"archived_sha256": "c9541bf669f483732ed9ae7bec8fd597c1aae9087954dad17ff5a803256fd64b",
"category": "historical_design"
},
{
"from": "docs/qa/2026-10-19-meyer-friday-pac-imaging-review.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-19-meyer-friday-pac-imaging-review.md",
"original_sha256": "b85aaa9b8fc67efea031156935ede484e8975af30bfee0de481c88cfb4d57e47",
"archived_sha256": "4cef9b11cfdd1ddaf40c5526016d1f427c5fb867c561acf9610fc94f019c348b",
"category": "historical_design"
},
{
"from": "docs/qa/2026-10-20-data-warehouse-and-pac-positioning.md",
"to": "docs/_archive/2026-10-operations-and-design/2026-10-20-data-warehouse-and-pac-positioning.md",
"original_sha256": "c3acd20f181483a052d66306bc007290440c6e9769bced5c62c3abfa115895fa",
"archived_sha256": "597afabd5ecfc0a7b87babf8a428cb408101d9a051e0ef546145bcc62991cbce",
"category": "architecture_discussion"
}
],
"changes": "Add historical notices, repair repository links, label unavailable local references; preserve original content in private backup."
}
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
归档保存历史设计、实验、排查与交付证据。文件名与原文保留;移动时修正引用。归档不等于问题关闭,不以历史环境快照判断当前运行状态。 归档保存历史设计、实验、排查与交付证据。文件名与原文保留;移动时修正引用。归档不等于问题关闭,不以历史环境快照判断当前运行状态。
## 2026-10-22 整理
- [美亚与患者事实开发历史](2026-10-meyer-and-patient-facts/README.md):8 份实现、字段审核与验证记录。
- [运维验收与架构讨论](2026-10-operations-and-design/README.md):11 份 Push、日期、投诉验收记录及数仓、影像方案讨论,含不同版本 HTML。
内部联调原文与一次性检查产物另行备份,不作为正式产品文档发布。
## 2026-10-14 整理 ## 2026-10-14 整理
| 分类 | 入口 | 移入文件 | 原位置与归档依据 | | 分类 | 入口 | 移入文件 | 原位置与归档依据 |
......
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