Post-hoc документація існуючої системи. Описує fluxи реально розгорнутих 4 форм без коду.
Лікар відкриває URL з конкретним кейсом → бачить картку пацієнта → спілкується з AI-пацієнтом через чат → паралельно замовляє лабораторні обстеження → ставить діагноз і пропонує продукт → Judge оцінює сесію → результат (бал/100 + правильна відповідь + рекомендований SKU).
1. GET /<form_path>/case/<case_id>
2. Backend завантажує JSON-спеку кейса з cases/<case_id>.json
3. Створює Redis-сесію (DB per форма, TTL 24h, ключ session:<uuid>)
4. Повертає HTML з картою пацієнта + chat-UI
5. Loop (chat):
5.1. Лікар вводить повідомлення → POST /api/chat
5.2. Backend паралельно викликає:
- Patient Agent (рольова симуляція пацієнта згідно patient_<case>.md)
- Intent Recognition (класифікує: question / examination_request / diagnosis_attempt)
5.3. Зберігає у Redis історію
5.4. Повертає відповідь пацієнта
6. Loop (Investigation Panel):
6.1. Лікар відкриває панель → GET /api/lab_catalog (39 тестів × 6 категорій)
6.2. Шукає тест через search-bar → клік
6.3. POST /api/order_tests з list test_ids
6.4. Backend перевіряє test_id ∈ LAB_CATALOG ∪ extra_tests кейса
6.5. Повертає результати з cases/<case_id>.json (test_results секція)
7. Закриття сесії:
7.1. POST /api/finish_case з diagnosis_text + product_choice
7.2. Backend викликає Judge Agent (system+user prompts)
7.3. Judge оцінює по rubric: 40 + 30 + 15 + 15 = 100
7.4. Зберігає результат у Redis
7.5. Повертає score + правильна відповідь + рекомендація
8. Result-screen → CTA: «Скачати CME» (TODO: Lead Capture модалка → Supabase email confirm → PDF)
1. Patient/Intent Agent отримує timeout
2. Backend: спробувати Gemini fallback (тільки на Schönen-main)
3. Якщо обидва failed — повертає friendly error «AI поки відпочиває, спробуй ще раз»
1. Backend перехоплює connection error
2. Повертає 503 з «session expired, refresh»
3. Лікар починає сесію заново
1. Backend: test_id ∉ LAB_CATALOG ∪ extra_tests
2. Повертає 400 з «test not available for this case»
1. Backend logs error
2. Fallback: показує bare diagnosis match без rubric breakdown
3. Алерт у Telegram (TODO — наразі тільки в logs)
{
"case_id": "case_07_ibs",
"title": "Пацієнт N р. зі скаргами на...", # no-spoiler title
"patient_persona_md": "patient_case_07.md",
"correct_diagnosis": "...",
"differential": ["...", "..."],
"key_tests_to_order": ["FBC", "CRP", "calprotectin"],
"extra_tests": ["..."],
"test_results": { "FBC": {...}, ... },
"recommended_sku": "Allerveg Atopik",
"rubric_overrides": { ... } # optional per-case
}
session:<uuid> = {
"case_id": "...",
"started_at": ts,
"history": [{"role":"doctor"|"patient", "text":"..."}],
"ordered_tests": ["..."],
"diagnosis_attempt": "...",
"product_choice": "...",
"judge_result": { "total": 87, "diagnosis": 35, ... }
}
[
{"id":"FBC", "name":"...", "category":"hematology", "price":180, "turnaround":"1d"},
...
]
load_case(case_id) → читає cases/<id>.json + patient_<id>.mdinit_session(case) → створює Redis запис, повертає uuidchat_step(session, text) → паралельно: Patient Agent + Intent Recognition; оновлює historyorder_tests(session, test_ids) → валідує + повертає results з case specjudge_session(session) → формує prompt для Judge LLM, парсить JSON відповідь, фолбек на diagnosis-only при failvalidate_case(case_json) → перевіряє що key_tests_to_order ∈ LAB_CATALOG ∪ extra_tests (offline скрипт)meta/meta-llama-3-8b-instruct (Patient + Intent + Judge), latency 1.0-1.4с p95, billing through Deltamedical Replicate accountgemini-med-detective.key, AI Ultra)/med-detective*/... → 127.0.0.1:876{5,6,8,9}