NRC Zaporizhzhia — a course platform
Someone without a browser gets exactly the same access to the courses as on the site — and there is no second version of the truth
The challenge
The training centre had a site with the courses, and talked to people separately in a messenger. The timetable lived in one place, applications in another, reminders were sent by hand. The classic situation where two systems drift apart and nobody knows which is right.
The solution
Courses, applications, the waitlist, reminders and news all live in one database. The public site, the admin and the Telegram bot read the same rows. The bot does not mirror the site menu — it guides the conversation, finds the right course, and drops the application into the same table the web form writes to.
- ✓ Enrol in a course entirely inside Telegram, no browser needed
- ✓ Waitlist and released-seat offers run as background jobs on BullMQ
- ✓ Bilingual content as data: every entity has its own translation table
- ✓ A separate three.js front end with GSAP — an interactive scene, not a decorative canvas
- ✓ Role-based access in the admin, on JWT
Architecture
- pnpm monorepo: web, admin, api, bot, experience
- NestJS + Prisma + PostgreSQL
- Redis and BullMQ for reminders and offers
- Sharp for image processing, Zod at the boundaries
- Docker Compose for dev, dev-server and prod
Why it was built this way
When a bot and a site keep separate databases, drift is a matter of time, not probability. Here they physically cannot diverge: it is one row in one table, shown two ways.
Stack
TypeScript · NestJS · Prisma · PostgreSQL · Redis · BullMQ · Next.js · React · three.js · GSAP · grammY · Docker · i18next