Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ tenant running the same code paths.
LearnStack ships in three production deployment modes — SaaS, Dedicated,
Self-Hosted — backed by the companion **`learnstack-hub`** repository
(separate repo, see [ADR-0019](docs/decisions/0019-learnstack-hub.md)).
The Hub repo lives at sibling path `../learnstack-hub` on developer
workstations; GitHub: https://github.com/cemililik/LearnStack-Hub.
Phase 02c P02c-0 (Hub repo bootstrap) shipped 2026-05-21 — see the
Phase 02c roadmap doc for the per-packet status.

## What state this is in

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ LearnStack ships in three production deployment modes — SaaS, Dedicated, Self-
backed by the companion **`learnstack-hub`** repository which provides the SaaS /
Dedicated control plane, plan editor, custom-domain admin, and license-key issuance.

The Hub repo is expected to live at `../learnstack-hub` (sibling to this repo on the
developer's workstation) so the cross-repo doc cross-links resolve. See
[learnstack-hub on GitHub](https://github.com/cemililik/LearnStack-Hub) and
[docs/roadmap/phase-02c-hub-foundation.md](docs/roadmap/phase-02c-hub-foundation.md).

## Status

Phase 01 complete. The repository now holds the .NET 10 solution scaffold (7
Expand Down
64 changes: 64 additions & 0 deletions docs/roadmap/phase-02c-hub-foundation.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,69 @@
# Phase 02c: LearnStack Hub Foundation (parallel track)

> **Status (2026-05-21).** Phase 02c in progress.
>
> **P02c-0 — Repository bootstrap ✅**
> Sibling `learnstack-hub` git repository created (GitHub:
> https://github.com/cemililik/LearnStack-Hub). Backend solution
> (`LearnStack.Hub.slnx`) with 7 core projects + 4 test projects builds
> green (0 warnings, 0 errors); 4 architecture tests + 1 smoke test pass.
> Frontend pnpm monorepo (`apps/operator-portal` + `packages/{config,sdk,ui}`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The frontend application directory is listed as apps/operator-portal, but the project is consistently referred to as learnstack-hub-web in README.md (line 68), CLAUDE.md (line 130), and later in this file (line 101). To maintain consistency across the documentation and avoid confusion between the directory structure and the project name, consider aligning the directory name with the established project name.

Suggested change
> Frontend pnpm monorepo (`apps/operator-portal` + `packages/{config,sdk,ui}`)
> Frontend pnpm monorepo (apps/learnstack-hub-web + packages/{config,sdk,ui})

> typechecks, lints, and builds. Hub-side compose stack
> (Dapr placement + sidecar on 50006 / 3501 / 50002, APISIX on 9180,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ports 50002 (Dapr placement) and 9180 (APISIX admin) are standard defaults that will likely conflict with the core LearnStack platform's services when both repositories are running as siblings on the same developer workstation. Since other ports like 50006 and 3501 have already been offset to avoid conflicts, these should also be shifted (e.g., to 50007 and 9181) to ensure a smooth local development experience.

Suggested change
> (Dapr placement + sidecar on 50006 / 3501 / 50002, APISIX on 9180,
> (Dapr placement + sidecar on 50006 / 3501 / 50007, APISIX on 9181,

> Postgres init for the `learnstack_hub` database) declared; shares
> LearnStack core's Postgres / Valkey / Vault / Kafka / Keycloak / Mailpit
> via `host.docker.internal`. Hub CI workflow (backend + frontend + meta
> + secret-scan) mirrors LearnStack core's shape. Documentation skeleton
> in place: `docs/architecture/contract-with-learnstack.md` points to
> LearnStack-side authority for the four-endpoint contract surface;
> `docs/decisions/` reserves the `HUB-NNNN` Hub-internal ADR series;
> `docs/glossary.md` covers Hub-specific terms. No Hub domain code yet —
> that lands in P02c-1.
>
> **P02c-1 — Hub Domain Core ⏳ Next**
> `LearnStackTenant` (mirror), `Plan`, `HubSubscription`, `Entitlement`
> aggregates + per-module DbContexts + initial EF migrations; Hub-side
> equivalent of LearnStack core P02a-2 (SharedKernel: `Result<T>`,
> `Entity<TId>`, `IClock`, Vogen) + P02a-3 (cross-cutting foundation).
> `Hub_NeverStores_TenantData` and
> `Hub_Modules_DoNotReference_LearnStack_Internals` architecture tests
> become real once modules land.
>
> **P02c-2 — Hub-side Internal API + Outbound `LearnStackApiClient` ⏳**
> `POST /api/v1/internal/license/verify` + `POST /api/v1/usage/report`
> handlers, mTLS + signed JWT + HMAC body-signature chain, Hub OpenAPI
> spec generation + frontend SDK generation.
>
> **P02c-3 — LearnStack core PR ⏳ blocked on LearnStack P02a-5/6/7/9**
> `HubEntitlementProvider` (production-complete) + `IUsageReporter`
> adapter on the LearnStack side; APISIX `/api/internal/*` stub activation;
> `POST /api/internal/tenants` + `PUT /api/internal/tenants/{id}/entitlements`
> handlers; Dapr `learnstack.hub.entitlement` consumer; architecture test
> catalogue migration of `LearnStack_Modules_DoNotReference_Hub` +
> `IEntitlementProvider_Implementations_Are_Three` +
> `NullEntitlementProvider_NotRegistered_OutsideDevelopment`.
>
> **P02c-4 — Operator Portal MVP ⏳**
> Keycloak `learnstack-hub` realm OIDC + PKCE BFF login, tenant list
> (filterable), tenant detail (entitlement read-only viewer), plan list
> (read-only), dashboard stub. MFA enforced.
>
> **P02c-5 — Custom Domain Lifecycle ⏳**
> `CustomDomain` aggregate + state machine, DNS-01 / HTTP-01 challenge
> runner, Let's Encrypt provider adapter,
> `learnstack.hub.custom-domain.activated/.deactivated/.renewed` event
> publish; LearnStack-side `platform_host_to_tenant` mirror handler per
> ADR-0022 Amendment 1 (Hub never writes LearnStack K8s state).
>
> **P02c-6 — License Key (functional skeleton) ⏳**
> `LicenseKey` aggregate + RSA-2048 keypair + `.lic` file format
> (JWT-style claims); LearnStack-side `SignedLicenseKeyEntitlementProvider`
> skeleton.
>
> **P02c-7 — End-to-End Exit Gate ⏳**
> Full SaaS scenario + Self-Hosted bootstrap rehearsal; Hub + LearnStack
> architecture suites green.

## Goal

Bootstrap the **separate `learnstack-hub` repository** and stand up the foundation
Expand Down
Loading