Files
slp-modular-cms/aidlc-docs/features/local-dev-master-slave-setup/inception/requirements/requirements.md
T
SluijsensandClaude Sonnet 5 274946dbff Adds SlpModularCms.Api.Slave for local master/slave dev testing (Unit 1)
Relocates ModuleOrchestrator, ServiceCollectionExtensions, and
ApiPrefixConvention from SlpModularCms.Api into SlpModularCms.Core.Hosting
so a new Master-less SlpModularCms.Api.Slave host project (ports 5285/7222)
can share the same bootstrap code without duplicating it. This lets a
developer run a master instance and a slave instance side by side locally
to test the master/slave connection, without touching the existing
master/slave protocol itself.

Relocates the two orchestrator/convention test files from
Modules.Identity.Tests to Core.Tests, dropping an incidental
ProjectReference to SlpModularCms.Api that existed only for those tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 02:07:35 +02:00

9.6 KiB

Requirements — Local Dev Master/Slave Setup

Intent Analysis

  • User Request: Enable running two local instances of the CMS backend simultaneously — one with SlpModularCms.Modules.Master loaded (the existing full CMS, acting as master) and one without it (acting purely as a slave/target) — on two different ports, so the master↔slave connection can be tested end-to-end locally.
  • Request Type: New Feature (developer tooling / local run configuration)
  • Scope Estimate: Multiple components — new host project (SlpModularCms.Api.Slave), solution/build changes, appsettings/launchSettings for both instances, frontend dev-server configuration for pointing at either instance.
  • Complexity Estimate: Moderate — no new business logic; the master/slave protocol itself (Modules.Master's CmsInstanceService/SlaveApiClient and Modules.Availability's MasterController/MasterAvailabilityService) already exists and is unchanged. Complexity comes from correctly separating build/run configuration for two instances without duplicating orchestration logic.

Background (from codebase investigation)

  • SlpModularCms.Api's Program.cs does not directly reference Modules.Master. Instead, Infrastructure/ModuleOrchestrator.cs discovers modules at startup by scanning its own build output directory for SlpModularCms.Modules.*.dll and instantiating any IModule implementation found — currently every module the API project references (Core, Availability, Identity, Master) always ends up in that output folder via ProjectReferences in SlpModularCms.Api.csproj.
  • The master/slave connection mechanism already exists and needs no changes:
    • Slave side (present in every instance, since Modules.Availability is always loaded): MasterController + MasterAvailabilityService + MasterApiKeyProtector accept and validate a per-instance API key pushed by a master.
    • Master side (only in Modules.Master): CmsInstanceService + SlaveApiClient + ApiKeyProtector manage registered CMS instances and talk to them.
    • The existing frontend "Add CMS Instance" dialog (from master-cms-module) is the existing UI flow for registering a slave under a master.
  • Frontend reads its backend URL from VITE_API_BASE_URL (frontend/src/lib/config.ts), sourced from a Vite env file (.env.local, .env.example), evaluated once per dev server process. Vite dev server currently runs on a fixed port (5173, vite.config.ts).
  • Backend CORS allowed origins are configured per-instance under Cors:AllowedOrigins in appsettings.Development.json / appsettings.local.json.

