
Продакшен · 2026/апр. 2026 — сейчас/ведущий инженер продукта
OpenVDK
Я отвечаю за продакшен-контур: Telegram-бот, Mini App и админка оператора на одном TypeScript API. Оплата — конечный автомат: повтор не открывает второй счёт и не выдаёт доступ дважды. Цена и идентичность живут на сервере. Релизы идут через CI/CD.
- TypeScript
- PostgreSQL
- Redis
- React
- Docker
- CI/CD
- Bun
- Hono
- Prisma
- BullMQ
- grammY
- сборка и деплой
- CI/CD
- идемпотентный контур оплаты
- 1
- клиента, один API
- 2
- процесса / один образ
- 3
- сервисов Compose
- 6
Оплата — конечный автомат
Создание платежа — Serializable get-or-create: переиспользовать pending-счёт, учитывать clientRequestId, повторять при конфликте сериализации. После подтверждения провайдера claim-lease и маркер fulfillment не дают VPN-панели и локальной подписке примениться дважды.
Watcher счетов работает до expiry, затем окно позднего подтверждения. Аудит оператора — часть автомата оплаты.
- 01ReserveSerializable get-or-create
- 02СБПсчёт провайдера
- 03Watchexpiry + late window
- 04Claimlease 10 мин
- 05ProvisionVPN-панель + локальная sub
- 06Auditжурнал оператора
Зона ответственности
Полный коммерческий контур в продакшене: идентичность в Telegram, trial через VPN-панель, оплата по СБП, выдача ключа, напоминания о продлении и консоль оператора — выручка, пользователи, ключи, рассылки, платежи, аудит.
Клиенты, очереди и fulfillment спроектированы как один контракт. UI — поверхность; продукт — платёж, который можно безопасно повторить.
Один образ, три процесса, шесть сервисов
PostgreSQL — источник истины, Redis — очередь задач. API, бот и worker делят один образ Bun и три entrypoint за Nginx: TLS, две React SPA, /api на Hono.
JWT админа хранится в базе, не в переменных окружения. Env только сидирует первого оператора. Админка отдаётся с настраиваемого base path.
Два клиента, один контракт
Цену задаёт сервер. Mini App аутентифицируется через Telegram initData. Покупки из бота — origin TELEGRAM, из Mini App — origin WEB. Deep links идут через startapp, чтобы путь SPA не попадал в payload бота.
Активация ключа — один сервис: conversation в боте и POST /api/tma/keys/activate. Рассылки разбираются на jobs с лимитом 20/с к Bot API.
CI/CD и эксплуатация
Собрал CI/CD: сборка, миграции и деплой из git. prisma migrate deploy — на старте API-контейнера. Напоминания о продлении привязаны к endsAt в фиксированном IANA-поясе, чтобы рестарт не слал дважды.
Консоль оператора читает логи контейнеров по SSE из того же Compose-стека.
Как устроен продукт
Бот
Канал продаж внутри Telegram. Первый контакт, пробный доступ, меню подписки и продление. Он же выпускает человека в Mini App: без старта бота веб-клиент не пускает.
Mini App
Интерфейс подписки. Выбор локации, тариф, список устройств, экран после оплаты. Это не касса со свободной суммой: клиент подтверждает серверный тариф.
Админка
Эксплуатация. Выручка и платежи, пользователи и ключи, рассылки, аудит, логи контейнеров. То, чем оператор управляет продакшеном, не заходя в код.




