Completes master-cms-module: Build & Test, docs, and appsettings
Finishes the master-cms-module feature (Units 1-4): runs Build and Test across master-backend, slave-availability-extension and frontend-cms-page, fixes a missing Availability EF migration for MasterRegistration and a TanStack Query v5 mutation-callback type break, adds the missing MasterModule appsettings section, and documents the module in README.md. Also seeds a tech-debt-backlog feature to track dead config and pre-existing/introduced frontend lint findings for later cleanup.
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
# Build and Test Summary
|
||||
|
||||
## Build Status
|
||||
- **Build Tool**: .NET SDK 10 (backend), Vite + tsc (frontend)
|
||||
- **Build Status**: Success (after one fix — see below)
|
||||
- **Build Artifacts**: `src/**/bin/Debug/net10.0/*.dll`, `frontend/dist/`
|
||||
- **Build Time**: ~15s backend, ~5s frontend
|
||||
|
||||
### Fixes Applied During Build Verification
|
||||
1. `frontend/src/api/useUpdateCmsInstanceStatus.ts` failed `tsc` because the installed `@tanstack/react-query@5.101.0` mutation `onSuccess` callback signature gained a 4th `context` parameter, and the code was manually forwarding only 3 args to the consumer callback. Fixed by forwarding all trailing args with a rest parameter (`...rest`). No behavior change — this is a type-signature compatibility fix, not a logic change.
|
||||
2. **Missing EF Core migration** — `SlpModularCms.Modules.Availability` had no migration for the `MasterRegistration` entity added in Unit 2, even though `AvailabilityModule.UseModule` calls `Database.Migrate()`. On a real database this meant the `AvailabilityMasterRegistrations` table would never be created, breaking the master registration flow end-to-end. Generated via `dotnet ef migrations add InitialCreate --project src/SlpModularCms.Modules.Availability --startup-project src/SlpModularCms.Api --context AvailabilityDbContext`.
|
||||
|
||||
## Test Execution Summary
|
||||
|
||||
### Unit Tests — Backend (.NET)
|
||||
- **Total Tests**: 193
|
||||
- **Passed**: 193
|
||||
- **Failed**: 0
|
||||
- **Status**: Pass
|
||||
- Breakdown: Core.Tests (45), Modules.Identity.Tests (46), Modules.Availability.Tests (60), Modules.Master.Tests (42)
|
||||
|
||||
### Unit Tests — Frontend (Vitest)
|
||||
- **Total Tests**: 209 (34 test files)
|
||||
- **Passed**: 209
|
||||
- **Failed**: 0
|
||||
- **Status**: Pass
|
||||
|
||||
### Integration Tests
|
||||
- **Test Scenarios**: 4 documented in `integration-test-instructions.md` (registration handshake, status push + middleware enforcement, fail-open on push failure/slave restart, frontend CMS page end-to-end)
|
||||
- **Status**: Manual — no automated cross-process harness exists in this codebase; scenarios are documented for manual verification. Underlying logic for each scenario is covered by the unit test suites above.
|
||||
|
||||
### Performance Tests
|
||||
- **Status**: N/A — no explicit performance SLA defined in NFR Requirements. Architectural review confirms the master-gate check is a zero-I/O in-memory field read (documented in `performance-test-instructions.md`).
|
||||
|
||||
### Additional Tests
|
||||
- **Contract Tests**: N/A — no separate service contract test suite; API shape covered by controller/integration unit tests
|
||||
- **Security Tests**: N/A for this stage — API key handling, Data Protection, and auth bypass-prefix design were validated during NFR Design/Requirements review, not re-tested here
|
||||
- **E2E Tests**: N/A — no browser-automation E2E suite in this codebase; frontend interactions covered by Vitest component tests + React Testing Library
|
||||
|
||||
### Lint (Frontend)
|
||||
- `npm run lint`: 6 problems (5 errors, 1 warning). Re-verified with a clean `git worktree` checkout of `c156107` (the commit before this feature's frontend work) plus a fresh `npm install` — an earlier same-tree `git checkout -- .` comparison had been contaminated by files that only exist at HEAD, giving a false "all pre-existing" reading.
|
||||
- **4 pre-existing** (confirmed via the clean baseline): `badge.tsx:32`, `InviteUserDialog.tsx` (×2), `SettingsPage.tsx:39`.
|
||||
- **2 newly introduced by this feature's Unit 3**: `AddCmsInstanceDialog.tsx:55` (error), `SetStatusDialog.tsx:72` (warning) — same underlying pattern as the pre-existing findings.
|
||||
- All 6 items logged to the new `tech-debt-backlog` feature (`aidlc-docs/features/tech-debt-backlog/inception/requirements/backlog.md`, TD-002/TD-003) per user decision (2026-07-01) rather than fixed in-flight, to avoid blocking Unit 4.
|
||||
|
||||
## Overall Status
|
||||
- **Build**: Success
|
||||
- **All Tests**: Pass (402 automated tests: 193 backend + 209 frontend)
|
||||
- **Ready for Operations**: Yes
|
||||
|
||||
## Next Steps
|
||||
Proceed to Operations phase (placeholder) — or, per the execution plan, Unit 4 (documentation) is still outstanding before the feature is fully complete.
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
# Build Instructions
|
||||
|
||||
## Prerequisites
|
||||
- **Build Tool**: .NET SDK 10 (backend), Node.js + npm/pnpm (frontend)
|
||||
- **Dependencies**: NuGet packages (restored automatically), npm packages in `frontend/`
|
||||
- **Environment Variables**: None required for build
|
||||
- **System Requirements**: Windows/Linux/macOS, .NET 10 runtime
|
||||
|
||||
## Build Steps
|
||||
|
||||
### 1. Backend — Install Dependencies & Build
|
||||
```bash
|
||||
dotnet build SlpModularCms.sln
|
||||
```
|
||||
|
||||
### 2. Frontend — Install Dependencies & Build
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build # tsc -b && vite build
|
||||
```
|
||||
|
||||
## Verify Build Success
|
||||
- **Backend**: `Build succeeded. 0 Error(s)` — all 9 projects compile (Core, Modules.Identity, Modules.Availability, Modules.Master, Api, plus 4 test projects)
|
||||
- **Frontend**: Vite produces a `dist/` bundle with no TypeScript errors
|
||||
- **Build Artifacts**: `src/**/bin/Debug/net10.0/*.dll`, `frontend/dist/`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### TypeScript build fails with mutation callback arity errors
|
||||
- **Cause**: `@tanstack/react-query` v5.101 changed the `onSuccess` mutation callback signature to include a 4th `context` parameter. Manually calling `options?.onSuccess?.(data, variables, context)` with only 3 args now under-supplies the callback's expected arity.
|
||||
- **Solution**: Forward all trailing callback args with a rest parameter, e.g. `onSuccess: (data, variables, ...rest) => { ...; options?.onSuccess?.(data, variables, ...rest); }`. Fixed in `frontend/src/api/useUpdateCmsInstanceStatus.ts`.
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Integration Test Instructions
|
||||
|
||||
## Purpose
|
||||
Verify that the three units of the Master CMS Module work together: the Master module (Unit 1), the slave-side Availability extension (Unit 2), and the `/cms` frontend page (Unit 3).
|
||||
|
||||
## Test Scenarios
|
||||
|
||||
### Scenario 1: Owner Adds a Slave — Master Pushes Registration (Unit 1 → Unit 2)
|
||||
- **Description**: The Owner registers a slave CMS from the Master `/cms` page; the Master generates an API key and pushes registration to the slave.
|
||||
- **Setup**: Run two instances of the API — one configured as Master (`SlpModularCms.Modules.Master` enabled), one as Slave (`SlpModularCms.Modules.Availability` running, reachable at a known URL).
|
||||
- **Test Steps**:
|
||||
1. On the Master, call `POST /api/v1/CmsInstances` with the slave's URL.
|
||||
2. `CmsInstanceService` generates an API key, stores it (Data-Protection-encrypted) in `CmsInstance`, and calls `ISlaveApiClient.RegisterMasterAsync` which `POST`s to the slave's `/api/v1/master/register` with the `X-Master-Api-Key` header.
|
||||
3. Query the Master's `GET /api/v1/CmsInstances` list endpoint.
|
||||
4. Query the slave's `GET /api/v1/master/registered-url` (with the same header) to confirm it stored the registration.
|
||||
- **Expected Results**: The new instance appears in the Master's `CmsInstance` list (API key never included in the DTO); the slave's `MasterRegistration` table stores the Master's URL and the Data-Protection-encrypted API key.
|
||||
- **Cleanup**: Stop both instances; clear both DBs if reused.
|
||||
|
||||
### Scenario 2: Master Sets Slave to Inactive → Slave Enforces via Two-Phase Middleware (Unit 1 → Unit 2)
|
||||
- **Description**: Owner disables a slave from the Master `/cms` page; the Master pushes the new status to the slave, whose `AvailabilityMiddleware` blocks CMS requests.
|
||||
- **Setup**: Both instances running and registered (per Scenario 1).
|
||||
- **Test Steps**:
|
||||
1. On the Master, call `PUT /api/v1/CmsInstances/{id}/status` with `Inactive`.
|
||||
2. Confirm the Master's `SlaveApiClient` pushes the status to the slave synchronously as part of the same request (`SlaveContactSuccess` in the response).
|
||||
3. Send a request to the slave's CMS route.
|
||||
- **Expected Results**: Slave's static `_masterIsAvailable` flag flips immediately on push; slave responds with `503` and the extended response body signaling master-controlled unavailability; frontend on the slave redirects to the disable message.
|
||||
- **Cleanup**: Set status back to `Active` on the Master.
|
||||
|
||||
### Scenario 3: Fail-Open on Master Unreachable or Slave Restart (Unit 1 & Unit 2)
|
||||
- **Description**: The slave gate must never hard-fail when it cannot reach the Master.
|
||||
- **Setup A (push failure)**: Registered slave; stop the Slave instance, then call the status-update endpoint on the Master.
|
||||
- **Test Steps A**:
|
||||
1. Stop the Slave process.
|
||||
2. On the Master, call `PUT /api/v1/CmsInstances/{id}/status` with `Inactive`.
|
||||
3. Inspect the Master's response body and `CmsInstance.LastIntegrityCheckFailedAt`.
|
||||
- **Expected Results A**: The DB status change is NOT rolled back; response reports `SlaveContactSuccess = false`; `IntegrityCheckBackgroundService` will retry and update `LastIntegrityCheckFailedAt` on its next interval (`IntegrityCheckIntervalMinutes`, default 60).
|
||||
- **Setup B (slave restart)**: Restart the Slave process while the Master is unreachable.
|
||||
- **Test Steps B**:
|
||||
1. Stop both Master and Slave.
|
||||
2. Start only the Slave.
|
||||
3. Send a request to the slave's CMS route immediately after startup.
|
||||
- **Expected Results B**: `_masterIsAvailable` defaults to `true` on process start (fail-open), so the slave is reachable even before the Master pushes a fresh status.
|
||||
|
||||
### Scenario 4: Frontend CMS Page End-to-End (Unit 3 → Unit 1)
|
||||
- **Description**: Owner manages slave CMS instances through the `/cms` page.
|
||||
- **Setup**: Master API running; frontend dev server pointed at it (`npm run dev`); logged in as Administrator.
|
||||
- **Test Steps**:
|
||||
1. Navigate to `/cms`.
|
||||
2. Add a new CMS instance via `AddCmsInstanceDialog`.
|
||||
3. Confirm it appears in `CmsInstanceList`.
|
||||
4. Open `SetStatusDialog` and toggle its status.
|
||||
- **Expected Results**: List refreshes via TanStack Query invalidation after each mutation; API key is never shown in the list response (per NFR).
|
||||
|
||||
## Setup Integration Test Environment
|
||||
|
||||
### 1. Start Required Services
|
||||
```bash
|
||||
# Terminal 1 — Master instance
|
||||
dotnet run --project src/SlpModularCms.Api --urls http://localhost:5001
|
||||
|
||||
# Terminal 2 — Slave instance (separate DB, MasterUrl pointing at Terminal 1)
|
||||
dotnet run --project src/SlpModularCms.Api --urls http://localhost:5002
|
||||
```
|
||||
|
||||
### 2. Configure Frontend
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev # defaults to Master instance per vite proxy config
|
||||
```
|
||||
|
||||
## Run Integration Tests
|
||||
These scenarios are currently **manual** (no automated cross-process integration test harness exists in this codebase). Automated coverage for the underlying units (registration logic, middleware two-phase check, cache/fallback, frontend mutations) is provided by the unit test suites listed in `unit-test-instructions.md`.
|
||||
|
||||
### Verify Service Interactions
|
||||
- Check Master logs for registration and status-update requests
|
||||
- Check Slave logs for `MasterAvailabilityService` pull attempts and cache hits/misses
|
||||
- Check browser dev tools network tab for `/api/v1/CmsInstances` calls from the frontend
|
||||
|
||||
### Cleanup
|
||||
```bash
|
||||
# Stop both dotnet run processes (Ctrl+C)
|
||||
```
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Performance Test Instructions
|
||||
|
||||
## Purpose
|
||||
Validate that the master-controlled availability gate does not introduce meaningful request latency on the slave, per NFR-PERF-01/PERF-02 (`aidlc-docs/features/master-cms-module/construction/slave-availability-extension/nfr-requirements/nfr-requirements.md`).
|
||||
|
||||
## Performance Requirements
|
||||
No explicit throughput/latency SLA was defined during NFR Requirements for this feature. The design goal instead is architectural:
|
||||
- **PERF-01**: The slave's master-gate check reads a `volatile` static in-memory field — zero async overhead, zero DB call per request.
|
||||
- **PERF-02**: Only the local availability gate touches the DB, unchanged from pre-existing behavior (1s cache per `AvailabilityOptions.StatusCacheSeconds`).
|
||||
|
||||
## Setup Performance Test Environment
|
||||
|
||||
### 1. Prepare Test Environment
|
||||
```bash
|
||||
dotnet run --project src/SlpModularCms.Api --urls http://localhost:5002 --environment Production
|
||||
```
|
||||
|
||||
### 2. Configure Test Parameters
|
||||
- **Test Duration**: 60 seconds
|
||||
- **Virtual Users**: 50 concurrent
|
||||
- **Target endpoint**: Any slave CMS route protected by `AvailabilityMiddleware`
|
||||
|
||||
## Run Performance Tests
|
||||
|
||||
### 1. Baseline (master-gate disabled / no `MasterRegistration` configured)
|
||||
```bash
|
||||
k6 run --vus 50 --duration 60s baseline-script.js
|
||||
```
|
||||
|
||||
### 2. With Master-Gate Enabled (registered slave, `_masterIsAvailable = true`)
|
||||
```bash
|
||||
k6 run --vus 50 --duration 60s gated-script.js
|
||||
```
|
||||
|
||||
### 3. Analyze Performance Results
|
||||
- **Expected**: p95 latency delta between baseline and gated runs should be negligible (sub-millisecond), since the gate check is a single `volatile` field read with no I/O.
|
||||
- **Bottlenecks**: If a measurable delta appears, verify no accidental DB or network call was introduced into `AvailabilityMiddleware`'s master-gate branch.
|
||||
|
||||
## Performance Optimization
|
||||
Not applicable at this time — no bottleneck identified in code review or NFR design. Revisit only if production monitoring shows gate-related latency.
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Unit Test Execution
|
||||
|
||||
## Run Backend Unit Tests
|
||||
```bash
|
||||
dotnet test SlpModularCms.sln --no-build
|
||||
```
|
||||
|
||||
### Expected Results
|
||||
| Test Project | Tests | Result |
|
||||
|---|---|---|
|
||||
| SlpModularCms.Core.Tests | 45 | Pass |
|
||||
| SlpModularCms.Modules.Identity.Tests | 46 | Pass |
|
||||
| SlpModularCms.Modules.Availability.Tests | 60 | Pass |
|
||||
| SlpModularCms.Modules.Master.Tests | 42 | Pass |
|
||||
| **Total** | **193** | **All Pass** |
|
||||
|
||||
## Run Frontend Unit Tests
|
||||
```bash
|
||||
cd frontend
|
||||
npm run test -- --run
|
||||
```
|
||||
|
||||
### Expected Results
|
||||
- **Test Files**: 34 passed (34)
|
||||
- **Tests**: 209 passed (209)
|
||||
- `Not implemented: Window's scrollTo()` messages are jsdom environment noise, not failures
|
||||
|
||||
## Fix Failing Tests
|
||||
If tests fail:
|
||||
1. Review console output for the failing test name and assertion
|
||||
2. For backend: check the relevant module's test project under `src/`
|
||||
3. For frontend: check `frontend/src/**/*.test.ts(x)`
|
||||
4. Rerun the specific test project/file until green
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
# Code Generation Plan — Unit 4: documentation
|
||||
|
||||
## Unit Context
|
||||
- **Scope**: Update `README.md` (root) with a Master CMS Module section covering the new module, migrations, and production env vars; replace the default Vite template `frontend/README.md` was never actually replaced by Unit 3 and still contains boilerplate — bring it in line with the rest of the documented feature set.
|
||||
- **Depends on**: Units 1-3 (master-backend, slave-availability-extension, frontend-cms-page) — documents their final, built-and-tested patterns.
|
||||
- **No new code**: Documentation only; no business logic, no NFRs, no tests. Functional Design / NFR Requirements / NFR Design were correctly skipped for this unit.
|
||||
|
||||
## Steps
|
||||
|
||||
- [x] **Step 1 — Root README: Add "Master CMS Module" section**
|
||||
Add a new `## Master CMS Module` section to `README.md` after the existing "Nieuwe Module Toevoegen" section, covering:
|
||||
- What the module does (Owner registers/manages slave CMS instances; slaves enforce master-controlled availability)
|
||||
- Architecture summary: `SlpModularCms.Modules.Master` (per-module `MasterDbContext`), extended `SlpModularCms.Modules.Availability` (slave-side `MasterRegistration` + two-phase `AvailabilityMiddleware`)
|
||||
- Registration flow: Owner adds a slave URL via `/cms` → Master generates an API key → Master pushes registration to the slave's `/api/v1/master/register` (`X-Master-Api-Key` header)
|
||||
- Status flow: Owner toggles status on Master → Master pushes to slave synchronously → fail-open on push failure (DB change not rolled back) → `IntegrityCheckBackgroundService` retries/reconciles on `IntegrityCheckIntervalMinutes` (default 60)
|
||||
- Fail-open behavior: slave defaults `_masterIsAvailable = true` at startup; no TTL on cached status
|
||||
|
||||
- [x] **Step 2 — Root README: Extend "Database Migraties" section**
|
||||
Add a subsection noting that `SlpModularCms.Modules.Master` and `SlpModularCms.Modules.Availability` are per-module `DbContext`s with their own migrations, applied automatically at startup via `Database.Migrate()`. Document the exact commands:
|
||||
```powershell
|
||||
dotnet ef migrations add <Naam> --project src\SlpModularCms.Modules.Master --startup-project src\SlpModularCms.Api
|
||||
dotnet ef migrations add <Naam> --project src\SlpModularCms.Modules.Availability --startup-project src\SlpModularCms.Api --context AvailabilityDbContext
|
||||
```
|
||||
Note the `--context` requirement for the Availability project (it now hosts two logical concerns sharing one `AvailabilityDbContext`, but `dotnet ef` needs disambiguation because the API composes multiple `DbContext` types across modules).
|
||||
|
||||
- [x] **Step 3 — Root README: Extend "Productie Setup" section**
|
||||
Add the new production-relevant configuration:
|
||||
- `MasterModule` options actually consumed by the code (bound from config section `MasterModule`): `IntegrityCheckIntervalMinutes` (default 60), `HttpTimeoutSeconds` (default 10), `MasterUrl`. **Revised during execution**: `CacheMinutes` and `ApiKey` are declared on `MasterModuleOptions` but never read anywhere in the codebase (verified via `dotnet-appsettings` skill pass) — they were superseded by Unit 2's actual design (per-instance encrypted keys, no-TTL cache). Left undocumented here per user decision; tracked as TD-001 in the new `tech-debt-backlog` feature instead of documenting dead config as if live.
|
||||
- **Data Protection key ring warning** (per NFR tech-stack-decisions.md): the API key encryption uses ASP.NET Core Data Protection with the default file-system key store. For containerized/multi-instance deployments, configure a persistent key ring (`PersistKeysToDbContext`, `PersistKeysToAzureBlobStorage`, etc.) — otherwise a container restart makes all stored `ApiKey` values undecryptable, breaking master↔slave communication until instances are re-added.
|
||||
- **Added during execution**: actual `MasterModule` config section added to `appsettings.json` and `appsettings.Development.json` (was completely missing before this unit, discovered via the `dotnet-appsettings` skill pass).
|
||||
|
||||
- [x] **Step 4 — Replace `frontend/README.md`**
|
||||
Replace the default Vite/React template content with a short pointer document: describe the frontend briefly and redirect to the root `README.md`'s "Frontend Development (CMS Admin UI)" section, which already documents setup, scripts, and configuration in full. Avoids duplicating content that already exists and stays in sync.
|
||||
|
||||
- [x] **Step 5 — Update feature state**
|
||||
Mark Unit 4 (documentation) Code Generation complete in `aidlc-docs/features/master-cms-module/aidlc-state.md`; update `aidlc-docs/active-features.md` status.
|
||||
|
||||
## Deviations From Plan (logged during execution)
|
||||
- **Missing EF migration found & fixed**: `SlpModularCms.Modules.Availability` had no migration for `MasterRegistration` (Unit 2 gap). Generated during Build & Test, before this unit started — see `aidlc-docs/features/master-cms-module/construction/build-and-test/build-and-test-summary.md`.
|
||||
- **Lint baseline correction**: the "all pre-existing" claim for frontend lint findings in the Build & Test summary was based on a contaminated comparison; corrected via a clean `git worktree` checkout. 2 of the 6 lint findings are new (Unit 3); all 6 moved to `tech-debt-backlog` (TD-002/TD-003) rather than fixed in-flight, per user decision.
|
||||
- **appsettings gap found & fixed**: `MasterModule` config section was entirely absent from `appsettings.json`/`appsettings.Development.json` despite `MasterModuleOptions.BindConfiguration("MasterModule")` in code. Added both files during this unit's execution (see Step 3).
|
||||
Reference in New Issue
Block a user