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

107 lines
8.6 KiB
Markdown

# Business Overview
## Business Context Diagram
```mermaid
graph TD
owner["Owner<br/>(system owner)"]
admin["Administrator"]
enduser["User"]
visitor["Public website visitor"]
cms["SlpModularCms instance<br/>(single host process)"]
slave["Other CMS instances<br/>(slaves)"]
db[("SQL Server<br/>database")]
owner --> cms
admin --> cms
enduser --> cms
visitor --> cms
cms --> db
cms -->|"pushes availability status"| slave
slave -->|"polls own status"| cms
classDef actor fill:#f6e05e,stroke:#c05621,stroke-width:1px,color:#000;
classDef system fill:#63b3ed,stroke:#2b6cb0,stroke-width:1px,color:#000;
classDef external fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
classDef store fill:#d6bcfa,stroke:#6b46c1,stroke-width:1px,color:#000;
class owner,admin,enduser,visitor actor;
class cms system;
class slave external;
class db store;
```
Text alternative: Owners, administrators, users and public visitors all interact with a single SlpModularCms host process, which persists to SQL Server and — when acting as a Master — centrally manages the availability of other (slave) CMS instances that in turn poll it for their own status.
## Business Description
- **Business Description**: SlpModularCms is a modular-monolith content management system built on .NET 10. A single deployed instance serves three surfaces from one host process: the customer's public website (`/`), the CMS administration UI (`/admin`), and the REST API (`/api/v1`). Functionality is delivered by pluggable modules discovered at startup, so one codebase can be deployed in different capability configurations. One instance can additionally take the role of **Master**, from which the system owner centrally enables or disables other ("slave") CMS instances — the commercial lever that lets the operator suspend a customer site (for example on non-payment) without needing access to that site's own hosting.
- **Business Transactions**:
| Transaction | Description |
|---|---|
| Initial system bootstrap | On a fresh installation the first Owner account is created via a one-time setup flow; afterwards the setup endpoint reports the system as initialized. |
| Authenticate a user | A user logs in and receives a short-lived access token plus a rotating refresh token held in an httpOnly cookie; the session refreshes silently and can be revoked. |
| Change own password | An authenticated user replaces their own password. |
| Invite and onboard a user | An administrator invites a person; the invitee validates the invitation token and completes registration to become an active user. |
| Manage users | An administrator lists users, changes a user's role, activates or deactivates a user, or deletes a user. Role changes obey a hierarchy (Owner > Administrator > User). |
| Maintain own profile | Any authenticated user updates their own profile details. |
| Control local availability | An Owner switches the instance between Available, NotAvailable and Maintenance, with an optional reason shown to blocked callers. |
| Register a slave instance | On the Master an Owner adds another CMS instance by URL; the Master generates an API key, stores it encrypted and pushes the registration to that instance. |
| Centrally set a slave's status | The Owner sets a registered instance to Available, NotAvailable or Inactive on the Master; the change is pushed to the slave synchronously. |
| Reconcile slave status | A recurring integrity check on the Master re-pushes the authoritative status to every active slave, and each slave independently polls the Master for its own status — so a restarted slave or a locally tampered status self-heals. |
| Discover instance capabilities | A client asks which optional modules are loaded on this instance, so it can hide features the deployment does not have rather than showing an error. |
| Serve the public website | An anonymous visitor loads the customer's public website from the same host process that runs the API. |
- **Business Dictionary**:
| Term | Meaning |
|---|---|
| **Module** | A self-contained functional unit implementing `IModule`, discovered from disk at startup. Determines what a deployed instance can do. |
| **Master** | An instance running the Master module, from which the availability of other instances is centrally managed. |
| **Slave** | An instance whose availability is (partly) controlled by a Master. Technically any instance running the Availability module that holds a Master registration. |
| **Availability status** | Whether an instance serves requests: `Available`, `NotAvailable`, or `Maintenance`. |
| **CMS instance status** | The Master's view of a registered instance: `Available`, `NotAvailable`, or `Inactive` (no longer managed by the Master; the gate is released). |
| **Master gate** | The check that blocks requests when the Master has marked this instance unavailable — separate from, and in addition to, the instance's own local availability switch. |
| **Fail-open** | Safety rule: if a slave cannot reach its Master for longer than a configured window, it reverts to Available, so an unreachable Master can never permanently block a site. |
| **Admin bypass** | An Owner or Administrator bearer token passes the availability gate, so administrators can always reach the system to switch it back on. |
| **Capability** | A module present on this instance, exposed so clients can distinguish "feature absent in this deployment" from "error". |
| **Owner / Administrator / User** | The hierarchical roles; a higher role satisfies every requirement of a lower one. |
| **Invitation** | A time-limited token allowing a named person to create an account. |
| **Public website** | The customer-facing site served at `/`. Built and deployed separately; **not part of this repository**. |
| **Admin SPA** | The CMS administration single-page application served at `/admin`, built from `frontend/`. |
## Component Level Business Descriptions
### SlpModularCms.Api (host / Client)
- **Purpose**: The deployable application. Boots the module system and serves all three surfaces — public website, admin SPA and API — from one process.
- **Responsibilities**: Compose configuration; discover and activate modules; serve static files and per-path SPA fallbacks; expose the API under a single `/api/v1` prefix; build and embed the admin SPA at publish time.
### SlpModularCms.Api.Slave (host / Client)
- **Purpose**: A second host representing an instance **without** the Master module, so master↔slave behaviour can be exercised locally.
- **Responsibilities**: Same as the Api host minus central management; deliberately references only Core, Identity and Availability.
### SlpModularCms.Core
- **Purpose**: The shared foundation every module builds on.
- **Responsibilities**: Identity, authentication and hierarchical authorization; the module contract and orchestrator; the availability contract; uniform RFC 9457 error responses; the `/api/v1` routing convention; capability reporting.
### SlpModularCms.Modules.Identity
- **Purpose**: Exposes account and access management to clients.
- **Responsibilities**: Login/refresh/revoke and password change; first-Owner setup; invitations; user administration.
### SlpModularCms.Modules.Availability
- **Purpose**: Decides whether this instance serves requests, honouring both the local switch and the Master's verdict.
- **Responsibilities**: Persist local availability; hold the Master registration; enforce the gate as middleware with documented bypasses; poll the Master for its own status; fail open when the Master is unreachable.
### SlpModularCms.Modules.Master
- **Purpose**: Turns an instance into the central control point for other instances.
- **Responsibilities**: Register instances and issue encrypted API keys; push status changes to slaves; answer a slave's status poll; reconcile periodically so drift and restarts self-heal.
### frontend (admin SPA)
- **Purpose**: The web UI through which Owners, Administrators and Users operate the CMS.
- **Responsibilities**: Login and silent session refresh; dashboard; user and invitation management; profile; availability settings (locked when the Master controls it); Master instance management; capability-driven feature gating.
### Test projects
- **Purpose**: Protect the business rules above against regression.
- **Responsibilities**: `SlpModularCms.Core.Tests`, `SlpModularCms.Modules.Identity.Tests`, `SlpModularCms.Modules.Availability.Tests` and `SlpModularCms.Modules.Master.Tests` mirror the production projects; the admin SPA has its own Vitest suite. `SlpModularCms.Api.Slave` has no test project by design.