Контекст
Multi-tenant архитектура BloodGPT: где хранить PHI (Protected Health Information) — лабораторные значения, демография пациента, AI-генерированные интерпретации. Cloud SQL уже используется для бизнес-логики (Organization, ApiKey, BloodTest metadata). Параллельно вводится Google Healthcare API (per-tenant FHIR store, см. google-healthcare-api).
Рассматривали
- Вариант A: всё PHI в FHIR — HIPAA проще (один периметр), FHIR-стандарт,
Patient/$everythingготовый export, но 10–100× latency чтения (50–200ms vs 2–5ms), нет SQL analytics, сложность маппинга нашей модели в FHIR-ресурсы. - Вариант B: SQL + RLS — быстро, минимум изменений, RLS даёт изоляцию tenants на DB-уровне, но PHI остаётся в двух местах (два периметра HIPAA audit), нужна синхронизация удалений между SQL и FHIR.
- Вариант C: гибрид — FHIR primary, SQL cache — best-of-both в теории, но удвоенная сложность (dual writes, cache invalidation, race conditions). Кэш как оптимизация откладывается до того, как basic архитектура устоится — сначала чистый FHIR, потом думать про cache layer если станет нужен.
Initial Claude-рекомендация — B. Ильдар отверг и выбрал A.
Выбрали: A — всё PHI только в FHIR
Cloud SQL хранит только non-PHI: Organization, ApiKey (auth/config), BloodTest (metadata + FHIR pointers), Patient (portal auth), Batch / TestOrder / LabTestCatalog (бизнес-логика). Никаких лабораторных значений, narrative-текстов, AI-интерпретаций.
Почему
- Latency разница (50–200ms vs 2–5ms) несущественна на фоне LLM-генерации, которая занимает секунды. Это снимает главный аргумент против A.
- Один периметр для HIPAA audit логически проще: BAA с Google уже покрывает Healthcare API + Cloud SQL + GCS + GKE; sensitive data physically живёт только в Healthcare API.
Patient/$everything— стандартный FHIR-operation, даёт готовый export-endpoint клиентам без нашего кода.- Будущие analytics закрываются BigQuery streaming из Healthcare API — есть нативный механизм, не нужен дублирующий SQL слой.
Ильдар: «на фоне скорости генерации это не так важно»
Ильдар: «каждый GET endpoint должен собрать данные из FHIR вместо простого Prisma include — а что за гет эндпоинты? они по сути все должны использовать fhir как источник истины»
Следствия
- Все pipeline-шаги (recognize, normalize, AI analysis) пишут в FHIR store через fhir-bundle transactions.
BloodTest.rawRecognitionResultJSON в Cloud SQL — становится legacy, заменяется FHIR store как shared state между Inngest steps (см. inngest и ai-enrichment-separate-step).- B2B API GET endpoints должны быть переписаны — читать из FHIR, не из Prisma include. Pending (Phase 4.5, см. в digest).
- Data migration script (Phase 5 в плане 871a7608) — на практике не понадобился: продакшн-данных в Cloud SQL не было, переливка
BloodTest.rawRecognitionResult+ParameterAnalysis+TestOverviewв Healthcare API не делалась. - HIPAA checklist (Phase 6): Cloud Audit Logs на Healthcare API, VPC Service Controls, OAuth scope minimization, проверка что Inngest events не несут PHI в payload.
- Окончательная очистка остаточного PHI из Cloud SQL — отдельная задача. Legacy JSON-поля (
BloodTest.rawRecognitionResult, identified в digest 871a7608) должны быть полностью удалены после verification, что все reads идут из FHIR.
No direct linkage между FHIR и SQL
Связь между FHIR и SQL — только через внутренние ID, без прямого матчинга идентичности человека:
- В FHIR — только медицинское (возраст, пол, результаты анализов, диагнозы, лекарства). Не имя, не почта, не телефон.
- В SQL — только метаданные (ApiKey, BloodTest pointers, Organization, Patient.email для portal auth, бизнес-логика).
- Один внутренний UUID с обеих сторон. JOIN’ов с PII-полями нет.
Defense-in-depth: утечка одной БД не даёт полную картину. FHIR без SQL — медицина без идентичности. SQL без FHIR — контакты без медицины. Полное PHI восстанавливается только при двойной утечке + знании схемы внутренних ID.
Альтернативный принцип (открытый, см. ниже) — хранить в FHIR всё что нужно агентам для генерации, не только медицинское. Не зафиксировано.
Carry-over: разрешить conflict minimal-PHI-in-FHIR vs agent-completeness. Возможно через granular tagging внутри FHIR resources (что считается PHI vs operational context).
Связано
- fhir-bundle — механизм transaction’ных записей
- fhir-composition — структурированный AI-вывод как FHIR
- fhir-careplan — follow-up рекомендации как FHIR
- fhir-observation — параметры крови как FHIR
- google-healthcare-api — конкретный backend
- multi-tenant-fhir-storage — общий концепт
- zero-extensions-fhir — связанное решение про FHIR-моделирование
- ai-enrichment-separate-step — следствие (FHIR как shared state)
Источники
Сноски
-
2026-04-27 ЧутокПланирования ([Р1] no direct linkage, [О1] Никита альтернатива), accessed 2026-05-17, https://github.com/Realai-plus/meeting-digests/blob/main/data/digest/2026/04/2026-04-27T10%3A04%3A11.000Z_%D0%A7%D1%83%D1%82%D0%BE%D0%BA%D0%9F%D0%BB%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_01KQ76AZGHMBNH1RCPTDYSRB4F.md. ↩
-
Google Cloud BAA, accessed 2026-05-17, https://cloud.google.com/security/compliance/hipaa. ↩