Files
slp-modular-cms/aidlc-docs/features/gitea-deployment-workflow/aidlc-state.md
T
SluijsensandClaude Opus 5 8e79a72340 Makes the application say what it is doing and when it fails
U4. Console logging plus Sentry, a same-origin tunnel so ad blockers cannot
silence browser errors, Umami on the admin SPA, and six security events that
alert rules can actually be built on.

The correlation id is the W3C trace id from the ambient Activity, enabled by
one line of ActivityTrackingOptions so every entry from every category carries
it without touching a call site. It propagates across the master/slave
boundary via traceparent, which TraceIdentifier cannot do at all, and it is
the same value ProblemDetails already returns to the browser.

The security events use source-generated LoggerMessage with constant
templates. Sentry groups log events by message, so interpolating an email
address would give every address its own issue and "more than 20 failed
logins in five minutes" could never fire — the events would arrive, be
visible, be tagged, and the alerting would silently be impossible. A test
asserts the rendered message is identical across argument values.

Scrubbing happens in-process, before transmission, and covers Set-Cookie as
well as Cookie: the login response issues the refreshToken there, so
scrubbing only the request side would protect nothing. Transactions are
scrubbed too, because they carry request data and are the channel nobody
thinks of.

The tunnel derives its destination from the DSN once at startup and reads
nothing from the request, which is what separates a tunnel from a
server-side request forgery primitive. Size is capped by a bounded read
rather than by trusting Content-Length, and the endpoint is rate limited.

Two things found along the way. Zod 4's url() hands the value to the URL
constructor, which accepts any scheme — so the existing frontend validation
would have accepted the exact "htp://" typo BR-U4-24 names, and the SPA
would have called a nonexistent origin. Now constrained to http(s). And the
new appsettings comments are verified against the real configuration
provider, because the failure mode if it rejected them is both hosts
refusing to start after a release switch.

One deviation. IAdminTokenValidator was meant to gain a reason-reporting
overload; implemented that way, a substitute returning false by default
silently inverted the access decision while both methods compiled. Two
methods whose difference is invisible at the call site is the defect, so it
is now a single Validate returning AdminTokenResult.

Touches two files from already-committed units: DatabaseMigrationExtensions
(U2) gains a flush before the rethrow, or the one Critical event in the
system dies with the process; AdminTokenValidator (U1) classifies why a
bypass was refused.

Build 0 errors; 366 backend tests pass, up from 315, and 237 frontend tests,
up from 213. tsc clean, eslint clean on every changed file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHoJpxYXzHACSQguHrC5fw
2026-07-28 11:25:54 +02:00

11 KiB
Raw Blame History

AI-DLC State Tracking

Project Information

  • Feature Name: Gitea Deployment Workflow
  • Feature Slug: gitea-deployment-workflow
  • Project Type: Brownfield
  • Start Date: 2026-07-27T00:00:00Z
  • Current Stage: CONSTRUCTION - Code Generation complete for Round 2 (U3 + U4)
  • Branch: feature/gitea-deployment-workflow

Workspace State

  • Existing Code: Yes
  • Reverse Engineering Needed: Completed — full rerun on 2026-07-27 (user chose Q3 = B)
  • Workspace Root: K:\Development\Projects\SlpModularCms

Reverse Engineering Status

  • Reverse Engineering — Completed on 2026-07-27
  • Artifacts Location: aidlc-docs/_shared/reverse-engineering/ (all 8 artifacts regenerated + timestamp)
  • Verified by execution: Release build 0 errors / 50 warnings; 219 backend tests pass; 213 frontend tests pass; pnpm run lint fails (5 errors, 1 warning); 2 high-severity transitive package advisories

Code Location Rules

  • Application Code: Workspace root (NEVER in aidlc-docs/)
  • Feature Documentation: aidlc-docs/features/gitea-deployment-workflow/ only
  • Shared Artifacts: aidlc-docs/_shared/
  • Structure patterns: See code-generation.md Critical Rules

Language Configuration

  • Documentation Language: English
  • Conversation Language: User Language (Dutch)

Extension Configuration

Extension Enabled Decided At
Security Baseline Yes (blocking) Requirements Analysis
Property-Based Testing No Requirements Analysis

Operations Configuration

  • Include Operations Phase: Yes
  • Decided At: Requirements Analysis

