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
- Monthly run
- Idempotency key per family
- One Stripe invoice
- Payout records
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.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.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