# 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 - [x] 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 only** — `AddHealthChecks()` + `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 - [x] Workspace Detection — Complete - [x] Reverse Engineering — Complete, approved 2026-07-27 (full rerun of all 8 `_shared/` artifacts) - [x] 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). - [x] User Stories — **SKIP** (infrastructure/operations work; no new end-user functionality or persona. Offered at Requirements Analysis approval, not requested.) - [x] Workflow Planning — Complete, approved 2026-07-27. Artifact: `inception/plans/execution-plan.md` - [x] 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. - [x] 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). - [x] 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 - [x] 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 - [x] Infrastructure Design — **EXECUTE for U6, U7 per the original plan; SKIP for the rest**. **U6 ✅** 2026-07-28 — single Pi, directory-only environment split, `systemd --user` (no sudo), releases/current/shared layout, 2-release retention, health check via public URL. Raised INFRA-U6-01 (linger requirement, carried to Operations). **U7 did not need it in practice**: by Units Generation, U7's scope had narrowed to documentation-only (Q8 = A — operational/infrastructure decisions moved to Operations), so it went straight to Code Generation with no infrastructure to design - [x] 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). **U6 ✅ U5 ✅** 2026-07-28 — Round 3: `deploy-scp.yaml` + `continuous_integration.yaml`, 372 backend + 237 frontend tests (unchanged from Round 2, confirming no regressions from FR-21/FR-22 fixes), 0 vulnerable packages, lint clean. Raised REF-U5-01 (Umami-origin gate needs a parallel Gitea variable, since the backend side is a host env var per D-16). **U7 ✅** 2026-07-28 — Round 4: `WEBSITE_WORKSPACE.md`, README.md and `.env.example` updated, all claims re-verified against actual U1–U6 source. **All 7 units complete.** - [ ] Build and Test — **EXECUTE** (phase-level, now that all 7 units are complete) ### 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: U1–U4), 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 4 **closed** 2026-07-28 — U7 complete and committed (`88770c5`). All 7 units of work are now generated - **Next Stage**: Build and Test (phase-level) — the last Construction stage before Operations - **Status**: Rounds 1–4 all done, nothing pushed. Starting Build and Test ## 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 — **372 passed, 0 failed** at stage close (Core 196, Availability 82, Master 57, Identity 37); was 253 after Round 1, 366 after U4, +6 from the integrity-check fix - 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 `Validate` → `AdminTokenResult` 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` - **Two defects found in local testing after Round 2, both fixed in this branch** rather than filed, per the standing rule that tech debt is for large or high-impact changes only: 1. Ciphertext written before U2 cannot be decrypted by the database key ring (`980dc80`). Recorded as ASM-08; local rows cleared and re-registered 2. `VerifyIntegrityAsync` could not tell an unreachable slave from one that does not recognise the master, so the only recoverable state was never repaired (`6957ec7`). Now four distinct outcomes; automatic registration on a rejected key is safe because the slave refuses any key that does not match an existing registration - **Note**: fix 2 is master/slave **domain** behaviour, not deployment work. It sits in this branch by explicit decision, not because it belongs to the feature - **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