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

81 lines
9.6 KiB
Markdown

# 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 `ProjectReference`s 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.