Decisions from Clarification

  1. Instance separation mechanism: A new host project, SlpModularCms.Api.Slave, with its own .csproj referencing SlpModularCms.Core, SlpModularCms.Modules.Identity, and SlpModularCms.Modules.Availability — but not SlpModularCms.Modules.Master. Because ModuleOrchestrator discovers modules purely by scanning its own build output, omitting the Master project reference is sufficient to produce a slave-only instance; no config-driven module toggle is needed for this feature.
  2. Production plugin-loading model is explicitly out of scope: the user separately wants a future production model where the API is built once without module project references and modules are dropped in as standalone DLLs post-build. That is a distinct, larger architectural change (build/packaging/CI, not local dev tooling) and is not part of this feature. Capture it as a follow-up idea (see "Out of Scope" below).
  3. Database isolation: Master and slave instances use separate local databases (separate connection strings/database names), same local SQL Server.
  4. Ports: Master keeps existing ports (http://localhost:5284, https://localhost:7221). Slave gets a new pair (http://localhost:5285, https://localhost:7222).
  5. Launch method: Two dotnet run --launch-profile <name> invocations (one per terminal/process) — no background helper script required.
  6. Frontend: The frontend must also be runnable against the slave instance (its own dev server / env configuration), not just the master — so the slave's admin UI is separately reachable for manual testing.
  7. Establishing the connection: No scripted/seeded auto-registration. The user will manually register the slave under the master using the existing "Add CMS Instance" UI flow, specifically to exercise/validate that flow end-to-end.

Functional Requirements

FR-1: Slave-only backend host project

  • Add SlpModularCms.Api.Slave, a new ASP.NET Core Web API project in src/, added to the solution.
  • Bootstraps the same way as SlpModularCms.Api (core infrastructure, CORS, rate limiting, controllers, module discovery/orchestration, exception handling, Scalar in Development) — but its .csproj references Core, Modules.Identity, and Modules.Availability only (no Modules.Master reference), so ModuleOrchestrator never discovers/loads the Master module for this instance.
  • Avoid duplicating the bootstrap/orchestration code (ModuleOrchestrator, ServiceCollectionExtensions, ApiPrefixConvention) between SlpModularCms.Api and SlpModularCms.Api.Slave — extract shared pieces into a location both projects can reference without pulling in Modules.Master (see NFR-1).

FR-2: Distinct local run configuration per instance

  • SlpModularCms.Api (master) keeps its existing launchSettings.json profiles and ports (5284 / 7221).
  • SlpModularCms.Api.Slave gets its own launchSettings.json with profiles on ports 5285 (HTTP) and 7222 (HTTPS).
  • Each project has its own appsettings.json / appsettings.Development.json / appsettings.local.json (gitignored) with:
    • A distinct ConnectionStrings:DefaultConnection (separate database name/catalog) so master and slave don't share data.
    • Cors:AllowedOrigins covering whichever frontend origin(s) will point at that instance.
    • The slave instance does not need MasterModule configuration (that section is only meaningful where Modules.Master is loaded).
  • Both instances can be started independently via dotnet run --launch-profile <name> from their respective project directories.

FR-3: Frontend configurable against either instance

  • Add a way to run the existing frontend against the slave instance in addition to the master, without needing two separate frontend codebases:
    • A second Vite env file (e.g. .env.slave.local, gitignored like .env.local) setting VITE_API_BASE_URL to the slave's HTTPS URL (https://localhost:7222).
    • A second npm script (e.g. dev:slave) that runs Vite with that env mode on a different dev-server port (e.g. 5174), so both frontend instances can run side by side if needed.
    • Update .env.example and/or frontend/README.md to document both modes.

FR-4: Documentation for the local master/slave workflow

  • Add a short runbook (e.g. frontend/README.md and/or a root-level docs/README section, or a dedicated markdown file referenced from the main README) describing:
    1. How to start the master backend + master frontend.
    2. How to start the slave backend (+ optionally slave frontend) on the alternate ports.
    3. How to use the master frontend's existing "Add CMS Instance" dialog to register the local slave (what URL/API key to use) and confirm the connection works (e.g. status shows as connected/healthy).

Non-Functional Requirements

NFR-1: No logic duplication between host projects

  • The master and slave host projects must share bootstrap/orchestration code (module discovery, DI wiring for core infrastructure, controller conventions) rather than maintaining two copies that can drift. Exact extraction mechanism (e.g. a small shared class library, or a shared partial/extension file linked into both projects) is a Functional/Application Design decision, not fixed here.

NFR-2: Isolation

  • Master and slave instances must not share a database, so testing against one cannot corrupt or interfere with the other's data.

NFR-3: Local-only scope

  • No changes to the actual master/slave communication protocol, production deployment, or CI/CD pipeline. This is strictly a local development convenience.

NFR-4: Secrets hygiene

  • Slave's appsettings.local.json (and any new gitignored env files) must follow the existing pattern — never committed, following dotnet-appsettings conventions already used by SlpModularCms.Api.

Out of Scope

  • Production drop-in module DLL loading: Building the API once without module project references and loading modules from an external "Modules" folder dropped in post-build/at-deploy. This is a distinct future initiative (build/packaging/CI concern) explicitly deferred by the user during clarification — to be captured as a new backlog/feature item when picked up, not designed as part of this feature.
  • Automated/scripted slave registration: The user explicitly wants to exercise the existing "Add CMS Instance" UI flow manually; no seed data or dev-only registration endpoint will be added.
  • Any change to Modules.Master, Modules.Availability, or the master/slave communication protocol itself.

Summary

This feature adds a second, Master-less ASP.NET Core host project (SlpModularCms.Api.Slave) plus per-instance run configuration (ports, databases, CORS) and frontend tooling, so the developer can run a master CMS instance (full stack, port 5284/7221) and a slave-only instance (no Master module, port 5285/7222) side by side locally, and manually connect them via the existing "Add CMS Instance" UI flow to validate the master/slave integration end-to-end. The production "plugin-style" module loading idea raised during clarification is explicitly out of scope and noted for future consideration.