Telegram-бот для отправки реплик deko через inline-режим. Пользователи могут искать реплики, добавлять их в избранное, смотреть или отключать личную аналитику и поддерживать бота через Telegram Stars. Администратор управляет каталогом, статистикой и резервными копиями прямо в Telegram.
Боевой бот: https://t.me/dekoquotes_bot
Проверки надёжности и порядок восстановления: Operations checklist.
Это одно Node.js-приложение на TypeScript:
- grammY обрабатывает polling при локальной разработке и webhook в production;
- PostgreSQL и Drizzle ORM хранят каталог, пользователей, избранное и платежи;
- Fluent содержит весь пользовательский текст;
- FFmpeg конвертирует присланные MP3 в OGG/Opus;
pg_dumpиpg_restoreсоздают и восстанавливают зашифрованные копии базы.
Сессии меню и диалогов хранятся в памяти до 24 часов и сбрасываются при перезапуске. Приложение рассчитано на одну реплику процесса.
Основные каталоги:
drizzle/ схема, запросы и миграции PostgreSQL
locales/ Fluent-локализация
scripts/ аварийные локальные инструменты
src/backup/ создание, проверка и восстановление копий
src/bot/ Telegram-команды, меню и диалоги
src/main.ts основной процесс бота
src/backup-cron.ts короткоживущий процесс ежедневного бэкапа
Требуются Node.js 24, pnpm, PostgreSQL, FFmpeg и PostgreSQL client tools.
pnpm install
cp .env.example .env
pnpm db:migrate
pnpm devДля локальной разработки обычно используются BOT_MODE=polling и отдельный тестовый Telegram-бот. В production используется BOT_MODE=webhook.
Обязательные для основного процесса:
BOT_TOKEN— токен Telegram-бота;BOT_MODE—pollingилиwebhook;DATABASE_URL— строка подключения PostgreSQL;BACKUP_ENCRYPTION_KEY— 32 байта в base64;- для webhook также
BOT_WEBHOOKиBOT_WEBHOOK_SECRET.
ADMIN_IDS — JSON-массив Telegram ID администраторов. Остальные настройки и значения по умолчанию перечислены в .env.example.
Ключ для резервных копий создаётся так:
openssl rand -base64 32Храните его отдельно от самих копий: без ключа восстановление невозможно.
Основной сервис собирается из корневого Dockerfile. Миграции запускаются Railway pre-deploy command:
pnpm db:migrateСтандартная команда запуска контейнера — node ./dist/main.mjs.
Для ежедневного бэкапа создайте второй Railway Cron service из того же репозитория и Dockerfile:
- cron schedule:
0 21 * * *— это 00:00 по Минску (UTC+3); - start command:
node ./dist/backup-cron.mjs; - переменные:
BOT_TOKEN,DATABASE_URL,BACKUP_ENCRYPTION_KEY,BACKUP_CHAT_IDи настройки логов.
BACKUP_CHAT_ID должен указывать на закрытый канал, куда бот может отправлять документы. Если переменная отсутствует, cron пишет в лог, что бэкап отключён, и завершается с кодом 0. При ошибке выполняются три попытки, после чего бот старается отправить в канал текстовое уведомление и завершает процесс с ненулевым кодом.
Команда /export создаёт зашифрованный файл .dump.enc и отправляет его администратору. /import принимает такой файл, проверяет формат и схему, просит подтверждение, отправляет аварийную копию текущей базы и только затем восстанавливает данные. Во время restore новые обращения к базе временно блокируются.
Если восстановление или проверка базы завершились ошибкой, бот сохраняет блокировку до проверки и восстановления через инструменты PostgreSQL. Перезапуск снимает эту блокировку: выполняйте его только после проверки базы. Порядок действий и тестовое восстановление описаны в Operations checklist.
Старые plaintext-дампы можно зашифровать или расшифровать локально:
pnpm backup:crypto encrypt backup.dump backup.dump.enc
pnpm backup:crypto decrypt backup.dump.enc backup.dumpМиграция 0018_analytics_enabled переименовывает и инвертирует поле аналитики, а 0017_simplify_runtime удаляет старые runtime-таблицы. Старый процесс не должен работать одновременно с этими миграциями.
Безопасный порядок для этого единственного перехода:
- Выполнить
/maintenanceи/exportна старой версии. - Остановить старый bot deployment, чтобы он больше не обращался к базе.
- Развернуть новую версию с Railway pre-deploy command
pnpm db:migrate. - Проверить
/voices, inline-отправку,/mydata,/exportи затем выключить/maintenance. - После успешной проверки удалить старые Railway API и Redis services.
Обычные последующие деплои снова используют стандартный pre-deploy без этой ручной остановки.
/voices открывает единое меню: добавление реплики, список с пагинацией и действия над выбранной репликой. Можно изменить название, ID, файл или удалить запись. Добавление идёт по шагам: название → ID → MP3. /newvoices сохранена как скрытая команда-алиас и не публикуется через /setcommands.
FFmpeg проверяется только при запуске добавления или замены файла. pg_dump и pg_restore вызываются только командами и cron-задачей, которым они нужны.
pnpm typecheck
pnpm lint
pnpm test
pnpm buildMIT — см. LICENSE.