Files
SluijsensandClaude Opus 5 8568ca43c6 Plans the Gitea deployment feature and refreshes the codebase analysis
Adds the AI-DLC inception record for deploying the CMS as a single .NET
application on hosting where no server configuration is possible.

The reverse-engineering artifacts were regenerated: the previous set
predated the Master module, the Slave host, the solution reorganisation
and single-host serving, all of which matter for deployment. Findings
were verified by running the build, both test suites and the linter
rather than inferred, which surfaced two facts the plan depends on:
the frontend lint gate currently fails (5 errors), and two transitive
packages carry high-severity advisories.

Records 24 functional requirements, 32 traced decisions and a
seven-unit decomposition whose ordering is load-bearing: durability
work must land before the first automated deploy, or the very first
deploy is the one that silently breaks master/slave trust.

Two conflicts found while designing and carried into the units:
- Both modules call AddDataProtection(), which runs after the host and
  would override a persistent key store while still passing any
  registration test.
- The availability gate runs before authentication, so its admin
  bypass cannot read HttpContext.User.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHoJpxYXzHACSQguHrC5fw
2026-07-27 23:59:30 +02:00

7.5 KiB

Unit of Work Dependencies


Dependency Diagram

graph TD
    u1["U1 Hosting and Serving"]
    u2["U2 Data Durability"]
    u3["U3 Security Headers and CSP"]
    u4["U4 Observability"]
    u5["U5 CI Workflow and Gates"]
    u6["U6 Deploy Workflow"]
    u7["U7 Documentation"]
    ops["Operations Phase"]

    u1 -->|"path layout for CSP scoping"| u3
    u4 -->|"Umami and Sentry origins"| u3
    u4 -->|"env-specific Vite variables"| u5
    u1 --> u6
    u2 -->|"durability must precede first deploy"| u6
    u3 --> u5
    u5 -->|"invokes"| u6
    u6 -->|"settled host layout"| u7
    u6 --> ops
    u7 --> ops

    classDef r1 fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
    classDef r2 fill:#90cdf4,stroke:#2b6cb0,stroke-width:1px,color:#000;
    classDef r3 fill:#fbd38d,stroke:#c05621,stroke-width:1px,color:#000;
    classDef r4 fill:#d6bcfa,stroke:#6b46c1,stroke-width:1px,color:#000;
    classDef opsphase fill:#f6e05e,stroke:#c05621,stroke-width:1px,color:#000;
    class u1,u2 r1;
    class u3,u4 r2;
    class u5,u6 r3;
    class u7 r4;
    class ops opsphase;

Text alternative: U1 and U2 are independent and run first; U3 needs U1's path layout and U4's origins; U5 and U6 need the application work complete; U7 needs U6's settled host layout; the Operations phase follows.


Dependency Matrix

Unit Depends on Depended on by Nature of dependency
U1 Hosting & Serving U3, U6 Establishes the path layout that U3's CSP scopes against and U6 deploys into
U2 Data Durability U6 Must land before any automated deploy, or the first atomic switch destroys the key ring
U3 Security Headers U1, U4 U5 Needs U1's final paths and U4's external origins
U4 Observability U3, U5 Introduces the origins U3 must permit and the build variables U5 must supply
U5 CI Workflow U3, U4 U6 Gates must pass against the finished application; the two builds need U4's variables
U6 Deploy Workflow U1, U2, U5 U7, Operations Deploys what the application units produced, invoked by U5
U7 Documentation U6 Operations Documents the layout U6 settles

Ordering Constraints That Are Load-Bearing

These are not preferences. Reordering any of them produces a broken or dangerous result.

1. U2 before U6 — otherwise the first deploy is the dangerous one

The atomic release switch (U6) changes the content root path on every deploy. Until U2 configures a database-backed key ring with an explicit application discriminator, that switch discards the Data Protection keys and makes every stored slave API key undecryptable. The symptom presents as a network fault between master and slave, so it would be misdiagnosed.

Deploying first and hardening afterwards means the very first production deploy carries the failure.

