Files
slp-modular-cms/aidlc-docs/features/slpsoftware-api/construction/slpsoftware-client-setup/code/summary.md
T
SluijsensandClaude Sonnet 5 0feedf9c01
Continuous Integration / config (pull_request) Successful in 12s
Continuous Integration / changes (pull_request) Successful in 22s
Continuous Integration / backend-build (pull_request) Successful in 5m52s
Continuous Integration / vulnerability-scan (pull_request) Successful in 5m6s
Continuous Integration / frontend-prepare (pull_request) Successful in 1m24s
Continuous Integration / backend-test (pull_request) Failing after 8m24s
Continuous Integration / frontend-build (pull_request) Successful in 2m14s
Continuous Integration / frontend-test (pull_request) Successful in 4m28s
Continuous Integration / frontend-lint (pull_request) Successful in 2m5s
Continuous Integration / publish-test (pull_request) Skipped
Continuous Integration / publish-production (pull_request) Skipped
Continuous Integration / deploy-test (pull_request) Skipped
Continuous Integration / deploy-production (pull_request) Skipped
Adds a MariaDB service to backend-test for SlpModularCms.Api.Tests
The new pipeline regression tests boot the real Api host via
WebApplicationFactory, which unconditionally runs the startup database
migration -- unlike every other test project here, which mocks or uses EF
Core InMemory. CI had no MariaDB service at all, so those tests failed on
the connection itself. Adds a mariadb service container to the backend-test
job plus a ConnectionStrings__DefaultConnection override for that step,
which overrides the appsettings.Development.json placeholder via standard
config layering without touching any committed appsettings file or
affecting local test runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FWyStNL2ZsjrS7FLd7xvvN
2026-08-02 10:46:25 +02:00

8.4 KiB

Code Generation Summary — Unit: SlpSoftware Client Setup

Moved (brownfield relocation, Step 1)

  • src/SlpModularCms.Api/Extensions/StaticContentExtensions.cssrc/SlpModularCms.Core/Hosting/StaticContentExtensions.cs (namespace SlpModularCms.Api.ExtensionsSlpModularCms.Core.Hosting; embedded-resource name updated to match)
  • src/SlpModularCms.Api/Extensions/WebsitePlaceholder.htmlsrc/SlpModularCms.Core/Hosting/WebsitePlaceholder.html
  • Deleted the now-empty src/SlpModularCms.Api/Extensions/ directory

