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>
This commit is contained in:
+22
@@ -0,0 +1,22 @@
|
||||
# Application Design — Clarification
|
||||
|
||||
## Contradiction: Q1 (file-linking) vs Q2 (move into Core)
|
||||
|
||||
You answered Q1 with **C** (MSBuild file-linking: keep the `.cs` files physically in one project, link them into the other so there's no new project) and Q2 with **B** (put the code directly into the existing `SlpModularCms.Core` project instead of a new project).
|
||||
|
||||
These two answers solve the same problem in different, mutually exclusive ways:
|
||||
- **C (file-linking)** implies the source files stay in `SlpModularCms.Api` (or wherever) and get *linked* (not copied) into `SlpModularCms.Api.Slave` — two projects compiling the same files, still no single shared assembly.
|
||||
- **B (move into Core)** means the files move into `SlpModularCms.Core`, which is *already* referenced by every project (both host projects, all modules) — no linking needed at all, because it becomes a normal shared dependency like everything else in Core.
|
||||
|
||||
Given your stated goal — "1 buildable project for production, no overhead for testing" — **B fully supersedes C**: moving the three classes (`ModuleOrchestrator`, `ServiceCollectionExtensions`, `ApiPrefixConvention`) into `SlpModularCms.Core` gives you exactly one copy of the code, compiled once, already available to both `SlpModularCms.Api` and `SlpModularCms.Api.Slave` via the existing `Core` reference — no new project, no file-linking, no extra overhead. File-linking would only be needed if you wanted to avoid touching `Core`, which contradicts choosing B.
|
||||
|
||||
Checked `SlpModularCms.Core.csproj`: it already has a `FrameworkReference` to `Microsoft.AspNetCore.App` (covers MVC, rate limiting, etc.) and already references `Microsoft.AspNetCore.Authentication.JwtBearer` and `Microsoft.AspNetCore.Identity.EntityFrameworkCore`. Moving the code in would require adding exactly two more package references to `Core`: `Asp.Versioning.Mvc` (for `AddApiVersioning`) and `Microsoft.AspNetCore.OpenApi` (for `AddOpenApi`) — both already used today, just currently referenced at the `Api` project level instead of `Core`.
|
||||
|
||||
### Clarification Question 1
|
||||
Confirm the resolution:
|
||||
|
||||
A) Yes — go with **B**: move `ModuleOrchestrator`, `ServiceCollectionExtensions`, and `ApiPrefixConvention` into `SlpModularCms.Core` (namespaces become `SlpModularCms.Core.Hosting.*` or similar). No new project, no file-linking. `Core` gains two package references (`Asp.Versioning.Mvc`, `Microsoft.AspNetCore.OpenApi`) it doesn't currently have. Both `SlpModularCms.Api` and `SlpModularCms.Api.Slave` call the same code via their existing `Core` reference.
|
||||
B) No — actually use file-linking (**C**) instead, and leave `Core` untouched; the three classes stay physically in `SlpModularCms.Api` and get linked into `SlpModularCms.Api.Slave`'s `.csproj` via `<Compile Include="..." Link="..." />`.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: A
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# Application Design Plan — Local Dev Master/Slave Setup
|
||||
|
||||
## Scope
|
||||
|
||||
This feature has no new business logic or data model — the only real "component design" decision is **how to share bootstrap/orchestration code** (`ModuleOrchestrator`, `ServiceCollectionExtensions`, `ApiPrefixConvention`) between `SlpModularCms.Api` (master) and the new `SlpModularCms.Api.Slave` project, per NFR-1 (no duplication) from requirements.md.
|
||||
|
||||
Investigated: all three classes are `public`, live in `SlpModularCms.Api.Extensions`/`SlpModularCms.Api.Infrastructure`, and only depend on `SlpModularCms.Core.*` namespaces (`Core.Data`, `Core.Identity.*`, `Core.Availability`, `Core.Modules`) — none of them reference `Modules.Master`, `Modules.Identity`, or `Modules.Availability` directly. This means they can move to a shared project without dragging in the Master module.
|
||||
|
||||
## Design Plan
|
||||
|
||||
- [ ] Decide shared bootstrap extraction approach (Question 1)
|
||||
- [ ] Decide shared project name/location (Question 2)
|
||||
- [ ] Generate `components.md` — the two host projects + the new shared bootstrap component
|
||||
- [ ] Generate `component-methods.md` — public extension methods / orchestrator methods, signatures unchanged from today
|
||||
- [ ] Generate `services.md` — confirm no new domain services (reuses existing `Modules.Master`/`Modules.Availability`/`Modules.Identity` services untouched)
|
||||
- [ ] Generate `component-dependency.md` — dependency matrix for `SlpModularCms.Api`, `SlpModularCms.Api.Slave`, and the shared bootstrap project
|
||||
- [ ] Generate consolidated `application-design.md`
|
||||
|
||||
## Questions
|
||||
|
||||
### Question 1
|
||||
How should the shared bootstrap code (`ModuleOrchestrator`, `ServiceCollectionExtensions`, `ApiPrefixConvention`) be shared between the master and slave host projects?
|
||||
|
||||
A) Move all three classes into a new shared class library project that both `SlpModularCms.Api` and `SlpModularCms.Api.Slave` reference (clean separation, standard .NET pattern, one source of truth).
|
||||
B) Keep the classes in `SlpModularCms.Api` and have `SlpModularCms.Api.Slave` reference `SlpModularCms.Api` itself — rejected in requirements analysis because `SlpModularCms.Api.csproj` references `Modules.Master`, which would defeat the purpose of a Master-less slave; listed here only for completeness.
|
||||
C) Use MSBuild file-linking (`<Compile Include="..\SlpModularCms.Api\...\*.cs" Link="..." />`) to share the same `.cs` files across both projects without a new class library.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: C, because I want 1 buildable project for production. I dont want to create extra overhead for testing purposes
|
||||
|
||||
### Question 2
|
||||
What should the new shared project be named, and what should it depend on?
|
||||
|
||||
A) `SlpModularCms.Api.Hosting` — new class library referencing only `SlpModularCms.Core`; contains `ModuleOrchestrator`, `ServiceCollectionExtensions`, `ApiPrefixConvention` (namespaces updated to `SlpModularCms.Api.Hosting.*`). Both `SlpModularCms.Api` and `SlpModularCms.Api.Slave` reference it plus their own module project references (Master only for the master host).
|
||||
B) Add this code directly into the existing `SlpModularCms.Core` project instead of creating a new project.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: B
|
||||
@@ -0,0 +1,142 @@
|
||||
# Execution Plan — Local Dev Master/Slave Setup
|
||||
|
||||
## Detailed Analysis Summary
|
||||
|
||||
### Transformation Scope (Brownfield)
|
||||
- **Transformation Type**: Single new component (host project) + configuration-only changes elsewhere. No architectural transformation, no deployment-model change, no infrastructure/cloud change.
|
||||
- **Primary Changes**: New `SlpModularCms.Api.Slave` host project; extraction of shared bootstrap/orchestration code so it isn't duplicated between the master and slave hosts; per-instance `appsettings`/`launchSettings`; frontend dev-server config for a second instance; a short runbook.
|
||||
- **Related Components**: `SlpModularCms.Api` (reference/behavior parity, no functional change), `SlpModularCms.Modules.Availability` (already slave-capable, unchanged), `SlpModularCms.Modules.Master` (unchanged — simply excluded from the slave project), `frontend` (dev-server/env config only).
|
||||
|
||||
### Change Impact Assessment
|
||||
- **User-facing changes**: No — this is developer tooling, not a product feature.
|
||||
- **Structural changes**: Yes, minor — one new project (`SlpModularCms.Api.Slave`) and, to satisfy NFR-1 (no duplicated bootstrap code), a small new shared project/location for `ModuleOrchestrator`, `ServiceCollectionExtensions`, and `ApiPrefixConvention` that both `SlpModularCms.Api` and `SlpModularCms.Api.Slave` reference.
|
||||
- **Data model changes**: No — no new entities, no new migrations.
|
||||
- **API changes**: No — no new endpoints or contract changes; existing Master/Availability endpoints are reused as-is.
|
||||
- **NFR impact**: Minor — addressed directly in requirements.md (NFR-1 no duplication, NFR-2 DB isolation, NFR-3 local-only scope, NFR-4 secrets hygiene). No new performance/security/scalability posture is introduced beyond what already exists.
|
||||
|
||||
### Component Relationships (Brownfield)
|
||||
- **Primary Component**: New `SlpModularCms.Api.Slave` project (backend)
|
||||
- **Shared Components**: New shared bootstrap location (exact form decided in Application Design) referenced by both `SlpModularCms.Api` and `SlpModularCms.Api.Slave`
|
||||
- **Dependent Components**: `frontend` (new dev-server mode pointing at whichever instance)
|
||||
- **Supporting Components**: `frontend/README.md` / root docs (runbook)
|
||||
|
||||
| Component | Change Type | Change Reason | Change Priority |
|
||||
|---|---|---|---|
|
||||
| Shared bootstrap (new) | Minor (extraction, no behavior change) | Avoid duplicating `ModuleOrchestrator` etc. between hosts (NFR-1) | Critical — both hosts depend on it |
|
||||
| `SlpModularCms.Api` | Configuration-only (adjust to consume shared bootstrap) | Keep master behavior identical, just sourced from shared location | Critical — must not regress existing master behavior |
|
||||
| `SlpModularCms.Api.Slave` (new) | Major (new project) | Slave-only host, no `Modules.Master` reference | Critical — the actual deliverable |
|
||||
| `frontend` | Configuration-only | Point at either instance via env/script | Important |
|
||||
| Docs/runbook | New content | Explain manual connection workflow | Optional but requested (FR-4) |
|
||||
|
||||
### Risk Assessment
|
||||
- **Risk Level**: Low — isolated to local dev tooling; no production code paths, no data model, no API contract changes; existing master build output is unaffected once the shared bootstrap is extracted correctly.
|
||||
- **Rollback Complexity**: Easy — new project and config files only; deleting them reverts to the current state.
|
||||
- **Testing Complexity**: Simple — existing unit tests for `Modules.Master`/`Modules.Availability` are untouched; verification is mostly "does each instance start correctly and can the existing Add CMS Instance flow connect them."
|
||||
|
||||
## Workflow Visualization
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["User Request"])
|
||||
|
||||
subgraph INCEPTION["🔵 INCEPTION PHASE"]
|
||||
WD["Workspace Detection<br/><b>COMPLETED</b>"]
|
||||
RA["Requirements Analysis<br/><b>COMPLETED</b>"]
|
||||
US["User Stories<br/><b>SKIPPED</b>"]
|
||||
WP["Workflow Planning<br/><b>IN PROGRESS</b>"]
|
||||
AD["Application Design<br/><b>EXECUTE</b>"]
|
||||
UG["Units Generation<br/><b>EXECUTE</b>"]
|
||||
end
|
||||
|
||||
subgraph CONSTRUCTION["🟢 CONSTRUCTION PHASE"]
|
||||
FD["Functional Design<br/><b>SKIP (per unit)</b>"]
|
||||
NFRA["NFR Requirements<br/><b>SKIP (per unit)</b>"]
|
||||
NFRD["NFR Design<br/><b>SKIP (per unit)</b>"]
|
||||
ID["Infrastructure Design<br/><b>SKIP (per unit)</b>"]
|
||||
CG["Code Generation<br/><b>EXECUTE</b>"]
|
||||
BT["Build and Test<br/><b>EXECUTE</b>"]
|
||||
end
|
||||
|
||||
subgraph OPERATIONS["🟡 OPERATIONS PHASE"]
|
||||
OPS["Operations<br/><b>PLACEHOLDER</b>"]
|
||||
end
|
||||
|
||||
Start --> WD
|
||||
WD --> RA
|
||||
RA --> US
|
||||
US --> WP
|
||||
WP --> AD
|
||||
AD --> UG
|
||||
UG --> CG
|
||||
CG --> BT
|
||||
BT --> End(["Complete"])
|
||||
|
||||
style WD fill:#4CAF50,stroke:#1B5E20,stroke-width:3px,color:#fff
|
||||
style RA fill:#4CAF50,stroke:#1B5E20,stroke-width:3px,color:#fff
|
||||
style US fill:#BDBDBD,stroke:#424242,stroke-width:2px,stroke-dasharray: 5 5,color:#000
|
||||
style WP fill:#FFA726,stroke:#E65100,stroke-width:3px,color:#000
|
||||
style AD fill:#FFA726,stroke:#E65100,stroke-width:3px,stroke-dasharray: 5 5,color:#000
|
||||
style UG fill:#FFA726,stroke:#E65100,stroke-width:3px,stroke-dasharray: 5 5,color:#000
|
||||
style FD fill:#BDBDBD,stroke:#424242,stroke-width:2px,stroke-dasharray: 5 5,color:#000
|
||||
style NFRA fill:#BDBDBD,stroke:#424242,stroke-width:2px,stroke-dasharray: 5 5,color:#000
|
||||
style NFRD fill:#BDBDBD,stroke:#424242,stroke-width:2px,stroke-dasharray: 5 5,color:#000
|
||||
style ID fill:#BDBDBD,stroke:#424242,stroke-width:2px,stroke-dasharray: 5 5,color:#000
|
||||
style CG fill:#4CAF50,stroke:#1B5E20,stroke-width:3px,color:#fff
|
||||
style BT fill:#4CAF50,stroke:#1B5E20,stroke-width:3px,color:#fff
|
||||
style Start fill:#CE93D8,stroke:#6A1B9A,stroke-width:3px,color:#000
|
||||
style End fill:#CE93D8,stroke:#6A1B9A,stroke-width:3px,color:#000
|
||||
|
||||
linkStyle default stroke:#333,stroke-width:2px
|
||||
```
|
||||
|
||||
Text alternative: Workspace Detection, Requirements Analysis are complete (green). User Stories is skipped (gray, dashed). Workflow Planning is in progress (orange). Application Design and Units Generation are planned to execute (orange, dashed border indicating conditional-but-selected). Per-unit Functional Design, NFR Requirements, NFR Design, and Infrastructure Design are all skipped (gray, dashed) for both units. Code Generation and Build and Test always execute (green). Operations remains a placeholder.
|
||||
|
||||
## Phases to Execute
|
||||
|
||||
### 🔵 INCEPTION PHASE
|
||||
- [x] Workspace Detection (COMPLETED)
|
||||
- [x] Requirements Analysis (COMPLETED)
|
||||
- [x] User Stories (SKIPPED)
|
||||
- **Rationale**: Pure developer tooling / local run configuration with no user-facing functionality, no personas, no acceptance-criteria needs — matches the explicit skip criteria in the workflow ("Developer tooling or build process improvements").
|
||||
- [x] Execution Plan (IN PROGRESS)
|
||||
- [ ] Application Design - **EXECUTE**
|
||||
- **Rationale**: A new component boundary is introduced (the shared bootstrap location consumed by both `SlpModularCms.Api` and `SlpModularCms.Api.Slave`) and its responsibilities/dependencies need to be defined before code generation, even though no new business logic exists. Kept minimal — no service-layer business rules to design, just component boundaries.
|
||||
- [ ] Units Generation - **EXECUTE**
|
||||
- **Rationale**: The change spans two clearly separable concerns (backend dual-instance hosting vs. frontend dual-instance tooling), each independently completable and testable — decomposing into units keeps Code Generation focused.
|
||||
|
||||
### 🟢 CONSTRUCTION PHASE (per unit)
|
||||
- [ ] Functional Design - **SKIP** (both units)
|
||||
- **Rationale**: No new data models, schemas, or business logic — this is host/bootstrap wiring and configuration reuse of existing services.
|
||||
- [ ] NFR Requirements - **SKIP** (both units)
|
||||
- **Rationale**: NFRs are already fully captured in requirements.md (no duplication, DB isolation, local-only scope, secrets hygiene) and require no tech-stack selection or further elaboration.
|
||||
- [ ] NFR Design - **SKIP** (both units)
|
||||
- **Rationale**: Depends on NFR Requirements, which is skipped.
|
||||
- [ ] Infrastructure Design - **SKIP** (both units)
|
||||
- **Rationale**: No cloud/infrastructure resources involved — purely local processes and local SQL Server databases using existing patterns.
|
||||
- [ ] Code Generation - **EXECUTE (ALWAYS)**
|
||||
- **Rationale**: Implementation of the new project, config files, and frontend tooling.
|
||||
- [ ] Build and Test - **EXECUTE (ALWAYS)**
|
||||
- **Rationale**: Verify both instances build and start, existing test suites still pass, and the manual master↔slave connection flow works.
|
||||
|
||||
### 🟡 OPERATIONS PHASE
|
||||
- [ ] Operations - PLACEHOLDER
|
||||
- **Rationale**: Future deployment and monitoring workflows; not applicable to local dev tooling.
|
||||
|
||||
## Proposed Units (for Units Generation)
|
||||
|
||||
1. **Unit 1 — Backend dual-instance hosting**: Extract shared bootstrap (`ModuleOrchestrator`, `ServiceCollectionExtensions`, `ApiPrefixConvention`) into a location both hosts reference; add `SlpModularCms.Api.Slave` project (no `Modules.Master` reference); add its `launchSettings.json`/`appsettings*.json`; update `SlpModularCms.Api`'s config for CORS/port clarity if needed; add both projects to the solution.
|
||||
2. **Unit 2 — Frontend dual-instance tooling & runbook**: Add `.env.slave.local`/`.env.example` updates, `dev:slave` npm script, and the runbook documenting how to start both instances and use the existing Add CMS Instance dialog to connect them.
|
||||
|
||||
## Package Change Sequence
|
||||
|
||||
Unit 1 must complete before Unit 2 can be meaningfully tested end-to-end (the frontend needs a running slave backend to point at), though Unit 2's config/doc changes could technically be authored in parallel. Sequential execution (Unit 1 then Unit 2) is recommended for a clean verification story.
|
||||
|
||||
## Estimated Timeline
|
||||
- **Total Phases**: Application Design, Units Generation, Code Generation (2 units), Build and Test
|
||||
- **Estimated Duration**: Small — a few hours of focused work; no research spikes needed since the master/slave protocol already exists and is unchanged.
|
||||
|
||||
## Success Criteria
|
||||
- **Primary Goal**: Developer can run a master instance (port 5284/7221, full stack) and a slave instance (port 5285/7222, no Master module) locally at the same time, on separate databases.
|
||||
- **Key Deliverables**: `SlpModularCms.Api.Slave` project, shared bootstrap extraction, per-instance config, frontend slave mode, runbook.
|
||||
- **Quality Gates**: Both backends build and start cleanly; existing test suites (`Modules.Master.Tests`, `Modules.Availability.Tests`, frontend tests) still pass unchanged; manual verification that the master frontend's "Add CMS Instance" dialog can register and see the local slave as connected.
|
||||
- **Integration Testing**: Manual — start both instances, register the slave from the master frontend, confirm connected/healthy status.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Unit of Work Plan — Local Dev Master/Slave Setup
|
||||
|
||||
## Plan
|
||||
|
||||
- [ ] Generate `unit-of-work.md` with unit definitions and responsibilities
|
||||
- [ ] Generate `unit-of-work-dependency.md` with dependency matrix between units
|
||||
- [ ] Generate `unit-of-work-story-map.md` mapping requirements (no user stories exist for this feature — User Stories stage was skipped) to units
|
||||
- [ ] Validate unit boundaries and dependencies
|
||||
|
||||
## Context
|
||||
|
||||
No user stories exist for this feature (skipped as pure dev tooling). Units are mapped directly from the Functional Requirements in `requirements.md` and the components in `application-design/`. `SlpModularCms.Api` has no dedicated test project today (it's thin bootstrap code, exercised indirectly via module test suites and manual verification) — the same pattern is expected to apply to `SlpModularCms.Api.Slave`.
|
||||
|
||||
## Questions
|
||||
|
||||
### Question 1
|
||||
Confirm the two-unit split proposed in the execution plan:
|
||||
|
||||
A) **Unit 1 — Backend dual-instance hosting**: relocate `ModuleOrchestrator`/`ServiceCollectionExtensions`/`ApiPrefixConvention` into `SlpModularCms.Core.Hosting`; add `SlpModularCms.Api.Slave` project (no `Modules.Master` reference); add both projects' `launchSettings.json`/`appsettings*.json`; add to solution. **Unit 2 — Frontend dual-instance tooling & runbook**: `.env.slave.local` support, `dev:slave` npm script, runbook documentation.
|
||||
B) Different split — describe after [Answer]: tag below.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
### Question 2 (Dependencies)
|
||||
Unit 2 (frontend) needs a running slave backend to be meaningfully tested against. Should Unit 2 still be generated even though Unit 1 must be functionally verified first?
|
||||
|
||||
A) Yes — generate Unit 1 fully (including a working build) before starting Unit 2's code, since Unit 2's manual verification depends on Unit 1 existing and running.
|
||||
B) Generate both units' code in parallel/independently, verify together at the end during Build and Test.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: A
|
||||
|
||||
### Question 3 (Technical Considerations)
|
||||
Does `SlpModularCms.Api.Slave` need its own dedicated test project (mirroring `SlpModularCms.Api`, which currently has none)?
|
||||
|
||||
A) No — no dedicated test project, consistent with `SlpModularCms.Api` today (thin bootstrap code covered indirectly by module test suites; this feature adds no new business logic to unit test).
|
||||
B) Yes — add a new `SlpModularCms.Api.Slave.Tests` project.
|
||||
X) Other (please describe after [Answer]: tag below)
|
||||
|
||||
[Answer]: A
|
||||
Reference in New Issue
Block a user