
Production · 2026/Apr 2026 – Present/Founding engineer
OpenVDK
I own the production sales loop: Telegram bot, Mini App, and operator admin on one TypeScript API. The money path is a state machine — a retry does not open a second invoice or grant access twice. Price and identity live on the server. Releases go through CI/CD.
- TypeScript
- PostgreSQL
- Redis
- React
- Docker
- CI/CD
- Bun
- Hono
- Prisma
- BullMQ
- grammY
- Build and deploy
- CI/CD
- Idempotent payment path
- 1
- Clients, one API
- 2
- Processes / one image
- 3
- Compose services
- 6
The money path is a state machine
Create payment is a Serializable get-or-create: reuse a pending invoice, honor clientRequestId, retry on serialization conflicts. After the provider confirms, a claim lease and a fulfillment marker keep the VPN panel and the local subscription from applying twice.
An invoice watcher runs until expiry, then a late confirmation window. Operator audit is a first-class part of the payment machine.
- 01ReserveSerializable get-or-create
- 02SBPPlatega invoice
- 03WatchExpiry + late window
- 04Claim10-minute lease
- 05ProvisionRemnawave + local sub
- 06AuditOperator trail
What I owned
The full commercial loop in production: Telegram identity, trial through the VPN panel, SBP checkout, key delivery, renewal reminders, and an operator console for revenue, users, keys, broadcasts, payments, and audit.
I designed clients, jobs, and fulfillment as one contract. The UI is a surface; the product is a payment that can be retried without corrupting subscriptions.
One image, three processes, six services
PostgreSQL is the source of truth; Redis backs the job queue. API, bot, and worker share one Bun image and three entrypoints behind Nginx — TLS and two React SPAs, /api to Hono.
Admin JWT is stored in the database, not in environment variables. Env only seeds the first operator. The admin UI is served on a configurable base path.
Two clients, one contract
Price is server-side. Mini App authentication is Telegram initData. Bot purchases are origin TELEGRAM; Mini App purchases are origin WEB. Deep links use startapp tokens so the SPA path never lands in the bot payload.
Key activation is one service — bot conversation and POST /api/tma/keys/activate. Broadcasts fan out as jobs with a 20/s limiter against the Bot API.
CI/CD and operations
I set up CI/CD: build, migrate, and deploy from git. Prisma migrate deploy runs when the API container starts. Renewal reminders are keyed off endsAt in a fixed IANA timezone so a restart does not double-send.
The operator console tails container logs over SSE from the same Compose stack.
How the product is structured
Bot
The sales channel inside Telegram. First contact, trial access, subscription menu, and renewal. It is also the gate into the Mini App: without starting the bot, the web client stays closed.
Mini App
The subscription UI. Location picker, plan, device list, payment result. This is not a checkout with a free-form amount: the client confirms the server-side plan.
Admin
Operations. Revenue and payments, users and keys, broadcasts, audit, container logs. How the operator runs production without touching the code.