Created

  • src/SlpModularCms.Core/Hosting/CmsHostOptions.cs — empty extension-point class (NFR Design Pattern 2)
  • src/SlpModularCms.Core/Hosting/CmsHost.csConfigureServices/ConfigurePipeline, the shared composition both Client projects call
  • src/SlpModularCms.Api.SlpSoftware/ — new Client project: .csproj, Program.cs, appsettings.json, appsettings.Development.json (own isolated local dev database, Infrastructure Design Q1 = B), Properties/launchSettings.json (ports 5286/7222, distinct from Api's 5284/7221 so both can run simultaneously)
  • src/SlpModularCms.Api.Tests/ — new test project: .csproj, PipelineTests.cs (4 tests: /health reachable, required security headers present on an HTML response with HSTS's Development-only absence explicitly asserted, /admin fallback 404s correctly with no build present, the sentry-tunnel rate limiter engages past its configured permit limit)

Modified

  • src/SlpModularCms.Api/Program.cs — rewritten to the thin form calling CmsHost.ConfigureServices/ConfigurePipeline; no behavior change
  • src/SlpModularCms.Api/SlpModularCms.Api.csproj — removed the WebsitePlaceholder.html embedded-resource item (moved to Core)
  • src/SlpModularCms.Core/SlpModularCms.Core.csproj — added the WebsitePlaceholder.html embedded-resource item
  • SlpModularCms.sln — added SlpModularCms.Api.SlpSoftware (nested under Clients) and SlpModularCms.Api.Tests (nested directly under Tests, mirroring Core.Tests's placement)
  • README.md — documented the new project, CmsHost, and the local dev database isolation

Not Created (explicit N/A, per the plan)

  • No Program.Coverage.cs for Api.SlpSoftware — no pipeline tests target it in this unit (Q1 = C)
  • No appsettings.local.json for Api.SlpSoftware — git-ignored, personal-per-developer, created locally when needed
  • No API/Repository layer code, no database migrations — this unit has neither (Unit 2 "Offerings" does)
  • No .gitea/workflows/*.yaml or Gitea Actions variable changes — Operations-phase scope (D-7/D-15)

Post-Completion Fix: Dev Port Collision + Frontend Dev Script

Prompted by a user question about a frontend pnpm dev:slpsoftware script, investigation surfaced a real bug: Api.SlpSoftware's launchSettings.json had been assigned HTTPS port 7222, which is already SlpModularCms.Api.Slave's port (confirmed via frontend/.env.example and Api.Slave/Properties/launchSettings.json). Fixed:

  • src/SlpModularCms.Api.SlpSoftware/Properties/launchSettings.json — HTTPS port 7222 → 7223 (HTTP 5286 unchanged, already free)
  • src/SlpModularCms.Api.SlpSoftware/appsettings.Development.jsonMasterModule:MasterUrl updated to match (https://localhost:7223)
  • README.md — corrected port note, with an explicit call-out of the 7222 collision reason

Added (frontend, not part of the original per-unit plan, but a direct, symmetrical follow-up to the port fix):

  • frontend/package.jsondev:slpsoftware script (vite --mode slpsoftware --port 5175), mirroring dev:slave
  • frontend/.env.example — documented the .env.slpsoftware.local pattern (VITE_API_BASE_URL=https://localhost:7223, VITE_APP_TITLE=SlpModularCms (SlpSoftware))

Post-Completion Fix: CORS Origin Mismatch Blocked the Setup Page

Api.SlpSoftware/appsettings.Development.json's Cors:AllowedOrigins had been copied from Api's own file verbatim, listing localhost:5173 — but pnpm dev:slpsoftware serves the frontend on port 5175. The mismatch caused the frontend's /api/v1/Setup/status check to fail on CORS, and router.tsx's InitGuard fails open toward the login page (not setup) on any fetch error — so the setup page never appeared, even against a genuinely empty database (verified directly via the local MariaDB, not assumed). Fixed: Cors:AllowedOrigins now lists localhost:5175.

Post-Completion Fix: GlobalExceptionHandler Logged Expected 401s as Errors

Pre-existing bug, unrelated to this feature's own scope (not introduced by the CmsHost extraction) but surfaced by testing the new instance: src/SlpModularCms.Core/Exceptions/GlobalExceptionHandler.cs logged every exception at LogError before mapping it to a status code, so a routine UnauthorizedException (e.g. an invalid/missing refresh token — the normal state for a fresh, never-logged-in session) was indistinguishable from a genuine unhandled 500 in the console and in Sentry. Fixed: exceptions that map to a status below 500 now log at LogWarning; only genuinely unmapped exceptions (500) log at LogError. Affects every Client project equally (Api, Api.Slave, Api.SlpSoftware), not just this feature. No existing test asserted log level; full suite reran green (196 + 4).

Post-Completion Fix: CI's backend-test Job Had No Database

The Gitea Actions backend-test job (.gitea/workflows/continuous_integration.yaml) just ran dotnet test with no MariaDB service — every pre-existing test project mocks or uses EF Core InMemory, so none of them ever needed one. SlpModularCms.Api.Tests boots the real Api host via WebApplicationFactory, which unconditionally runs the startup migration, so it genuinely needs a reachable database — a design gap in this unit's own NFR Requirements/Design that should have been anticipated when committing to a real pipeline test (Q1 = C) rather than a mocked one. Fixed by adding a mariadb service container to backend-test plus a ConnectionStrings__DefaultConnection environment-variable override for that step only (overrides the placeholder in Api/appsettings.Development.json via standard ASP.NET Core config layering — env vars win over appsettings.*.json). No committed appsettings changed; local dotnet test runs are unaffected (developers' own appsettings.local.json still applies there). Verified the override mechanism directly against the local MariaDB container before trusting it in CI.

Scope note: continuous_integration.yaml is nominally owned by the gitea-deployment-workflow feature. This specific change (making the test gate pass for a test project this feature introduced) was judged in-scope to fix directly as Build-and-Test correctness — distinct from the actual deploy-target retarget (D-15), which remains deferred to this feature's own Operations phase.

Build and Test Verification (Step 13.5)

Two real build fixes were needed and applied during this step (not deviations from the plan — the plan didn't anticipate these, since they only surface once the code actually compiles):

  1. SlpModularCms.Core.csproj was missing a Scalar.AspNetCore package reference — CmsHost.ConfigurePipeline calls MapScalarApiReference(), which moved into Core along with the rest of the pipeline composition but the package reference hadn't followed it. Added.
  2. CmsHost.cs and the moved StaticContentExtensions.cs were missing explicit using Microsoft.Extensions.Hosting; / using Microsoft.Extensions.DependencyInjection;Core is an Microsoft.NET.Sdk project (not Sdk.Web), so it does not get ASP.NET Core's implicit usings the way Api (Sdk.Web) did. Added both.

After both fixes:

  • Build: Success (full solution, all 13 projects)
  • SlpModularCms.Core.Tests: 196 passed, 0 failed — no regression from the Step 1 file move
  • SlpModularCms.Api.Tests (new): 4 passed, 0 failed — /health reachable, required security headers present on an HTML response (with HSTS's Development-only absence correctly asserted, not overlooked), /admin fallback 404s correctly with no build present, the sentry-tunnel rate limiter engages past its configured permit limit

Local environment note: running the new tests required a local MariaDB (the same one Api itself needs to run, per the README). It was stopped; started it via podman machine start + podman start mariadb for this verification, and left both running afterward for continued local development (including Unit 2 "Offerings").