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