Med Detective — Глибокий аудит (2026-04-19)
Проект: /srv/projects/med-detective/ — веб-квест для лікарів (Schönen/Deltamedical)
Live: http://31.131.26.203/med-detective/
11 кейсів, FastAPI + Vanilla JS + Tailwind, Llama-3 (Replicate)
1. ТЕХНІЧНИЙ СТЕК І АРХІТЕКТУРА
Поточний стан
- Backend: FastAPI (Python 3.12, uvicorn)
- Frontend: Vanilla JS + Tailwind CDN (self-contained HTML)
- LLM: Llama-3-8B (Replicate) для Patient+Intent, Llama-3-70B для Judge, Gemini 2.5 Flash fallback (403 — нема billing)
- Persistence:
sessions: dict in-memory (втрачається при рестарті)
- Deploy: uvicorn через nohup (впаде при ребуті), нема systemd, Docker є але не використовується в prod
- CI/tests: відсутні
- Logging/monitoring: відсутнє
🟥 Критично
- Сесії in-memory → втрата при рестарті. Потрібно Redis/PostgreSQL.
- Нема rate limiting → вразливість до DDoS через
/api/chat. Потрібен SlowAPIMiddleware per IP.
- CORS
allow_origins=["*"] (main.py:80) → whitelist medizine.ua + localhost.
- Judge JSON парсинг крихкий — regex
r"\{.*\}" (main.py:136) ловить перший {...}. Потрібен strict parser або json_repair.
- Нема fallback chain — якщо Replicate впав, вся система падає. Потрібен retry з exponential backoff + fallback на Groq/Gemini.
- Нема systemd unit —
nohup uvicorn, перезавантажиться сервер → проект не підніметься.
🟧 Важливо
- Нема input validation (Pydantic max_length, regex).
- Нема env validation на startup (падає при першому call).
- ThreadPoolExecutor без graceful shutdown.
- requirements.txt без pin versions.
🟨 Nice-to-have
- Async/await (httpx) замість ThreadPoolExecutor.
- Caching Intent responses.
- OpenTelemetry/Prometheus metrics.
2. UI / UX
Поточний стан
- Single-page Vanilla JS, Tailwind responsive (sm/md/lg), typing indicator є, product card з'являється при correct diagnosis
🟥 Критично
- Діагноз через
prompt() браузера (frontend/index.html:341) — архаїка. Замінити на HTML modal з typeahead по accepted_diagnoses.
- Нема feedback при LLM fail — якщо пацієнт не розуміє, лікар думає що bug. Додати "Перепитати" або "Технічна помилка" повідомлення.
- Product images порожні у case_10, case_11 (
"image": ""). Закачати або placeholder.
🟧 Важливо
- Checking modal з фіксованими таймаутами 3-13с, а Judge реально займає 20+ с — SSE/WebSocket для real-time.
- Chat auto-scroll не завжди спрацьовує (
chat.scrollTop = chat.scrollHeight не викликається).
- Нема "Скасувати діагноз" — один клік = пропав.
- Мобільний UX: кнопки й input не містяться на малих екранах.
- Share button копіює в clipboard — додати native share API + TG/WA лінки.
🟨 Nice-to-have
- Анімація bubble slide-in.
- Dark mode (Tailwind має вбудований).
- Keyboard shortcuts (Ctrl+Enter submit).
- Screen reader / a11y (aria-*, semantic HTML).
3. МЕХАНІКА І ЗАЛУЧЕНІСТЬ
Поточний стан
- 11 кейсів, Scoring 45+30+15+10=100, progress тільки within session, нема leaderboard/badges/XP, нема difficulty tier, нема daily quests, нема persistence між сесіями
🟥 Критично
- "Angry-guess" exploit — лікар може ставити 50 діагнозів підряд без жодних консеквенцій. Ввести max 3 спроб + lockout.
- Знає діагноз одразу → макс 55 балів, але правила це не показують явно. Додати explanation у rules modal + мінімум 3 питання перед діагнозом.
- Нема механіки замовлення обстежень — частина діагностики недостатня. docs/investigation_panel_design.md вже планує це (Phase 7), не реалізовано.
- Нема persistence прогресу — клір браузера = 0. Потрібен optional account (email) або localStorage stats.
🟧 Важливо
- Додати
difficulty: easy/medium/hard у case schema, показати на картках.
- Daily quest / streak mechanic — unlock 1 новий кейс/день, 7 днів = badge, 30 = CME certificate.
- Anonymous leaderboard (top-10 тижня).
- Розширений feedback після помилки (2-хв міні-лекція + посилання Uptodate/посібники).
🟨 Nice-to-have
- Динамічна складність (адаптивна).
- Team mode (2 лікарі на 1 пацієнта).
- Historical log пройдених кейсів.
- Challenge mode (3 кейси за 3 хв).
4. КОМУНІКАЦІЯ ПАЦІЄНТ ↔ ЛІКАР
Поточний стан
- Patient prompts — детальні character sheets, українською (переважно), Gender 8Ж/3Ч (27% чоловіків!), health-anxiety trigger у case_08/case_10/case_07 — не уніфіковано, typing indicator fixed delay, нема streaming
🟥 Критично
- Спойлери в титулах — case_01 "хронічною закладеністю" → лікар одразу думає rhinitis. case_11 "біль у попереку після підйому" → ортопедія. Переписати 4-5 титулів по шаблону "Пацієнт(ка) N р. з <нейтральна скарга>".
- Health-anxiety trigger не уніфікований — правило від 18.04 застосовано частково. Додати
health_anxiety_trigger field у case schema + validate при генерації patient prompt.
- Llama-8B русизми ("но", "вообще", "получается", "Рукі"). Пост-процесинг regex або strengthened system prompt.
- Pacient не має guardrails на off-topic — якщо лікар питає про погоду, пацієнт продовжує. Додати guardrail "відповідай стисло, переспрямуй на симптоми".
- Gender imbalance 27% — потрібно додати 3-4 кейси з чоловіками 45+ (ХБН, простата, Tinnitus, подагра).
🟧 Важливо
- 15с на Judge — "пацієнт думає" виглядає як зависання. Groq (200ms) або streaming SSE.
- Patient пам'ять коротка (за промптом) — іноді забуває що вже казав. Потрібна conversation summary injection.
🟨 Nice-to-have
- Character personality (не нейтральні персонажі, а реалістично-перелякана Тетяна тощо).
- Streaming token-by-token (WebSocket).
- Voice mode (TTS для patient, STT для лікаря).
5. LLM МОДЕЛІ
Поточна матриця
| Агент |
Модель |
Backend |
Latency |
Cost/call |
Проблеми |
| Patient |
Llama-3-8B |
Replicate |
~1с |
$0.0002 |
русизми, off-topic |
| Intent |
Llama-3-8B |
Replicate |
~1с |
$0.0002 |
OK |
| Judge |
Llama-3-70B |
Replicate |
~15с |
$0.00175 |
ТАЙМАУТ, JSON крихкий |
| Fallback |
Gemini 2.5 Flash |
Google |
500мс |
$0 |
403 — нема billing |
🟥 Критично
- Judge 15с — user timeout. Switch на Groq (Llama-70B ~200ms, free tier потім $0.59/1M), або OpenAI gpt-4o-mini ($0.15/1M, ~500ms), або Claude Haiku ($0.80/1M, ~800ms). Groq — best value.
- Gemini 403 — активувати billing на GCP проєкті або замінити.
- JSON parsing крихкий — імплементувати
json_repair library або iterate через всі {...} matches.
- Нема fallback chain — retry + backoff + cascade (Groq → Gemini → Replicate → cached).
🟧 Важливо
- Groq backend class відсутній — додати
GroqBackend у llm.py.
- Cost tracking — Replicate usage monitoring (logging token usage).
- Structured output —
response_format={"type":"json_object"} на Groq/OpenAI гарантує.
- Function calling — Intent classification через constrained function calls (не вільна генерація).
🟨 Nice-to-have
- A/B testing LLM (50% Llama, 50% Groq, порівняти).
- Fine-tune Llama на ~100 Ukrainian medical cases.
- Vision support (якщо додадуться рентгени/УЗД).
- Self-hosted ollama на GPU (100ms, $500 hardware).
6. МАРКЕТИНГ / BRAND POSITIONING
Мапа продуктів у кейсах
| Case |
Продукт |
Тип |
| 01 |
Deflu Silver Nose |
MD |
| 02 |
Filtrum Gastro Gel |
MD |
| 03 |
Forteza Lido |
OTC ЛЗ |
| 05 |
Forteza спрей |
OTC ЛЗ |
| 06 |
Allerveg Atopik |
Кос. |
| 07 |
Menopace Plus |
БАД |
| 08 |
Zest Магній B6 |
БАД |
| 09 |
Zest Магній B6 |
БАД |
| 10 |
Argett Sport |
MD |
| 11 |
ProFLEX Osteo |
БАД |
🟥 Критично
- НЕМА LEAD CAPTURE. Жодний email/phone не збирається. Це вхід на маркетингову воронку! Потрібна optional форма на result screen (ім'я + email + спеціальність + місто/клініка) → Supabase + сегментація.
- НЕМА ANALYTICS. Які кейси популярні? Скільки пройшло? Скільки кликнуло product card? GA4 + custom events (
game_started, diagnosis_submitted з score/time, product_clicked, email_subscribed).
- Продуктова прив'язка case_08 спірна — Panic disorder часто SSRI, не магній. Лікар може сприйняти як promotion. Додати disclaimer "магній як адьютвант".
🟧 Важливо
- Retention = 0 — лікар пройшов → забув. Daily quest + streak + CME certificate (генерація PDF "10 годин самоосвіти") = reason to return.
- Referral — "Я розв'язав case Олени на 87 балів. Спробуй: [link]" → social sharing з unique ref code, бонус за friend-play.
- CME integration — партнерство з НМАП або самостійний сертифікат з disclaimer (простіше).
- UTM + pixel — на всіх product links (medizine.ua?utm_source=meddetective&utm_campaign=case_07), FB pixel для retargeting.
- Cross-sell — після case_07 (Menopace) → показати suggestion "Ще 2 кейси з менопаузою (08, 11)". Підвищить session length.
🟨 Nice-to-have
- Telegram bot version (inline quest у медичних TG-групах).
- Podcast / YouTube series "За лаштунками case X" з лікарем-експертом.
- B2B partnerships з КМС/НМАП/ДУ "Інститут серця" як "навчальний інструмент резидентам".
- White-label (інші бренди запускають квести на цій платформі за комісію).
TOP-5 ПРІОРИТЕТІВ
1. 🟥 Groq Judge (impact HIGH, effort LOW)
Проблема: 15с Judge → drop-off ~40%.
Дія: Додати GroqBackend у llm.py, Judge через Groq Llama-70B (~200ms).
ETA: 2-3 год.
2. 🟥 Lead Capture + CRM (impact CRITICAL, effort LOW)
Проблема: 0 emails = 0 маркетингу.
Дія: Email modal на result screen → Supabase. Tag по спеціальності.
ETA: 3-4 год.
3. 🟥 Analytics (GA4 + custom events) (impact HIGH, effort LOW)
Проблема: Працюємо наосліп.
Дія: GA4 property + events (game_start, diagnose, product_click), dashboard Looker.
ETA: 2 год.
4. 🟧 Despoiler + Guardrails (impact MEDIUM, effort LOW)
Проблема: Кейси 01/11 здають діагноз у заголовку.
Дія: Переписати 4-5 титулів + health_anxiety_trigger у всіх.
ETA: 1-2 год.
5. 🟧 Gamification MVP (impact HIGH для retention, effort MEDIUM)
Проблема: Zero return rate.
Дія: Streak counter (localStorage), daily quest (1 кейс/день), badge system, CME PDF після 10 кейсів.
ETA: 1-2 дні.
Total готовність Med Detective: ~55% до production (backend стабільність 40%, UI 70%, content 75%, маркетинг 10%).