This roadmap describes how LearnStack evolves from an architecture concept into a white-label platform for multi-branch education businesses that teach live.
LearnStack is not a single LMS implementation. It is an education-aware CMS, learning engine, and platform foundation that powers multiple brands, landing pages, catalogs, portals, and education products across domains — language schools, yoga studios, music schools, coding bootcamps — on the same code paths, differing only in tenant customization data (ADR-0018). That claim has a stated edge: see Platform Vision § Genericity boundary.
The roadmap also references the learnstack-hub companion (separate repository, see
ADR-0019). Hub's own plan lives in its own
repository at ../LearnStack-Hub/docs/roadmap/; the phases here cover only LearnStack's
side of the boundary.
Two kinds of decision, two treatments — the one-way-door test from ADR-0035:
If I add this six months from now, will I have to touch code that is already written?
Yes → ship it now. Tenant and organization isolation, the outbox_messages table
and its ownership, strongly-typed identifiers, the localization schema. Adding these
later means touching every query, every migration, every job payload.
No → ship the port now, the adapter on demand. Dapr, Kafka, APISIX, Vault, the Hub
integration, signed licence keys, custom-domain TLS automation, audit_log
partitioning. Each has a port in LearnStack.SharedKernel, a working default
implementation, an owning phase, and a written trigger condition. None of them blocks a
user-visible artefact.
The second consequence of that principle is Phase 02d: a two-tenant vertical slice that puts a working education site in a browser immediately after the kernel is sound, rather than five phases later. Genericity is proven continuously from Phase 02d onward, not deferred to the showcase phase.
- Phase 00: Product Strategy and Architecture Definition — complete
- Phase 01: Repository, Tooling, and Local Infrastructure — complete
- Phase 02a: Platform Kernel, Multi-Tenancy, Organization, and Foundation Sockets — in progress (packets 0–3 shipped)
- Phase 02d: Two-Tenant Walking Skeleton
- Phase 02b: Identity Integration, Session, and Events
- Phase 03: Identity Domain, Authorization, and Admin Foundation
- Phase 04: Headless CMS, Page Builder, and Media Library
- Phase 05: Education Catalog and Learning Content
- Phase 06: Public Site Renderer and Admin Studio
- Phase 07: Enrollment, Learner Portal, and Progress Tracking
- Phase 08a: Assessment, Notifications, and Background Jobs
- Phase 08b: Scheduling and Booking
- Phase 08c: In-App Live Classroom
- Phase 09: Billing, Integrations, and Analytics
- Phase 10: Tenant Customization Showcase (online English education)
- Phase 11: Production Hardening, Operations, and Scale
Hub-side tracks. These phases hold LearnStack's side of the boundary and point at the Hub repository for the rest:
- Phase 02c: Hub Integration — LearnStack side
- Phase 09b: Hub Billing — pointer; the plan lives in the Hub repository
- Phase 12: Hub Marketplace — pointer; post-MVP, optional
Identifier note. Phase identifiers are stable and load-bearing: they appear in commit messages, branch names, pull requests, architecture-test registrations, and across both repositories.
02dwas added after02band02calready existed, so it sorts last alphabetically while running before them in dependency order. The dependency map below is authoritative for order; filename order is not.
flowchart TB
p00[Phase 00<br/>Strategy]
p01[Phase 01<br/>Repo + Tooling]
p02a[Phase 02a<br/>Kernel + Tenancy + Org + Sockets]
p02d[Phase 02d<br/>Two-Tenant Walking Skeleton]
p02b[Phase 02b<br/>Identity Integration + Events]
p02c[Phase 02c<br/>Hub Integration]
p03[Phase 03<br/>Identity Domain + RBAC]
p04[Phase 04<br/>CMS + Media]
p05[Phase 05<br/>Catalog + Learning]
p06[Phase 06<br/>Renderer + Studio]
p07[Phase 07<br/>Enrollment + Portal]
p08a[Phase 08a<br/>Assessment + Notifications]
p08b[Phase 08b<br/>Scheduling]
p08c[Phase 08c<br/>Classroom]
p09[Phase 09<br/>Billing + Integrations]
p10[Phase 10<br/>Tenant Showcase]
p11[Phase 11<br/>Production + Demand-Gated Adapters]
p00 --> p01 --> p02a --> p02d --> p02b --> p03 --> p04 --> p05 --> p06
p06 --> p07 --> p08a --> p08b --> p08c --> p09 --> p10 --> p11
p02b -. unblocks .-> p02c
p02c -. parallel, non-blocking .-> p11
Reading the map. The spine is the critical path. Phase 02c hangs off it rather than
sitting in it: LearnStack runs on NullEntitlementProvider until a tenant must be
billed or plan-gated, which is the trigger condition
ADR-0035 records for it.
| Track | Relationship to the spine | Trigger |
|---|---|---|
| Phase 02c — Hub Integration | Parallel from Phase 02b onward; never blocks | A tenant must be billed or plan-gated |
Hub repository work (P02c-*) |
Independent repository, own cadence | See ../LearnStack-Hub/docs/roadmap/ |
| Phase 09b — Hub Billing | Pointer; the plan lives in the Hub repository | Commercial billing needed |
| Phase 12 — Hub Marketplace | Pointer; post-MVP, optional | Product-market evidence |
Demand-gated adapters (Dapr, Kafka, APISIX, Vault, licence keys, custom-domain TLS, audit_log partitioning) |
Land in Phase 11 unless their trigger fires earlier | Per the table in ADR-0035 |
A demand-gated item is not "deferred". It has a port, a working default implementation, an owning phase, and a trigger condition — all four written down. If a trigger fires early, the item moves to the phase where it fired and ADR-0035's table is amended.
The first goal is a platform core that is correct where correctness is expensive to retrofit, and thin where it is not:
- The tenant + organization + domain model is correct from the beginning
(ADR-0017), and its Row Level
Security implementation is the corrected template in
ADR-0003 Amendment 3 —
one
AND-ed policy,FORCE ROW LEVEL SECURITY, an explicitWITH CHECK, and a non-owning application role. Isolation tests run as that role, because a test that runs as the owner passes even when every policy is inert. - MUST-class audit is durable from the first command (ADR-0033). Audit correctness cannot be added later; audit scale can, and is.
- Module boundaries stay clear; architecture tests enforce them from Phase 02a,
including
Core_Modules_HaveNo_DomainSpecific_Names— the mechanical guarantee behind the platform's entire premise. - CMS and education catalog capabilities work together against tenant-defined content types, blocks, lesson items, taxonomies, and scoring / completion rules (ADR-0018).
- Public site, admin studio, and learner portal are powered by the same core — and so are tenants in unrelated domains, without code changes. Two tenants exist from Phase 02a Packet 7 onward, so every subsequent phase is tested against the genericity claim rather than assuming it.
- Live online classes happen inside the product through a provider-agnostic classroom layer.
- No vertical packs. The English-learning showcase is not a code module; it is the first tenant customization data set, exercised in depth in Phase 10.
- The control plane is a companion, not a prerequisite.
Every phase document carries the same six sections, with three declared exceptions noted below the table:
| Section | What it answers |
|---|---|
## Goal |
Why this phase exists, in a few sentences |
## Scope |
What is built, grouped by subsystem |
## Deliverables |
What exists at the end that did not exist at the start |
## Completion Criteria |
Observable statements a reviewer can check |
## Risks |
What tends to go wrong here, and the mitigation |
## Phase Exit Decision |
The gate: what must be true before the next phase begins |
Three exceptions, all deliberate:
- Phase 09b and Phase 12 are
pointer documents into the
learnstack-hubrepository, which owns their plan. They carry Goal, Scope on the LearnStack side, Trigger and Phase Exit Decision only; Deliverables, Completion Criteria and Risks live in the Hub's own roadmap. Restating them here would duplicate a plan this repository does not own. - Phase 01 predates the
## Phase Exit Decisionconvention and carries## Technical Notesinstead. Its annotation block records this; it is not a gap to fill.
Phases in progress additionally carry a dated > **Status** block at the top, listing
packets and their state. A packet is an independently reviewable, independently
mergeable slice with its own pull request; see Glossary.
The roadmap deliberately carries no effort estimates, owners, or timeboxes. It is a dependency and scope plan; sequencing decisions belong here, capacity decisions do not.
At the end of this roadmap, LearnStack can:
- Provision a tenant with at least one default organization — through the Hub for SaaS / Dedicated, through the CLI for Self-Hosted.
- Load tenant customization data (content types, page blocks, lesson item types, level taxonomy, scoring rules, completion rules, custom fields, templates) and render the tenant's product entirely from that data.
- Publish tenant-specific landing pages, navigation, course catalogs, and course detail pages.
- Manage courses, modules, lessons, and learning materials.
- Grant learner access to courses, gated by the tenant's plan entitlement where a plan exists.
- Track learner progress, with completion semantics defined by the tenant's
TenantCompletionRule. - Run quiz and placement-test flows scored by the tenant's
TenantScoringRule. - Run in-app live online classes with scheduling, attendance, classroom events, recording consent, and recording metadata.
- Extend payment, notifications, search, storage, analytics, and live-classroom providers through adapters.
- Run with
NullEntitlementProvider(no Hub),HubEntitlementProvider(SaaS / Dedicated), orSignedLicenseKeyEntitlementProvider(Self-Hosted, air-gappable) without code changes — onlyDeploymentModeconfiguration.DevelopmentandSaaSare wired end to end today;Dedicated,SelfHostedOnlineandSelfHostedAirGappedare prepared seams, not supported deployments, until Phase 11 builds their adapters and integration suites (ADR-0035).