LMS Platform
Live · self-hostedA course-selling platform — instructors create courses with chapters and video lessons and set a price; students browse a catalog, pay, and track progress. Three roles: student, instructor, admin.
1 The Problem
Most course platforms are demoed on a managed host and nowhere else — which answers "can you build a feature" but not "can you own the infrastructure it runs on." The goal here was to build a real product (courses, payments, video, roles) and then prove it could ship two different ways from the same source: a zero-ops managed platform, and a box you configure and operate yourself.
2 The Approach
Content and access are strictly separated from delivery. Course structure (chapters, lessons, ordering) lives in Postgres via Prisma. Video never touches the app's own storage — it's uploaded straight to Mux, and playback is gated by signed tokens: an unenrolled user cannot obtain a working video URL at all, not even by guessing one. Payments run through Stripe Checkout, and the webhook handler verifies every signature and is written to be idempotent, so a replayed event can never double-grant access to a course.
3 Architecture — one codebase, two production deployments
The same repository ships to production two different ways simultaneously, sharing the same external services (Neon, Clerk, Stripe, Mux, Blob) but running on entirely different infrastructure:
The CI/CD pipeline for Path B: typecheck → build → push image to ECR (tagged :latest and :<sha>) → SSH into EC2 → pull, restart the container, prune old images → smoke-check the public URL. Every image keeps its commit SHA, so rollback is one docker run away.
The actual pipeline run from this repository's GitHub Actions.
4 Tech Stack
5 Result
A working course marketplace with real payment integrity and video protection, deployed and operating on two independent production environments from a single codebase.