Files
slp-modular-cms/aidlc-docs/features/slpsoftware-api/construction/slpsoftware-client-setup/nfr-design/nfr-design-patterns.md
T
SluijsensandClaude Sonnet 5 fa389e42ee
Continuous Integration / config (pull_request) Successful in 11s
Continuous Integration / changes (pull_request) Successful in 21s
Continuous Integration / backend-build (pull_request) Successful in 6m10s
Continuous Integration / vulnerability-scan (pull_request) Successful in 4m59s
Continuous Integration / frontend-prepare (pull_request) Successful in 1m27s
Continuous Integration / backend-test (pull_request) Failing after 7m48s
Continuous Integration / frontend-build (pull_request) Successful in 2m5s
Continuous Integration / frontend-test (pull_request) Successful in 4m24s
Continuous Integration / frontend-lint (pull_request) Successful in 2m0s
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 SlpModularCms.Api.SlpSoftware and extracts shared CmsHost composition
Unit 1 of the slpsoftware-api feature (FR-1/FR-2/FR-3): a new Client project
in the Clients solution folder, intended to eventually become the deployed
API for test.slpsoftware.nl/slpsoftware.nl, hosting the same four modules as
SlpModularCms.Api plus a future Offerings module.

- Extracts SlpModularCms.Api/Program.cs's hosting-pipeline composition into
  SlpModularCms.Core.Hosting.CmsHost (ConfigureServices/ConfigurePipeline),
  shared by both Client projects so they cannot drift apart
- Moves StaticContentExtensions.cs + WebsitePlaceholder.html from Api into
  Core, since CmsHost cannot live in Api but Core cannot depend on Api
- Adds SlpModularCms.Api.SlpSoftware with its own isolated local dev database
  and dev ports (5286/7223, distinct from Api's and Api.Slave's)
- Adds SlpModularCms.Api.Tests with WebApplicationFactory-based pipeline
  regression tests (security headers, health check, SPA fallback, rate
  limiting), scoped to Api per NFR Design
- Adds a frontend dev:slpsoftware pnpm script mirroring dev:slave
- Fixes GlobalExceptionHandler logging routine 401s (e.g. an expired/missing
  refresh token) as unhandled errors -- pre-existing, unrelated to this
  feature's own scope, found while testing the new instance

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

2.8 KiB

NFR Design Patterns — Unit: SlpSoftware Client Setup

Pattern 1: Pipeline Regression Test, Scoped to Api (NFR-CS-01)

Decision (Q1 = C): the new WebApplicationFactory-based integration tests target SlpModularCms.Api only. SlpModularCms.Api.SlpSoftware is not separately pipeline-tested in this unit — it inherits confidence transitively through the shared CmsHost.ConfigureServices/ConfigurePipeline code path that both projects call identically.

Pattern: a single WebApplicationFactory<TEntryPoint>-based test fixture, pointed at Api, asserting on real HTTP responses:

  • Security headers present (CSP, HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy) — CSP presence and required directives only, not the exact Umami/Sentry exceptions (those are Api-specific configuration, unrelated to CmsHost correctness).
  • /health returns success.
  • A non-file /admin/* route resolves to the admin SPA's index.html.
  • A burst of requests against a rate-limited route eventually receives a 429.

Accepted trade-off: if a future change to CmsHost behaves differently under Api.SlpSoftware's specific module composition (Offerings module present) than under Api's, this test suite alone would not catch it. This is an accepted gap per the user's decision, not an oversight — full end-to-end coverage of Api.SlpSoftware itself is covered later by the feature-wide Build and Test phase once Unit 2 exists.

Pattern 2: CmsHostOptions as an Empty Extension Point (NFR-CS-02)

Decision (Q2 = B): CmsHostOptions is introduced as a genuinely empty class (or, in C# terms, a class with zero properties, or internal sealed record CmsHostOptions; — exact syntax decided at Code Generation) — a placeholder in the method signature, not a placeholder-with-a-guess-field.

Pattern: standard Options Object pattern, sized for its current job (nothing) rather than a speculative future job. Both Api and Api.SlpSoftware construct new CmsHostOptions() and pass it to CmsHost.ConfigureServices(builder, options) / ConfigurePipeline(app, orchestrator, options). When a real per-project difference appears later, a property is added to this one class rather than changing either method's signature again.

Constraint carried forward (from NFR-CS-02 / tech-stack-decisions.md): whatever is eventually added to CmsHostOptions, it must never affect DataProtectionExtensions.ApplicationDiscriminator — that stays the hardcoded "SlpModularCms" constant regardless.

Pattern 3: Security — Verification, Not New Design (NFR-CS-03)

No new security pattern is introduced by this unit. The applicable pattern is "prove equivalence," fully covered by Pattern 1's regression tests. No additional logical components (WAF, extra middleware, etc.) are needed.