2. U4 before or with U3 — otherwise the CSP is written blind

U3's Strict policy must permit the Umami script origin and the Sentry ingest origin. Those origins are introduced by U4. Writing U3 first means either guessing them or shipping a CSP that blocks the observability U4 then adds — a failure that appears only in a real browser.

This is why R2 groups them rather than running them in sequence.

3. U1 before U3 — otherwise path scoping is provisional

U3 assigns policies by path prefix. Until U1 settles which paths exist and where they are served from, that assignment is written against a layout still in flux.

4. U3 and U4 before U5 — otherwise the gates fail on incomplete work

U5's six gates run against the whole application. Switching them on before the application units are complete produces failures that reflect unfinished work rather than defects.

5. U5 with U6 — one interface, two files

U6 is a reusable workflow invoked by U5 with a fixed input set. Designing them apart risks an interface mismatch that only surfaces on the first real run.

6. U6 before U7 — documentation cannot precede the layout it documents

U7's website contract states target paths, reserved paths and the persistent-directory arrangement. U6 settles those in its Infrastructure Design.


What Is Not Dependent

Worth stating explicitly, because it justifies the grouping:

  • U1 and U2 do not touch each other. U1 changes serving and middleware; U2 changes persistence and startup. They share Program.cs as a file, but not as logic — U1 adds pipeline and endpoint registrations, U2 adds service registration and a startup call. A merge conflict is possible; a behavioural conflict is not.
  • U4 does not depend on U1, U2 or U3. Observability can be added to the application as it stands today.
  • U7 does not depend on U3, U4 or U5 beyond describing their results.

Shared Resources and Coordination Points

Resource Touched by Coordination needed
SlpModularCms.Api/Program.cs U1, U2, U3, U4 Four units modify the same file in different places. Registration and pipeline order is specified in services.md § S-01, so each unit inserts at a defined position rather than appending
SlpModularCms.Api.Slave/Program.cs U1 (health only), U2, U3, U4 Same, minus the static mounts. The Slave is a reference instance (Q2 of Application Design = A) and must keep working; it has no test project, so it is verified by starting it
SlpModularCms.Core U1, U2, U3, U4 Each unit adds its own subfolder under Hosting/Health/, Security/, Observability/ — so files do not collide
AvailabilityModule.cs / MasterModule.cs U2 Removing AddDataProtection() from both. No other unit touches them
appsettings.json U2, U3, U4 Three new sections. Additive, no overlap
frontend/ U4 (features), U5 (lint fixes) U5's lint fixes touch AddCmsInstanceDialog.tsx, InviteUserDialog.tsx, SettingsPage.tsx and SetStatusDialog.tsx; U4 touches main.tsx, config.ts and adds a Umami component. No overlapping files
.gitea/workflows/ U5, U6 Separate files sharing one input contract

Consequence of Merging the Quality Gates into U5

Q2 = B moved the lint fixes and package pins from a standalone first unit into U5. This is coherent — gates and their prerequisites land in one commit, so the pipeline is never red on arrival — but it has one side effect worth managing:

pnpm run lint stays failing through U3 and U4, and U4 changes frontend files. New violations introduced during U4 would therefore hide among the five pre-existing ones.

Mitigation: run lint on the changed files during U4 rather than the whole tree. The blocking gate still arrives with U5, but nothing new accumulates in the meantime.

The overlap is limited: U5's fixes and U4's changes touch disjoint files, so there is no merge risk — only a detection gap.


Rollback Between Units

Every unit is a self-contained commit on feature/gitea-deployment-workflow, with a single pull request at the end (Q6 = A).

Unit Revertible independently? Notes
U1 Yes Pipeline and endpoint registrations
U2 Yes, with care The Core migration adds a table; reverting the code leaves the table in place, which is harmless
U3 Yes Additive middleware plus one config section
U4 Yes Additive
U5 Yes New file plus lint and package changes
U6 Yes New file only
U7 Yes Documentation only

Nothing is deployed to any environment until U6 is complete and explicitly triggered, so a mid-sequence failure cannot affect a running environment.