Scope Decisions (from feature-selection.md)

  • Public website: documentation/instructions only — where the website build lands in wwwroot/, how it coexists with wwwroot/admin/, and what a per-website workspace must deliver. The website's own build/deploy workflow stays out of scope (Q4 = A).
  • Environments: local, test, production only.
  • Observability stack: UptimeRobot (uptime), Umami (analytics), console logging + Sentry (logging/errors).
  • Deployment constraint: upload as a published .NET application; no server configuration may be required.
  • Reference: existing working Gitea Actions setup at K:\Development\SlpSoftware\Projects\SlpSoftware (React/Vite) is the starting point.
  • Health check endpoint: IN SCOPE (decided 2026-07-27). Liveness onlyAddHealthChecks() + MapHealthChecks("/health"), no package needed and no database check (Q17 = A / D-21, superseding the earlier note that AddDbContextCheck might be included). /health must be added to AvailabilityMiddleware._bypassPrefixes so the availability gate cannot return 503 for it. Health = infrastructure liveness; Availability/capabilities = CMS domain state — these stay strictly separate.

Note

: this section records the earliest scope decisions. The authoritative and complete decision set is inception/requirements/requirements.md § 3 (D-01…D-32) — in particular, Q4 = C changed the public website from living directly in wwwroot/ to wwwroot/web/.

Stage Progress

INCEPTION

  • Workspace Detection — Complete
  • Reverse Engineering — Complete, approved 2026-07-27 (full rerun of all 8 _shared/ artifacts)
  • Requirements Analysis — Complete, approved 2026-07-27. 24 FRs (FR-24 added at Application Design), 10 NFRs, 32 decisions, 7 assumptions, 4 open items, 4 documented security deviations. Two question rounds: requirement-verification-questions.md (25 Q) and requirement-clarification-questions.md (5 Q).
  • User Stories — SKIP (infrastructure/operations work; no new end-user functionality or persona. Offered at Requirements Analysis approval, not requested.)
  • Workflow Planning — Complete, approved 2026-07-27. Artifact: inception/plans/execution-plan.md
  • Application Design — Complete, approved 2026-07-27. 14 code components (9 new, 5 modified) + 2 workflow components. Artifacts in inception/application-design/. Two composition conflicts found and carried to Unit 2. Added FR-24, closed OPEN-02.
  • Units Generation — Complete (awaiting approval). 7 units in 4 execution rounds. Artifacts: unit-of-work.md, unit-of-work-dependency.md, unit-of-work-story-map.md

CONSTRUCTION

Units finalised at Units Generation (see inception/application-design/unit-of-work.md): U1 Hosting & Serving · U2 Data Durability · U3 Security Headers & CSP · U4 Observability · U5 CI Workflow & Gates · U6 Deploy Workflow · U7 Documentation

Execution rounds (Q4 = B): R1 = U1 + U2 · R2 = U3 + U4 · R3 = U5 + U6 · R4 = U7. One commit per unit; single PR at the end (Q6 = A).

  • Functional Design — EXECUTE for U1, U2, U3, U4; SKIP for U5, U6, U7. U1 U2 approved 2026-07-27 · U3 U4 2026-07-28
  • NFR Requirements — SKIP (all units) — already comprehensively captured in requirements.md § 5 and § 6
  • NFR Design — EXECUTE for U3, U4; SKIP for the rest. Deliberate deviation from the default NFR-Requirements/NFR-Design coupling — rationale in the execution plan. U3 U4 2026-07-28 — 11 patterns for U3, 10 for U4. Closed OPEN-01; raised REF-U3-01
  • Infrastructure Design — EXECUTE for U6, U7; SKIP for the rest
  • [~] Code Generation — EXECUTE (all 7 units, each built and tested before its completion message). U1 U2 2026-07-27 (253 backend tests). U3 2026-07-28 (315). U4 2026-07-28 (366 backend + 237 frontend)
  • Build and Test — EXECUTE

OPERATIONS

  • Deployment Setup — EXECUTE
  • Monitoring Setup — EXECUTE
  • Production Readiness Validation — EXECUTE (includes the dotnet-appsettings compliance gate)

Execution Plan Summary

  • Risk Level: High — three destructive-and-silent failure modes (customer website loss, Data Protection key-ring loss, automatic migration against production)
  • Stages to Execute: Functional Design (×4: U1U4), NFR Design (×2: U3, U4), Infrastructure Design (×2: U6, U7), Code Generation (×7), Build and Test, Deployment Setup, Monitoring Setup, Production Readiness Validation
  • Stages to Skip: User Stories (no end-user functionality), NFR Requirements (already captured), plus per-unit skips as listed above

