Building Orkesta: engineering notes from a multi-tenant event platform
Every event ends the same way: one person at the door with a printed list and a phone, trying to reconcile a guest spreadsheet, a notebook of table assignments, and a WhatsApp thread full of “did you confirm?”. Three tools that never agree, desyncing exactly when the pressure peaks. Orkesta is what I built to collapse all three into one flow — and these are the engineering notes from doing it.
The real problem isn’t features, it’s coordination
The planners I built for don’t need another app. They need every question — who’s coming, with how many guests, at which table, who actually walked in — to live in one place and stay in sync from invite to check-in. So I didn’t start from a feature list. I started from the question: what has to be true for the day of the event to not fall apart? Everything that didn’t serve that didn’t get built.
Multi-tenant from line one
The first real decision was treating Orkesta as a true multi-tenant SaaS from the start, not a single-event demo I’d “scale later.” Many organizers, each with their own events and isolated data, and four roles — platform admin, organizer, check-in staff, guest — enforced on the server, not just hidden in the UI. Retrofitting tenant isolation is a rewrite; baking it into the data model and every query from day one is just discipline.
If authorization only lives in the frontend, it doesn’t exist. Every protected endpoint checks role and ownership.
The stack, and why each piece earns its place
- Angular 19 + SSR. The public invitation is the one page that has to load fast on a phone, because that’s exactly where guests open it. Server-side rendering buys that first paint instead of shipping a blank shell.
- NestJS in strict TypeScript. A documented REST API with role-based access control applied server-side. Strict types end-to-end means the contract between front and back is checked at build time, not discovered in production.
- Prisma + PostgreSQL. A relational model fits the domain — organizers own events, events own guests, guests map to tables. Prisma keeps that schema typed and the migrations honest.
- Redis. Reports and notifications don’t belong in the request path. Pushing that work to the background keeps the API responsive when a big guest list confirms all at once.
- JWT access + refresh. Short-lived access tokens, refresh for continuity — standard, boring, and exactly what auth should be.
Nothing exotic. The whole point was a base I can reason about under pressure.
What I learned
Owning the full stack changes how you decide. There’s no one to hand the backend problem to when the frontend needs it solved — so you solve it, and you solve it properly, because you’re the one who lives with the choice. That pressure is a feature: it kills shortcuts you’d otherwise rationalize.
Cache invalidation is the quiet tax. Moving work to Redis is easy; making sure the right thing recomputes when state changes is the part that actually earns the performance. I’d rather pay that cost deliberately than ship a fast API that lies about the guest count.
Constraints clarify. “What has to be true for the day to not fall apart” turned out to be a sharper design tool than any feature backlog. It’s the same question I keep coming back to — and it’s why Orkesta is a product running in production, not a prototype I keep meaning to finish.