E-Learning Platform Architecture: Multi-Tenant Courses, Progress Tracking, and Video Delivery
Most learning platforms do not fail because the video player is bad. They fail because of choices made in the first month of e-learning platform development: how course content is versioned, how tenants are separated, and where progress events get written. Those decisions cost almost nothing to get right at the start. Fixing them later, once ten institutions and fifty thousand learners depend on the system, means a migration project with real downtime risk.
This post covers the four architecture problems we see most often when edtech teams bring us their platform: course versioning, multi-tenant isolation, progress tracking under write pressure, and video delivery. It ends with the stack we recommend for European edtech SaaS and the compliance rules you cannot postpone. If you are still deciding which features belong in your product at all, start with our post on must-have features in education software and come back here for the data model.
Course versioning: learners are mid-course while you edit
Here is the scenario that breaks naive course models. An instructor updates module 3 of a ten-module course. Four hundred learners are somewhere inside that course. Sixty of them already passed the old quiz in module 3. What does their progress mean now?
If your lessons table has one row per lesson and the instructor edits that row in place, you have silently rewritten history. Certificates issued last month now point to content that no longer exists. A learner who disputes a failed quiz cannot be shown the questions they actually answered.
The pattern that works is snapshot-based versioning. A course has a mutable draft and immutable published versions. Publishing creates a new version row and deep-copies (or content-addresses) the module and lesson structure. Enrollments pin to a version. Progress records reference the pinned version, never the draft.
Two practical rules follow from this:
- New enrollments always get the latest published version. Existing enrollments keep their pinned version by default, with an explicit migration path when the change is a typo fix rather than a restructuring.
- Store a diff summary between versions. When an institution asks why cohort A and cohort B saw different content, you want an answer in minutes, not an archaeology project.
The storage overhead is smaller than teams fear. Course structure is tiny compared to video. Copying a few hundred rows per publish is nothing; losing the audit trail is expensive.
Multi-tenant isolation between institutions
Most edtech SaaS platforms serve many institutions from shared infrastructure. A university, a corporate training department, and a certification body all live in the same database. The question is how hard the walls between them are.
We have written about the general trade-offs in SaaS architecture work before, and for e-learning the short version is: shared schema with a tenant discriminator column is fine for most platforms, but only if you enforce it below the application layer. PostgreSQL row-level security policies keyed on the tenant ID catch the query someone forgot to scope. In a Symfony application, a Doctrine filter that appends the tenant condition to every query gives you the same guarantee one layer up. Use both. The cost is minutes of configuration; the alternative is explaining to a university why another institution saw their student roster.
Some contracts force a stronger model. Public institutions in Germany regularly require that their data is separable on request, which pushes you toward schema-per-tenant or at least tenant-partitioned tables with clean export paths. Decide this before you sign the contract, because retrofitting schema-per-tenant onto a shared-schema platform is one of the more painful migrations we get called in for.
Identity deserves the same care. Learners often exist in multiple tenants: a person can be a student at one institution and a course author at another. Model the person once and the tenant membership as a separate relation with its own roles. Platforms that duplicate the user per tenant end up with password reset chaos and GDPR deletion requests that miss half the records.
Progress tracking without a write bottleneck
Progress tracking is where e-learning platforms quietly fall over. The granularity product wants is high: video position every few seconds, every quiz attempt, every interactive exercise. Multiply by concurrent learners and you get a write load that dwarfs everything else on the platform. A midsize platform with 5,000 concurrent video watchers emitting a position event every 10 seconds produces 500 writes per second on that one table, all day.
Writing each event straight into a normalized progress row in your main database is the mistake. It works in the demo, then lock contention and index bloat arrive with the first big customer.
The shape that holds up is a split between the event stream and the materialized state:
| Layer | What it stores | Where |
|---|---|---|
| Event log | Raw events: video heartbeat, quiz attempt, exercise completion | Append-only table or queue, batched writes |
| Materialized state | Current position, completion percentage, best quiz score | Small row per enrollment, updated asynchronously |
| Reporting | Aggregates per cohort, course, tenant | Rebuilt from the event log on schedule |
Video heartbeats do not need durability guarantees. Buffer them client-side, send them in batches of 10 to 30 seconds, and treat the loss of one batch as acceptable. Quiz attempts are the opposite: those are legal records in some contexts, so they go through the durable path with idempotency keys so a retried request cannot record two attempts.
The materialized state table stays small and hot, which keeps the learner dashboard fast. The event log gives you replay: when product asks for a new metric next quarter, you rebuild it from history instead of shipping a tracking change and waiting three months for data.
Video delivery: CDN, signed URLs, and HLS
Never serve course video from your application servers, and never serve it from a public bucket either. Paid course content behind a public URL gets scraped within weeks.
The standard pipeline looks like this. Instructors upload through a progressive, resumable upload (tus or S3 multipart) so a 4 GB recording over hotel Wi-Fi survives interruption. A transcoding step converts the source into HLS renditions at several bitrates, generates thumbnails, and produces caption files. The output lands in object storage behind a CDN.
Access control lives in signed URLs. The application checks the enrollment, then issues a short-lived signed URL (or signed cookie for HLS, since a playlist references many segment files) scoped to that learner. Expiry of a few hours balances security against playback interruptions. The CDN validates the signature, so your servers never touch video bytes.
Adaptive bitrate matters more in education than in entertainment. Learners watch on campus networks, on trains, on old laptops. A 240p rendition that keeps playing beats a 1080p stream that buffers. Captions are not optional either, both for accessibility law and because a meaningful share of learners watch with sound off.
Auto-generate captions in the pipeline, but give instructors an editing pass. Automatic transcription of domain vocabulary is still rough, and a chemistry course with mangled formula names in the captions looks careless.
Certificates and tamper-evident audit trails
A certificate is a claim that a specific person completed a specific course version with a specific result on a specific date. Every one of those references must be immutable, which is why certificates depend on the versioning decision from the first section.
Store the certificate as a signed record: a hash of the certificate payload, signed with a platform key, verifiable through a public URL. When an employer checks a certificate three years later, verification should not depend on your relational database still containing the original rows in their original state. Hash-chaining certificate issuance into an append-only log is cheap insurance for the day a dispute or an accreditation audit arrives.
Compliance shapes e-learning platform development from day one
Three regimes matter for most of our clients. GDPR applies to every learner in the EU: right to erasure, data minimization, and a clear answer to where video analytics data flows (which affects your choice of CDN and transcoding provider). FERPA applies if US educational institutions are your customers; it constrains who may see student records and forces role separation your permission model has to express. Accessibility means WCAG 2.1 AA across the UI plus captions on all video, and in the EU the European Accessibility Act has made this contractual reality rather than a nice-to-have since 2025.
None of these bolt on cleanly. Erasure is easy when identity is modeled once, painful when learner rows are duplicated per tenant. Captions are easy when the transcoding pipeline produces them, painful when three thousand videos exist without them.
A stack that works for European edtech SaaS
For clients building in Europe we usually land on: Symfony with API Platform for the backend, PostgreSQL with row-level security for tenant isolation, Redis plus a message queue (Symfony Messenger with RabbitMQ or SQS) for the event pipeline, Next.js for the learner-facing frontend, and an EU-region object store with a CDN that supports signed cookies for video. Transcoding through a managed service rather than self-hosted FFmpeg farms, unless video volume is your core cost driver.
This stack is boring on purpose. E-learning platforms live or die on data integrity and delivery reliability, and every component above has a decade of production history behind it. If you want a second opinion on your own choices, that is what our tech stack strategy engagements are for, and if the platform already exists and creaks, a code and architecture review finds the load-bearing problems before your biggest customer does.
Building or rescuing an e-learning platform right now? We help edtech teams with web application development and architecture work of exactly this kind. Write to hello@wolf-tech.io or have a look around wolf-tech.io to see how we work.