Current Status

  • Lifecycle Phase: CONSTRUCTION
  • Current Stage: Round 2 complete — U3 Security Headers & CSP and U4 Observability generated, built and tested
  • Next Stage: Round 3 — U5 CI Workflow & Gates + U6 Deploy Workflow (U6 needs Infrastructure Design first)
  • Status: Awaiting Round 2 code approval. Rounds 1 and 2 committed, nothing pushed

Round 2 Design Record (2026-07-28)

  • Functional Design U3 + U4 complete and committed (357d395)
  • NFR Design U3 — construction/u3-security-headers/nfr-design/ — 11 patterns. All new types in Core/Hosting/Security/, so Core.Tests can reach them (avoids repeating U1's Step 11 deviation)
  • NFR Design U4 — construction/u4-observability/nfr-design/ — 10 patterns. Sentry.AspNetCore 6.8.0 into Core; @sentry/react ^10.68.0 into frontend
  • OPEN-01 CLOSED: correlation ID = W3C trace ID from the ambient Activity, TraceIdentifier as fallback. Rationale: propagates master→slave via traceparent, and equals the traceId ASP.NET Core's ProblemDetails already returns
  • REF-U3-01 raised: BR-U3-22's Umami-origin startup warning is not implementable — the backend cannot read VITE_UMAMI_WEBSITE_ID. Withdrawn from U3 and replaced by a blocking U5 CI gate comparing the frontend build variable against that environment's SecurityHeaders:AllowedScriptOrigins
  • Additions beyond the functional design, each with rationale in the pattern docs: Set-Cookie added to the scrub list; a sentry-tunnel rate limiter; OnRejected on the existing rate limiter (today a 429 leaves no trace anywhere); SentrySdk.FlushAsync before the migration-failure rethrow (otherwise the one Critical event dies with the process)
  • Three defaults chosen rather than escalated (each one line to change, listed at the end of U4's pattern doc): JSON console outside Development, TracesSampleRate 0.1, tunnel cap 200 KB
  • U4 modifies two files from already-committed units — DatabaseMigrationExtensions (U2) and AdminTokenValidator (U1). Both additive; to be named in the U4 commit message

Round 1 Verification Record (2026-07-27)

  • dotnet build SlpModularCms.sln -c Release — 0 errors
  • Backend tests — 253 passed, 0 failed (Core 83, Availability 82, Identity 37, Master 51); baseline was 219
  • New EF migration 20260727203036_AddDataProtectionKeys — verified purely additive
  • Embedded placeholder resource name verified against the compiled assembly manifest
  • Carried to phase-level Build and Test: composed-startup behaviour that needs a running host and a real database — /admin trailing-slash redirect, 404-vs-HTML for missing assets, SPA fallback and placeholder resolution, /health while availability-disabled, MigrateCoreDatabase against SQL Server, and both hosts starting
  • Deviation: U1 plan Step 11 (StaticContentTests) not implemented — the code lives in SlpModularCms.Api, which has no test project by convention; behaviour carried to Build and Test instead. Recorded in the unit's generation-summary.md

Round 2 Verification Record (2026-07-28)

  • dotnet build SlpModularCms.sln -c Release — 0 errors (70 warnings, all pre-existing package advisories)
  • Backend tests — 366 passed, 0 failed (Core 196, Availability 82, Master 51, Identity 37); was 253 after Round 1
  • Frontend tests — 237 passed, 0 failed; baseline 213
  • npx tsc -b clean; eslint on every changed frontend file reports 0 problems; full pnpm run lint unchanged at the pre-existing 5 errors / 1 warning (FR-21, U5)
  • Sentry.AspNetCore 6.8.0 ships a native net10.0 asset — the carried-forward compatibility question is closed
  • @sentry/react 10.68.0; pnpm-lock.yaml diff is additions only
  • Two findings: z.string().url() accepts htp:// in Zod 4 (URL constructor accepts any scheme), so the pre-existing frontend validation never caught the typo BR-U4-24 names — now z.url({ protocol: /^https?$/ }). And appsettings.json comments are verified by DeployedConfigurationTests against the real provider rather than assumed, because the failure mode is both hosts refusing to start
  • One deviation: IAdminTokenValidator collapsed to a single ValidateAdminTokenResult instead of adding an overload. Two methods with an invisible difference at the call site let a substitute silently invert the access decision while both compiled — see U4's generation-summary.md
  • Carried to phase-level Build and Test: trace-ID propagation master → slave, TraceId present in rendered console output, tunnel status codes, the security_event tag on a real Sentry event, threshold behaviour end to end, and CSP/HSTS header presence on real static assets and error responses