Привет, Хабр. В прошлых статьях рассказывал про Telegram-бота на Gemini и внедрение AI во все поля ввода Windows. Сегодня — история другая: личная, экспериментальная. Я написал медицинский сервис для своей семьи, подключил к нему Claude Opus и честно не знаю, чем всё закончится. Но пока результат интереснее, чем я ожидал.
У сына задержка речевого развития. За два года мы прошли кучу специалистов: неврологов, психиатров, логопедов, дефектологов. У каждого — своя карта, свои записи, своё мнение. В какой-то момент я понял две вещи. Первая: жена, которая занимается этим 24/7, физически не может удержать всё в голове. Вторая: врачи между собой не общаются, и никто не видит полной картины.
Был случай с неврологом, которую направили из поликлиники. Она настоятельно рекомендовала остеопата. Я загуглил — остеопатия не относится к доказательной медицине. В отзывах видно, что она почти всем направляет одного и того же остеопата. Я задумался: как понять, профессионал передо мной или нет, если я не врач? Ответ: никак. Если нет инструмента, который проверит за тебя.
Медицина — точная наука: анализы, дозировки, референсные значения — всё это цифры. Нейросеть с цифрами работает хорошо. Главное — она видит всю картину целиком: все взаимосвязи между анализами, назначениями и диагнозами, которые ни один врач не охватит за 15 минут приёма. Так я начал писать сервис.
Что получилось на данный момент
Это — семейная медицинская база данных. В неё загружаются все данные о здоровье: документы, анализы, расшифровки приёмов, назначения, прививки, рост и вес. Нейросеть анализирует всё целиком — не фрагмент, а всю историю со всеми связями.
Ключевое отличие от «просто спросить ChatGPT» я понял на жене. Она пользуется бесплатной версией и говорит: «мне хватает». Для простых вопросов — да. Но когда у тебя папка документов за пять лет, а ты спрашиваешь про новый анализ, нейросеть в чате уже забыла, что три приёма назад другой врач назначил препарат. Контекст не резиновый. По мере диалога нюансы теряются.
У меня Claude получает полный контекст: все диагнозы, препараты, анализы, хронологию, связи между ними — за один запрос. Ничего не теряется между сеансами. Это не чат, а персистентная база знаний с нейросетью в роли аналитика.
Важно: AI в сервисе не ставит диагнозы. Он объясняет на языке фактов, что было сделано, что упущено и почему это важно. Никаких «скорее всего», только: «врач N не назначил анализ X, хотя при диагнозе Y это стандарт по международным гайдлайнам». Разница принципиальная.
Главный экран
При открытии — PIN-экран. Если на устройстве настроена биометрия, можно войти через Face ID или Windows Hello. Иначе — 6-значный код.
После входа — сводка: четыре кликабельные карточки: активные диагнозы, текущие препараты, количество визитов, критичные ошибки. Ниже — топ диагнозов, текущие препараты, ближайшие напоминания и AI-резюме по пациенту.
AI-резюме — это структурированная сводка, которую нейросеть генерирует после анализа всей базы: приоритеты, план действий, на что обратить внимание. Обновляется при добавлении нового документа.
Остальные страницы: план обследований (можно менять приоритеты перетаскиванием), список врачебных ошибок и несостыковок, все диагнозы, документы (визиты и анализы в одной ленте с фильтрами), карта здоровья, AI-чат, раздел «ещё» — специалисты, прививки, рост-вес, глобальный поиск.
Есть и десктопная версия — не просто адаптация под ПК. На десктопе: сайдбар, модалки во весь экран, таблицы и графики используют всё пространство. Я сам пользуюсь наполовину с телефона, наполовину с компьютера, и важно, чтобы на обеих платформах интерфейс ощущался нативно.
Карта здоровья и почему связи важнее хранения
Изначально данные лежали рядом, но не связаны. Препарат, диагноз, приём у врача — всё записано, но нигде не зафиксировано: кто назначил, от какого диагноза, на каком приёме. Нейросети приходилось каждый раз угадывать по тексту и датам. Работало, пока данных было мало. Потом начались сбои.
Я смотрел графовые БД: SurrealDB, Kuzu, Neo4j. Но понял: у меня 100 сущностей и 300 связей — это не тот масштаб. Проблема не в движке, а в схеме данных.
Решение оказалось простым: связующие таблицы в SQLite.
Теперь у каждой связи есть явный ID. Это позволяет использовать SQL с JOIN’ами. Нейросеть больше не парсит текст, а работает с чёткими связями. Точность анализа выросла на порядок.
Поверх базы — визуализация на Cytoscape.js. Узлы: диагнозы, врачи, препараты, приёмы, ошибки. Рёбра: кто что назначил, от какого диагноза, на каком приёме. При клике на узел подсвечиваются только его связи, остальное затемняется.
AI-координатор: как это работает без вызовов API
В сервисе нет прямых вызовов API нейросети. Ни одной строки fetch('https://api.anthropic.com/...'). Ни одного @anthropic-ai/sdk в зависимостях. Ни одного API-ключа в .env.
Как тогда работает AI?
На сервере лежит файл service_instructions.md — документ на 50+ КБ с полным протоколом: как оценивать визиты, строить планы, искать противоречия, в каком формате записывать результаты. Это — промпт для Claude, но структурированный и детализированный.
Работает по двум механизмам:
- Очередь запросов: в базе есть таблица
ai_requests. Когда я нажимаю «Запросить AI-анализ» на любой сущности, туда добавляется запись со статусомpending. - Единая точка контекста: эндпоинт
GET /api/patient-context. Он возвращает ВСЁ, что знает база: диагнозы, препараты, анализы, визиты, ошибки, план, историю изменений. Один JSON на 200–500 КБ.
Цикл обработки:
- Загружаю новый документ
- Открываю Claude Code и говорю: «Посмотри инструкцию, есть новый документ»
- Claude читает
service_instructions.md, делаетGET /api/patient-context, видит новый документ и очередьai_requests - Анализирует, сверяет с данными, ищет противоречия и пропущенные обследования
- Пишет результаты напрямую в базу:
ai_assessment, новые ошибки, обновления плана - Помечает запросы как
completed
Визуально это выглядит как полный цикл: от загрузки документа до записи результатов в базу.
Это работает лучше, чем прямые API-вызовы. У Claude в Claude Code есть инструменты: чтение файлов, запуск SQL, HTTP-запросы. Он сам перерендерит PDF в высоком разрешении, если не прочитал показатель, сам сверит с оригиналом.
Есть кнопка «Запросить AI-анализ» под любой сущностью. Нажимаешь — запрос в очереди. Нейросеть при следующем обновлении видит, что нужно проанализировать, без лишних объяснений. Та же логика с комментариями: можно задать вопрос под документом и получить ответ с учётом контекста.
Минус: это не автоматика. Мне нужно вручную открыть Claude Code и запустить анализ. Примерно раз в неделю. Можно было автоматизировать через хук на загрузку, но пока мне спокойнее контролировать процесс. Новые данные появляются не каждый день.
Сколько это стоит
На примере карты сына:
service_instructions.md— 51 КБ → ~17 000 токеновpatient-context— 188 КБ → ~63 000 токенов- Итого на вход: ~80 000 токенов
На выходе Claude генерирует 5–10 тыс. токенов: оценки, новые записи, правки.
По ценам OpenRouter (Claude Opus 4.6):
- Вход: 80K токенов × $0.005 = $0.40
- Выход: 8K токенов × $0.025 = $0.20
- Итого: ~$0.60 за полный анализ всей медкарты
Новые документы — 2–4 раза в месяц. Через API это обошлось бы в $1.5–2.5 в месяц.
Я использую подписку Claude Max за $100/мес, но не ради сервиса — он просто едет в том же потоке. Claude — мой основной инструмент для кода, текстов, анализа.
Нейросеть ошибается
Однажды при обработке лабораторного отчёта Claude неправильно прочитал значение в PDF: число из соседней строки «перескочило». В базу попало критическое отклонение, которого не было. Нейросеть построила на этом аналитику, завела ошибку, добавила пункт в план. Я заметил при проверке, попросил перепроверить — Claude сам нашёл расхождение и исправил всё.
После этого я добавил в инструкцию обязательную двухэтапную проверку для документов с числами: первый проход в стандартном разрешении, второй — с перерендером PDF в 400–500 DPI и построчной сверкой. Только при полном совпадении данные идут в базу.
Вывод: всегда проверяйте данные за нейросетью, особенно когда речь о здоровье. Но прогресс идёт быстро — с каждым обновлением таких ошибок будет меньше.
Автоматическая история: 40 триггеров и ноль кода для логирования
Логирование изменений работает без единой строки кода в роутах. Никаких await log('medication_added', ...). История строится через триггеры SQLite.
40 триггеров на 13 таблицах (insert/update/delete). Любая правка — из фронтенда, админки или консоли — автоматически записывается в audit_log как старый и новый JSON. Обойти нельзя — триггер на уровне базы.
Модуль changelog.js превращает сырые логи в читаемые записи:
- Если статус ошибки изменился с
openнаresolved— пишет «Решена ошибка: СОЭ 24, не учли» - Правки за 60 секунд группируются в одну запись
- Группировка по дням: Сегодня / Вчера / 3 дня назад / 2026-04-05
На фронте — страница «История». Создана, чтобы видеть, что изменилось после обработки документа: какие напоминания добавились, какие выводы переписаны, какие ошибки закрыты. Изменения от AI отмечаются отдельно, можно откатить, если что-то пошло не так.
Стек и деплой
Сервис на VPS: nginx + TLS снаружи, Node.js + better-sqlite3 внутри, systemd для автозапуска.
Фронт: React 19 + TypeScript strict + Vite, роутинг — React Router 7, данные — TanStack Query, формы — react-hook-form + zod, граф — Cytoscape, анимации — Motion, иконки — @tabler/icons-react, PWA — vite-plugin-pwa + Workbox.
Бэкенд: Express + better-sqlite3, биометрия — @simplewebauthn/server.
Все SQL-запросы написаны в стиле PostgreSQL: pool.query('SELECT * FROM patients WHERE id = $1', [id]). В db.js — обёртка, которая транслирует $1 в ?, эмулирует RETURNING, заменяет NOW() на datetime('now'). Формально SQLite, но переключиться на PostgreSQL можно за полчаса.
Безопасность. Это стоит обсудить отдельно
Медицинские данные ребёнка — самое чувствительное. Я не хочу, чтобы их кто-то увидел, и не хочу потерять базу. Безопасность — приоритет с первого дня. Защита многослойная: нужно пробить несколько независимых барьеров.
Сеть и TLS
На VPS — UFW с default-deny: открыты только SSH (22), ACME (80), HTTPS (443). Fail2ban банит IP при попытках взлома: 3 неудачные попытки за 10 минут → час бана, срок растёт при повторах. SSH принимает только ключи, паролей нет — брутфорс невозможен.
TLS 1.2 и 1.3, старые протоколы отключены. Сертификат Let’s Encrypt с автопродлением. Заголовки безопасности: HSTS на 2 года, CSP (запрет сторонних скриптов), X-Frame-Options: DENY, nosniff, Referrer-Policy, Permissions-Policy (отключены камера, микрофон, GPS и др.).
Три способа войти
Биометрия (Face ID / Touch ID / Windows Hello). Через WebAuthn — тот же стандарт, что у банков. Ключ хранится в Secure Enclave, сервер видит только публичный ключ. Подпись возможна только при физической разблокировке устройства.
PIN + контрольное слово. PIN — 4–10 цифр. Хранится как scrypt-хеш. Сравнение — constant-time, чтобы исключить угадывание по времени. Контрольное слово запрашивается только при входе с нового устройства. Устройство определяется по UUID в localStorage. После входа — уведомление в Telegram с IP, браузером и временем. Если зашёл не я — узнаю мгновенно.
Просто PIN. Если устройство уже доверенное, а биометрия не настроена.
Защита от брутфорса
Реализован экспоненциальный таймаут после трёх неудачных попыток: 3-я — 1 минута, 4-я — 2, 5-я — 4, дальше удваивается до 24 часов. С 14-й попытки — блокировка на сутки. Перебрать миллион комбинаций невозможно.
Счётчик в базе — очисткой кеша не обойти. Лимит: 20 попыток входа за 15 минут на IP, 1000 запросов на всё остальное. Fail2ban на уровне файрвола. Сессии живут 14 дней, при смене PIN — мгновенно инвалидируются.
Серверный бэкенд и данные
Сервис работает не от root. Есть отдельный системный пользователь с минимальными правами. Даже при уязвимости в коде — атакующий получит только доступ к медкарте, но не сможет лезть в другие сервисы.
systemd-unit настроен с изоляцией: NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp и др. Файлы базы и конфигов — права 600, видны только владельцу.
Поиск — через FTS5 (встроенный полнотекстовый индекс SQLite). Это исключает SQL-инъекции: пользовательский ввод не склеивается вручную.
Загрузка документов проверяется дважды: MIME-тип и расширение. Разрешены: PDF, DOC/DOCX, XLS/XLSX, JPG, PNG, WebP, HEIC. SVG запрещён — может содержать JavaScript. Каждому файлу — UUID-имя. При скачивании — проверка пути, защита от path traversal.
Бэкапы по правилу 3-2-1
Три копии, две среды, одна оффсайт.
Копия 1: горячие снимки каждые 6 часов через нативный .backup API SQLite. Хранятся последние 14. Защита от логических ошибок: случайное удаление, ошибка AI.
Копия 2: полный ежедневный архив в 02:00. База + все медиа. Упаковывается в tar, шифруется AES-256-CBC с PBKDF2 (100 000 итераций, стандарт OWASP). Без ключа — бессмысленный набор байтов. Хранятся 14 последних.
Копия 3: сразу после создания архив отправляется в Telegram через бота. Физически лежит в облаке Telegram — отдельно от VPS, GitHub, ноутбука. История в Telegram — вечная, скачать можно с любого устройства. Файл зашифрован, ключ — в менеджере паролей.
Код — на GitHub (private repo), данные — на VPS с двумя уровнями бэкапов, зашифрованная копия — в Telegram. Даже если VPS сгорит — код клонируется, данные скачиваются, расшифровываются, сервис поднимается за час.
Аудит и уведомления
Все изменения — в audit_log. auth_log — все события входа, выхода, смены PIN, биометрии, отвязки устройства: с IP, user-agent, временем.
В Telegram — мгновенные уведомления:
- Новое устройство вошло
- Настроена биометрия
- Сменён PIN
- Сервис перезапущен
- Ежедневный бэкап создан или упал
Так я узнаю о подозрительной активности в ту же секунду.
Честно о слабых местах
Идеальной безопасности нет:
- VPS не выделенный хост: виртуалка на общем железе. Теоретически возможна утечка через соседний контейнер. Минимизирую изоляцией, но физическая изоляция — другой бюджет. Для семьи — риск приемлем, для тысячи пациентов — нет.
- База на диске не зашифрована: файл в открытом виде. При root-доступе — можно прочитать. Защита — через права 600 и непривилегированного пользователя. SQLCipher ломает FTS5, критичный для AI. Смягчение: ежедневный бэкап в Telegram — зашифрован.
- Сессионные токены в localStorage: теоретически уязвимы к XSS. Снижаю риск через CSP, запрет SVG, валидацию. Смягчение: короткий срок жизни, уведомления, возможность разлогинить все устройства.
Для семейного инструмента — разумный уровень защиты с чёткими компромиссами.
Что AI реально нашёл
Без примеров — это теория. Вот три реальных кейса.
Пропущенные базовые обследования
Claude проанализировал историю сына за пять лет и выявил, что ряд базовых анализов не назначались:
- ТТГ — не проверялся больше трёх лет, хотя при диагнозе это стандарт
- МРТ головного мозга — ни разу за пять лет, хотя может показать структурные изменения
- Ферритин — ни разу, хотя скрытый дефицит железа у таких детей — частое явление и коррекция помогает
Каждый специалист не обязан назначать всё. Но когда видишь всю историю — пробелы очевидны.
Три невролога, три схемы
За полтора года — три невролога, три разные схемы лечения:
- Первый: Когитум, Кортексин, Глицин
- Второй: Винпоцетин, Аминолон
- Третий: Ницерголин, Глиатилин, Нейробион
Только один уточнил, что ребёнок уже принимает.
Claude построил хронологию и задал вопрос, который я не задавал: «Какая схема работала? Почему меняли? Где записан ответ?» А нигде. Система не говорит «кто прав». Она показывает факты и предлагает задать эти вопросы врачу.
И та самая история: при загрузке расшифровки приёма Claude отметил: остеопатия — альтернативная медицина, рекомендация строить лечение на ней — не соответствует доказательному подходу. Без оценки врача — просто факт.
Мне именно это и нужно: не «хороший или плохой», а «соответствует ли подход доказательной медицине». Решение — моё.
Я добавил себя
Сын был первым пациентом. Потом я добавил себя. Мне 38, и я никогда толком не разбирался со здоровьем. Ходил на диспансеризацию, получал лист — «всё норм» — и забывал.
Попросил Claude составить базовый чекап для мужчины 38 лет с сидячим образом жизни. Он подобрал 35 пунктов:
- Анализы: ОАК, биохимия, ТТГ, глюкоза, гомоцистеин, онкомаркеры, тестостерон, витамин D
- Инструментальные: флюорография, ЭКГ, УЗИ брюшной полости, щитовидной, почек
- Врачи: терапевт, офтальмолог, стоматолог, уролог, дерматолог (с дерматоскопией), ревматолог
Сумма — больше 35 тысяч рублей. Но выяснилось, что всё покрывается корпоративным ДМС. Полный чекап — бесплатно. Начну на следующей неделе.
Это главное. Не «AI найдёт ошибки врачей», а «AI поможет не пройти мимо того, что ты мог бы сделать для себя».
Честный взгляд на то, что я сделал
AI не заменяет врача. Это инструмент контроля, а не диагностики. Каждая рекомендация — повод задать вопрос на приёме, а не основание для самолечения.
Garbage in, garbage out. Если данные кривые — анализ будет кривым. Двухэтапная проверка помогает, но не устраняет проблему.
Это не production-сервис. Это эксперимент. Я не знаю, чем он закончится. Может, через год напишу: «сервис изменил моё отношение к здоровью». А может — «забил через три месяца». Пока ощущение первое. Подождём.
Про расшифровки приёмов
Жена давно записывает все визиты на диктофон. Эти записи — золото: нейросеть получает не только выписку, но и полную расшифровку разговора — с нюансами, вопросами, рекомендациями.
Транскрибирую через NotebookLM от Google: загружаю аудио, получаю текст, вставляю в сервис. Whisper пока не использую — боюсь ошибок в терминологии и названиях препаратов на неидеальных записях. NotebookLM справляется лучше.
Открытый код и что дальше
Код планирую выложить на GitHub в ближайшие недели. Идея «своя база + AI-координатор через инструкцию и patient-context» может быть полезна как шаблон — не только для медицины. Допилю и выложу, ссылку — в Telegram.
Я скорее выберу врача, который использует нейросеть вместе со своим опытом, чем того, кто игнорирует прогресс.
Если у вас был похожий опыт — собрали медданные, пробовали AI — пишите в комментарии. Интересно увидеть другие примеры.
Жена после знакомства с сервисом написала три сообщения:
— Как интересно всё, конечно
— Не то слово как полезно
— Да конечно п* она умная
Для меня это — лучшая приёмка продукта. Если она сказала «полезно» — значит, сервис делает то, ради чего я его писал.