Back to home
Case Study

We built a production SaaS. Here is how it works

Clasify is our own product: a white-label platform that academies run their teaching on. It is also the honest answer to “what have you built?” — a live multi-tenant system you can sign up for and inspect rather than a logo on a wall.

Why the portfolio is one project

We could pad this section. Most agency sites do — a grid of logos, a delivery count, a satisfaction percentage nobody audits. We would rather show one system in enough depth that you can judge the engineering yourself.

Clasify runs real academies with real students in live video lessons, takes real payments, and holds their data under their own branding and their own domains. Every operational problem in that sentence is one we had to solve properly, because we are the ones woken up when it breaks.

What follows is what is actually running. The public site you are reading is part of the same codebase.

For a technical reader, the stack: React and Vite with TypeScript on the front end; Express and Prisma against PostgreSQL behind it; Socket.IO for presence and live classroom state, with Redis holding the state shared across processes; WebRTC for the media itself, relayed through a coturn server we host; S3-compatible object storage for recordings; Caddy terminating TLS and issuing certificates for customer domains; Prometheus metrics throughout; and Vitest plus Playwright in the pipeline. Chosen to be straightforward to hire for, not to be interesting.

What is running in production

Every item here is something we built and still run ourselves — not a service line we have only read about.

Multi-tenant isolation

Each academy is a tenant with its own subdomain or verified custom domain. Vendor pages, brand assets and robots.txt are all gated off tenant hosts, so on an academy’s own domain there is nothing on the page that points back to a vendor.

Live classrooms over WebRTC

In-browser video lessons with a self-hosted TURN relay, so students behind restrictive networks still connect instead of silently failing to join.

Session recording

Lessons recorded and streamed directly to object storage, with playback restricted to administrators and a state machine that survives an interrupted session.

Exactly-once payments

Subscription billing through a payment gateway with idempotency keys and claim-before-charge, so a lost response cannot double-charge — a bug we found and closed before a customer met it.

Custom domains, automatically

Customers point their own domain at the platform and get a certificate issued without anyone touching a server, with the vendor’s own marketing pages 404ing on that host by design.

Twelve locales, full right-to-left

A typed catalogue where an unregistered namespace is a build error rather than a screen of raw keys, with Arabic plural rules and locale-prefixed URLs carrying reciprocal hreflang.

Monitoring and backups

Metrics, health and readiness endpoints, alerting, and encrypted off-site backups that have been restored and verified rather than merely scheduled.

Immutable deploys

Builds pinned to an image digest with a one-command rollback, and schema migrations applied in a one-shot step before the new image is swapped in — so a failed migration aborts the release instead of taking the running app down with it.

What it taught us

The same sequence on every engagement, whatever the stack.

1

Foundations cannot wait

Tenancy, billing and permissions decided first. Every one of the three is brutally expensive to change once customers depend on the behaviour.

2

Design for the failure, not the demo

Lost responses, duplicate webhooks, interrupted recordings, dropped connections. The happy path is the easy tenth; the rest is where products are actually judged.

3

Operating it changes how you build it

Running your own product means every shortcut comes back to you personally. It is the fastest available education in what is worth doing properly.

Straight answers

The questions that actually come up on a first call.

Want something like this built?

If your product needs tenants, subscriptions, live media or a payment path that cannot afford to be wrong, this is the work we do. Tell us what you have in mind.

Every project starts with a scoping conversation and a written estimate before any code is written. No retainer required to talk.