Skip to content

Repository files navigation

LearnStack Hub

The control plane application for LearnStack — a separate codebase that owns tenant lifecycle, subscription / plan / billing, license issuance, entitlement projection, custom-domain administration, compliance caps, and the operator portal.

LearnStack Hub is not an LMS, not a tenant-facing surface, and never stores tenant content. Hub holds tenant metadata (plan, subscription, license, custom domain, compliance caps); tenant data (courses, lessons, learners, enrollments, classroom sessions) lives exclusively inside LearnStack core.

Status

Phase 02c — Repository Bootstrap (P02c-0) ✅. Solution scaffold + frontend monorepo + compose stack + CI + docs skeleton are in place. No Hub domain code yet — that lands in P02c-1 (Hub Domain Core: LearnStackTenant mirror, Plan, HubSubscription, Entitlement).

See docs/roadmap/README.md for the per-packet breakdown (P02c-0 through P02c-7) and the authoritative LearnStack-side roadmap.

make install   # one-time: deps + git hooks
make dev       # bring Hub-side compose stack up (requires learnstack compose already running)

Why a Separate Repo

LearnStack Hub ships as a separate git repository per ADR-0019 — separate CI/CD, separate release cadence, separate Keycloak realm (learnstack-hub vs. learnstack), separate operator audit stream. The two repos communicate through a closed four-endpoint HTTPS contract surface with mTLS + signed JWT + HMAC body signature on every call.

The architecture deep-dive lives in the sibling repo: docs/architecture/24-learnstack-hub.md.

Sibling Layout Expected

Hub repo's documentation cross-links to LearnStack core via relative sibling paths (../learnstack/...). The expected on-disk layout is:

<parent-dir>/
├── learnstack/        (https://github.com/cemililik/learnstack)
└── learnstack-hub/    (this repo)

If you check out the two repos somewhere other than as siblings, cross-repo doc links will 404. Multi-root workspace files (*.code-workspace) are gitignored — each developer keeps their own.

Dev Workflow

Hub repo's compose stack is deliberately minimal: it only runs services that are Hub-specific (Hub Dapr sidecar, Hub APISIX gateway, Postgres init). Everything else — Postgres, Valkey, Vault, Kafka, Keycloak, Mailpit — is shared with LearnStack core's compose stack and reached via host.docker.internal.

Boot order (each in its own terminal):

# 1. LearnStack core compose (shared backends)
cd ../learnstack
make dev

# 2. Hub-side compose (Dapr sidecar + Hub APISIX + Postgres init for learnstack_hub DB)
cd ../learnstack-hub
make dev

# 3. LearnStack core API
cd ../learnstack/backend
dotnet run --project src/LearnStack.Api

# 4. Hub API
cd ../learnstack-hub/backend
dotnet run --project src/LearnStack.Hub.Api

In production, the two repos deploy independently — the shared compose is a dev-time convenience only.

Direction At A Glance

  • Backend: .NET 10 + ASP.NET Core + EF Core + MediatR + Hangfire (queue jobs land in P02c-5+).
  • Database: PostgreSQL 18 (shared instance in dev under learnstack_hub database; separate instance in prod). Hub does not use Row-Level Security — Hub data is operator-administered, not tenant-isolated.
  • Cache / Pub-Sub / Secrets: Valkey 8 (shared instance, hub:* namespace), Kafka (shared cluster, learnstack.hub.* topic prefix), Vault (shared instance, learnstack-hub/* path prefix) — all accessed via Hub's own Dapr sidecar.
  • API Gateway: APISIX in standalone YAML mode on its own port (9180 / 9543); separate instance from LearnStack core's APISIX.
  • Frontend: Next.js 15.5 (App Router) operator portal under frontend/apps/operator-portal; flat-config + Next 16 migration tracked in P02c-4 (apps/operator-portal/.eslintrc.cjs TODO). Authenticates against the learnstack-hub Keycloak realm with MFA required.
  • Identity: Keycloak learnstack-hub realm (separate from learnstack tenant-facing realm). The realm export lives in the sibling repo at learnstack/infra/keycloak/realms/learnstack-hub.json because LearnStack core's compose imports both realms at first boot.
  • Architecture: Modular monolith (mirrors LearnStack's pattern) with explicit module contracts.

Hub HTTPS Contract Surface

Four endpoints, closed list (Standards 20 § Hub HTTPS Contract Surface):

Direction Method + Path Purpose Hosted in
Hub → LearnStack POST /api/internal/tenants Create tenant + default org LearnStack core
Hub → LearnStack PUT /api/internal/tenants/{id}/entitlements Push entitlement projection (incl. host mapping per ADR-0022 Amendment 1) LearnStack core
LearnStack → Hub POST /api/v1/internal/license/verify License verify Hub
LearnStack → Hub POST /api/v1/usage/report Usage telemetry Hub

Every call carries mTLS (LearnStack-internal CA) + RS256 JWT (aud=learnstack-internal, exp ≤ 5min) + HMAC-SHA256 body signature in X-Signature. Adding a fifth endpoint requires a new ADR.

Documentation Map

Hub-specific (this repo)

Authoritative cross-cutting (LearnStack core)

Conventions

  • All documentation in English (mirrors ADR-0007).
  • Diagrams use Mermaid in fenced code blocks.
  • Cross-cutting architectural decisions live in LearnStack core under learnstack/docs/decisions/; Hub-internal-only decisions live here under docs/decisions/ with the HUB-NNNN numbering series so they never collide with LearnStack ADR numbers.
  • Engineering rules from LearnStack's Standards corpus apply here unless explicitly overridden by a Hub-internal ADR.
  • Single source of truth: each piece of knowledge lives in exactly one place. Linking is preferred over copying.

About

No description, website, or topics provided.

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages