Skip to content

Case study

Running a Tutoring Academy on One Multi-Tenant Platform

Exactly one Stripe invoice per family per month, behind pre-deploy gates of 303 pytest modules, 86 Vitest suites and 20 Playwright flows.

Project
Online tutoring platform (LMS and CRM)
Industry
EdTech / SaaS
Role
Full-stack engineer
  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind CSS v4
  • FastAPI
  • Python 3.14
  • SQLModel
  • Pydantic v2
  • PostgreSQL
  • pgvector
  • Redis
  • Alembic
  • Stripe
  • Google Meet API
  • Docker
  • Vercel
  • Railway
  • GitHub Actions
  • Playwright
  • Vitest
  • pytest

The context

An online tutoring academy (confidential) runs its whole business on one platform: leads, scheduling, classes, attendance, billing and tutor payouts, split across a front-end and a backend repository.

The problem

The academy needed leads, scheduling, classes, attendance, billing and tutor payouts in one system, across four role classes.

My responsibility

  • Architected and shipped the multi-tenant platform end to end, with the backend as the sole authorization boundary
  • Built a 373-endpoint backend with 176 migrations under an expand, migrate, contract policy
  • Built the idempotent billing engine that issues exactly one Stripe invoice per family per month
  • Set up pre-deploy quality gates: 303 pytest modules, 86 Vitest suites and 20 Playwright flows
  • Authored roughly 995 of 1,656 commits across both repositories

Architecture

  1. Monthly run
  2. Idempotency key per family
  3. One Stripe invoice
  4. Payout records
The monthly billing run. A retried run can't issue a second invoice for the same family.

Key decisions

  • The backend is the only authorization boundary

    Each request resolves its tenant and role on the server before a scoped query runs, so all four role classes are governed in one place.

  • Expand, migrate, contract

    All 176 migrations follow an expand, migrate, contract policy, so schema changes ship in steps.

  • Idempotent billing

    Each monthly run carries an idempotency key per family, so the engine issues exactly one Stripe invoice per family per month.

  • Quality gates before every deploy

    303 pytest modules, 86 Vitest suites and 20 Playwright flows run before a deploy.

Technical challenges

  1. 1.Four role classes on one platform

    Leads, classes, attendance, billing and payouts each involve different roles. Keeping authorization in the backend alone means each rule is enforced in one place.

  2. 2.Billing that must not double-charge

    A billing run can be retried. The per-family idempotency key makes a retry safe: it can't produce a second invoice.

Results

  • Exactly one Stripe invoice per family per month
  • Pre-deploy quality gates of 303 pytest modules, 86 Vitest suites and 20 Playwright flows
  • Leads, scheduling, Google Meet classes, attendance, billing and tutor payouts in one system
  • Roughly 995 of 1,656 commits authored across both repositories

Building a SaaS product with AI in it?

From the data model to the deployed interface: multi-tenant platforms, AI voice agents, LLM features and Stripe billing.