Telegram-бот контроля курсов лекарств: врач назначает — пациент начинает кнопкой — бот напоминает — врач видит соблюдение.
A Telegram bot for medication-course adherence: the doctor writes the course, the patient explicitly starts it, the bot reminds, the doctor sees adherence. MVP for private doctors in Uzbekistan, Russian and Uzbek (Latin).
Быстрый старт · Как это работает · Документация · Развёртывание · Состояние проекта
⚠️ Сервис организует лечение, назначенное врачом. Он не ставит диагнозы, не выбирает препараты и дозы, не меняет схему и не советует менять её самостоятельно. Он не служба экстренной помощи. Об этом сказано пациенту в самом боте.
| Для кого | Что делает |
|---|---|
| 🧑⚕️ Врач | Приглашает пациента одноразовой ссылкой · составляет курс мастером в чате · следит за соблюдением · приостанавливает, меняет план, отменяет · получает отчёт файлом (PDF и CSV для Excel) |
| 🙋 Пациент | Соглашается на обработку данных · подтверждает связь с врачом · сам нажимает «Начать курс» · получает напоминания · отмечает «Принял / Позже / Пропустил» · видит историю · может отозвать согласие и запросить удаление |
| 👁 Опекун | Только читает расписание и отметки подопечного (после добавления врачом и согласия пациента) |
| 🏥 Сотрудник клиники | Веб-панель: врачи своей клиники, курсы без содержимого, операционные инциденты |
| ⚙️ Администратор | Админка прямо в боте: заявки врачей → подтвердить с записью «что проверено», отозвать статус, состояние сервиса, инциденты, назначение других администраторов по Telegram id |
| 🛠 Оператор сервера | ops.cjs: миграции, зашифрованные копии, репетиция восстановления, проверка готовности установки (preflight) |
- 🔒 Напоминаний не будет, пока пациент сам не начал курс. Повторное нажатие ничего не сбрасывает.
- 🕐 Время считается по местному времени пациента (IANA-зона, переход на летнее время учтён), а хранится в UTC.
- 📜 История не переписывается. Поздняя отметка не стирает факт пропуска; изменение плана — новая ревизия.
- 📬 Честная доставка. Напоминания идут через очередь в базе (outbox): рестарт любого процесса ничего не теряет, а врачу не пишут «пациент уведомлён», пока Telegram этого не подтвердил.
- 🚦 Под лимитом Telegram: не больше 25 сообщений в секунду на весь бот, ответ 429 приостанавливает отправку.
- 🧾 Каждое действие в журнале аудита — какие поля изменились (но не их значения).
flowchart LR
TG([Telegram]) -- webhook / polling --> BOT[apps/bot]
BOT -- ответы --> TG
WRK[apps/worker<br/>очередь, напоминания,<br/>сверка, сводки] -- sendMessage --> TG
BR([браузер сотрудника]) --> PNL[apps/panel<br/>HTML без скриптов]
BOT --> DB
WRK --> DB
PNL --> DB
subgraph core [общие пакеты]
DB[(PostgreSQL 16<br/>состояние + очередь)]
SCH[schedule<br/>календарь и слоты]
I18[i18n ru/uz]
end
Одна база — единственный источник состояния и очереди: никаких таймеров в памяти и никакого Redis. Права проверяются SQL-предикатами при каждом чтении и записи, а не «на входе».
Жизненный цикл курса
stateDiagram-v2
[*] --> DRAFT: врач составляет
DRAFT --> PENDING_PATIENT: врач отправляет
PENDING_PATIENT --> ACTIVE: пациент нажал «Начать»
PENDING_PATIENT --> EXPIRED_NOT_STARTED: окно старта истекло
ACTIVE --> PAUSED: врач ставит на паузу
PAUSED --> ACTIVE: врач возобновляет
ACTIVE --> COMPLETED: последний день прошёл
ACTIVE --> CANCELLED: врач отменяет
PAUSED --> CANCELLED: врач отменяет
COMPLETED --> [*]
CANCELLED --> [*]
И приём: SCHEDULED → NOTIFIED → TAKEN | SKIPPED | MISSED → TAKEN_LATE, с отложением «Позже» (до трёх раз, не дальше дедлайна).
Нужны Node 24 и pnpm 9 (corepack enable). Docker не обязателен: тестовый Postgres поднимается встроенный.
git clone https://github.com/NuX-team/Med_Course.git && cd Med_Course
pnpm install
cp .env.example .env # впишите TELEGRAM_BOT_TOKEN тестового бота от @BotFather (в git он не попадёт)
pnpm dev:db # терминал 1: Postgres 16 на 127.0.0.1:5433
pnpm db:migrate # терминал 2, один раз
pnpm dev:bot # бот (polling)
pnpm dev:worker # терминал 3: напоминания
pnpm dev:panel # терминал 4: веб-панель, http://localhost:3002 (нужен PANEL_BASE_URL в .env)Откройте бота в Telegram и отправьте /start. Чтобы стать администратором (у вас уже должен быть аккаунт в боте):
pnpm admin grant-admin <ваш-telegram-id> # id покажет, например, @userinfobotПосле этого в меню бота появится ⚙️ Админка: через неё подтверждаются врачи и назначаются другие администраторы. Врач: «Для врачей» → заявка → подтверждение в админке → «Пригласить пациента» → второй аккаунт Telegram открывает ссылку.
🔐 Токен бота лежит только в
.env. Никогда не кладите его в код, в.env.example, в чат и в issue. Для разработки заведите отдельного тестового бота: настоящие пациенты не должны попадать в ваши опыты.
pnpm check # формат + линтер + типы + все тесты — то же, что CI
pnpm test:unit # быстро, без базы
pnpm test:db # на настоящем Postgres (поднимается сам)
pnpm build # собрать dist/*.cjsapps/
bot/ Telegram-адаптер: webhook/polling, меню, мастер курса, админка, команды ops и admin
worker/ очередь напоминаний, оповещения об инцидентах, сверка, сводки, /metrics
panel/ веб-панель сотрудников (Fastify, HTML на сервере, без клиентских скриптов)
packages/
config/ переменные окружения → типизированный Config (ошибки называют переменные, не значения)
db/ схема, 17 миграций, слой доступа (Actors + SQL-предикаты), аудит, шифрование полей, копии
schedule/ чистые функции календаря: слоты, дедлайны, adherence
telegram/ клавиатуры, кодек кнопок, тексты напоминаний
i18n/ русский и узбекский (латиница)
report/ отчёт по курсу: PDF и CSV
logger/ pino с вычёркиванием секретов
deploy/ docker-compose.prod.yml, Caddyfile (HTTPS), образец настроек сервера
docs/ ТЗ, архитектура, руководство по пилоту
| Документ | Что внутри |
|---|---|
| docs/BOT_GUIDE.md | как пользоваться ботом: пациент, врач, опекун, администратор, правила и частые вопросы |
| docs/PILOT.md | Начните отсюда для запуска: развёртывание, резервные копии, откат, что утвердить клинике и юристу |
| docs/ARCHITECTURE.md | архитектура, модель данных, автоматы состояний, безопасность, решения D-1…D-130 |
| docs/TZ.md | исходное техническое задание v1.0 |
| PROJECT_STATUS.md | что сделано на каждом этапе, что проверено и чего нет, открытые вопросы |
| CONTEXT.md | договорённости, инварианты кода, грабли среды — для того, кто продолжает работу |
| CONTRIBUTING.md | как вносить изменения |
| SECURITY.md | как сообщить об уязвимости |
Одна команда поднимает базу, миграции, бот, воркер, панель, ежесуточные копии и HTTPS (Caddy):
docker compose --env-file .env.production -f deploy/docker-compose.prod.yml up -d --build
docker compose --env-file .env.production -f deploy/docker-compose.prod.yml exec backup node ops.cjs preflight --backups /backupspreflight отвечает на вопрос «можно ли пускать людей»: настройки, Telegram, схема базы, администратор, очередь, свежесть
копии. Подробно, со списком «до пилота обязательно» — в docs/PILOT.md.
- Поля с личными данными (имя пациента, названия препаратов, указания) шифруются на уровне приложения; ключи — только в окружении.
- Видимость данных — SQL-предикаты в каждом запросе; врач видит только своих пациентов, пациент — только себя, администратор не видит содержимого курсов.
- Согласие, отзыв согласия, запрос на удаление (обезличивание через 30 дней), показ истории будущему врачу — по решению пациента.
- В логах нет токенов, ключей и текстов назначений; тест на каждом прогоне ищет секреты в файлах репозитория.
- Резервные копии шифруются отдельным ключом (AES-256-GCM); восстановление репетируется командой
drill. - Веб-панель: CSP
default-src 'none', никаких скриптов, одноразовый вход из бота, CSRF, ограничения частоты запросов.
Уязвимость нашли? См. SECURITY.md.
| Этапы | Статус |
|---|---|
| 0–3 · ТЗ, архитектура, схема БД и права, ядро расписания | ✅ |
| 4–7 · Telegram-адаптер, врач и подключение пациента, мастер курса, старт и материализация | ✅ |
| 8–10 · воркер и напоминания, пауза/ревизии/отмена, история, adherence, уведомления врачу, опекун | ✅ |
| 11–13 · панель клиники и техническая панель, отчёты PDF/CSV, приватность и резервные копии | ✅ |
| 14 · пик напоминаний под лимитом Telegram, оповещения об инцидентах, метрики, защита от частых запросов | ✅ |
| 15 · пилот: команды оператора, проверка готовности, файлы для сервера, руководство | ✅ код · людям: утверждения |
| 16 · админка внутри бота: врачи, состояние, инциденты, администраторы | ✅ |
Честно о проверенности. Всё покрыто тестами на настоящем Postgres с поддельным Telegram, и каждый этап проходил
мутационную проверку (намеренные поломки кода, которые тесты обязаны поймать). Живьём проверены сборки, миграции, копии и
восстановление на локальной базе и ответ Telegram на токен. Ещё не проверено: полный диалог врача и пациента в настоящем
Telegram, docker compose up на сервере, нагрузка тысячами людей, открытие CSV в Excel. Тексты согласия не читал юрист,
узбекские тексты — носитель языка, медицинские — клиника: без этого настоящих пациентов пускать нельзя
(см. docs/PILOT.md, раздел 5).
TypeScript (strict) · Node 24 · pnpm workspaces · Fastify · grammY · PostgreSQL 16 · Drizzle ORM · Zod · pino · Luxon · pdf-lib · Vitest · tsup · Docker · Caddy · GitHub Actions
Правила работы — в CONTRIBUTING.md. Лицензия пока не выбрана: код закрытый, все права принадлежат владельцу проекта, пока он не решит иначе.