# Component Dependencies
Dependency matrix, communication patterns and data flow.
---
## Dependency Diagram
```mermaid
graph TD
subgraph core["SlpModularCms.Core"]
sechdr["C-01 SecurityHeadersMiddleware"]
secopt["C-02 SecurityHeadersOptions"]
csp["C-03 CspPolicyBuilder"]
health["C-04 Health checks"]
dp["C-05 CmsDataProtection"]
appdb["C-06 ApplicationDbContext
plus keys table"]
migrate["C-07 Migration runner"]
logging["C-08 CmsLogging"]
sentry["C-09 CmsSentry"]
end
subgraph apihost["SlpModularCms.Api"]
statics["C-10 Static mounts"]
prog["C-16 Host composition"]
end
subgraph slavehost["SlpModularCms.Api.Slave"]
progslave["C-16 Host composition"]
end
subgraph modules["Modules"]
avail["C-13 AvailabilityMiddleware"]
end
subgraph fe["frontend"]
cfg["C-14 Config"]
feobs["C-15 Sentry plus Umami"]
end
subgraph wf[".gitea/workflows"]
ci["C-12 CI workflow"]
scp["C-11 deploy-scp"]
end
sechdr --> secopt
sechdr --> csp
csp --> secopt
dp --> appdb
migrate --> appdb
sentry --> logging
prog --> sechdr
prog --> health
prog --> dp
prog --> migrate
prog --> logging
prog --> sentry
prog --> statics
progslave --> sechdr
progslave --> health
progslave --> dp
progslave --> migrate
progslave --> logging
progslave --> sentry
avail --> dp
cfg --> feobs
ci --> scp
ci --> fe
ci --> apihost
classDef corelayer fill:#fbd38d,stroke:#c05621,stroke-width:1px,color:#000;
classDef host fill:#90cdf4,stroke:#2b6cb0,stroke-width:1px,color:#000;
classDef module fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
classDef frontend fill:#d6bcfa,stroke:#6b46c1,stroke-width:1px,color:#000;
classDef workflow fill:#fbb6ce,stroke:#b83280,stroke-width:1px,color:#000;
class sechdr,secopt,csp,health,dp,appdb,migrate,logging,sentry corelayer;
class statics,prog,progslave host;
class avail module;
class cfg,feobs frontend;
class ci,scp workflow;
```
Text alternative: all new cross-cutting components live in Core and are consumed by both host projects; only the static mounts are exclusive to the Api host; the Availability middleware depends on Core's Data Protection; and the CI workflow orchestrates the frontend, the Api host and the deploy workflow.
---
## Dependency Matrix
| Component | Depends on | Depended on by | Coupling |
|---|---|---|---|
| C-01 `SecurityHeadersMiddleware` | C-02, C-03 | C-16 (both hosts) | Compile |
| C-02 `SecurityHeadersOptions` | Configuration | C-01, C-03 | Configuration binding |
| C-03 `CspPolicyBuilder` | C-02 | C-01 | Compile |
| C-04 Health checks | — | C-16 (both hosts) | Compile |
| C-05 `CmsDataProtection` | C-06 | C-16, and indirectly C-13 | Compile |
| C-06 `ApplicationDbContext` keys table | EF Core, SQL Server | C-05, C-07 | Compile + schema |
| C-07 Migration runner | C-06 | C-16 (both hosts) | Compile |
| C-08 `CmsLogging` | — | C-09, C-16 | Compile |
| C-09 `CmsSentry` | C-08, configuration | C-16 | Compile |
| C-10 Static mounts | Filesystem layout | C-16 (`Api` only) | Runtime (filesystem) |
| C-11 `deploy-scp.yaml` | Host over SSH | C-12 | Workflow call |
| C-12 CI workflow | C-11, both build outputs | — | Workflow |
| C-13 `AvailabilityMiddleware` | C-05 (key ring), validated principal | Both hosts, via module discovery | Compile + runtime |
| C-14 Frontend config | Vite build variables | C-15, `ApiClient` | Build-time |
| C-15 Frontend observability | C-14, Vite build variables | — | Build-time |
| C-16 Host composition | C-01, C-04, C-05, C-07, C-08, C-09, C-10 | — | Compile |
---
## Communication Patterns
### In-process (the majority)
Everything in `Core` is consumed by the hosts through **DI registration and middleware composition**. There are no new service-to-service calls, no new queues and no new network hops inside the application. This is deliberate: the feature adds cross-cutting behaviour, not new interactions.
### Configuration-driven
`C-02` binds the `SecurityHeaders` section; `C-09` reads a Sentry DSN; `C-05` reads Data Protection settings. All follow the existing Options pattern. **Configuration errors must surface at startup, not per request** — an unknown CSP policy name fails the process rather than silently degrading, which given fail-fast startup (Q8 = A) means a misconfigured deployment goes visibly red instead of quietly serving without protection.
### Filesystem-coupled (the fragile one)
`C-10` depends on a directory layout that no code creates:
| Path | Owner | Created by |
|---|---|---|
| `wwwroot/admin/` | This repository | `dotnet publish` (`BuildAndCopyAdminFrontend` target) |
| `wwwroot/web/` | **A separate website workspace** | That workspace's own deployment; persists across releases (ASM-01) |
This is the feature's most fragile coupling, because it is enforced by convention rather than by the type system. Two consequences:
1. `C-10` must **tolerate a missing `wwwroot/web/` at startup** — a fresh deployment has none until a website workspace deploys into it, and the CMS must still start and serve `/admin` and `/api/v1`.
2. The deployment (S-05) must link the persistent `wwwroot/web/` into each new release directory. Getting this wrong destroys the customer's website — the highest-severity risk in the feature (NFR-02).
### Build-time coupling (frontend)
`C-14` and `C-15` read Vite variables baked in at build time, which is precisely why two artifacts are produced (D-15). The backend and frontend are additionally coupled in the *reverse* direction by the publish target, which runs `pnpm install` and `pnpm build` — making Node and pnpm prerequisites of `dotnet publish` and a required step in the CI workflow's toolchain setup.
### Cross-instance (unchanged, but newly protected)
Master↔slave communication is untouched functionally. What changes is its durability: with `C-05` and `C-06`, the encrypted API keys underpinning that trust survive a redeploy. Previously an atomic release switch would have discarded the file-based key ring and broken the protocol silently.
---
## Data Flow
### Request flow with the new components
```mermaid
sequenceDiagram
box rgba(246,224,94,0.4) Client
participant V as Visitor or admin
end
box rgba(144,205,244,0.4) Pipeline
participant E as Exception handler
participant S as Security headers
participant F as Static files
participant A as Availability gate
participant H as Health endpoint
end
V->>E: HTTP request
E->>S: continue
S->>S: resolve CSP policy for path
S->>F: continue with OnStarting callback
alt file exists in web or admin mount
F-->>V: file, headers applied at response start
else no matching file
F->>A: continue
alt path is /health or another bypass prefix
A->>H: continue
H-->>V: 200 Healthy or 503 Unhealthy
else instance disabled
A-->>V: 503 ProblemDetails
else instance available
A-->>V: routed to controllers or SPA fallback
end
end
```
Text alternative: security headers register a response-start callback before static files short-circuit, so both static and dynamic responses carry them; `/health` passes the availability gate via the bypass list, while other paths are blocked with a 503 when the instance is disabled.
### Startup flow
```mermaid
graph TD
start["Process starts"]
log["Configure logging and Sentry"]
disc["Discover modules"]
svc["Register services
including Data Protection"]
build["Build application"]
mig["Migrate ApplicationDbContext"]
modmig["Module contexts migrate
during UseModules"]
serve["Accept traffic;
/health answers"]
dead["Process does not start;
/health silent, UptimeRobot red"]
start --> log
log --> disc
disc --> svc
svc --> build
build --> mig
mig -->|success| modmig
mig -->|failure| dead
modmig --> serve
classDef normal fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
classDef decision fill:#90cdf4,stroke:#2b6cb0,stroke-width:1px,color:#000;
classDef bad fill:#fbb6ce,stroke:#b83280,stroke-width:1px,color:#000;
class start,log,disc,svc,build,modmig,serve normal;
class mig decision;
class dead bad;
```
Text alternative: logging and Sentry are configured first so any later startup failure is captured; Core migrations run before module migrations, and a migration failure stops the process entirely rather than serving a broken application.
### Deployment data flow
```mermaid
graph LR
art["Build artifact"]
backup[("Database backup
production only")]
newrel["New release directory"]
persist[("Persistent wwwroot/web
customer website")]
active["Active release symlink"]
prev["Retained previous release"]
art --> newrel
backup -.->|before any change| newrel
persist -->|linked into| newrel
newrel --> active
active -.->|previous becomes| prev
prev -.->|rollback| active
classDef artifact fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
classDef store fill:#d6bcfa,stroke:#6b46c1,stroke-width:1px,color:#000;
classDef link fill:#90cdf4,stroke:#2b6cb0,stroke-width:1px,color:#000;
class art,newrel artifact;
class backup,persist store;
class active,prev link;
```
Text alternative: the build artifact populates a new release directory into which the persistent customer website is linked; the active pointer then switches atomically, and the previous release is retained so a rollback is a pointer switch rather than a rebuild.
---
## Coupling Concerns
| Concern | Assessment |
|---|---|
| **`Core` is inherited by both hosts** | Intended (Q1 = A, Q2 = A). Every `Core` change reaches `SlpModularCms.Api.Slave`, which has no test project — so it is verified at Build and Test by actually starting it. The Slave is a reference instance, not a throwaway. |
| **Duplicate `AddDataProtection()` in two modules** | **A real conflict**, documented in `services.md` S-01. Module registration runs *after* host registration, so the modules' calls would override the persistent key store and make FR-12 a no-op that looks implemented. Both must be removed. |
| **`AvailabilityMiddleware` runs before `UseAuthentication()`** | Constrains how FR-24 can be implemented — either validate the token in the middleware, or move authentication earlier. Resolved in Functional Design for Unit 2. |
| **Filesystem convention for `wwwroot/web/`** | The weakest link: not enforceable in code, and getting it wrong is destructive. Mitigated by design (persistent path outside the release directory) and by documentation (FR-09), but it stays a convention. |
| **Static files short-circuit the pipeline** | Dictates that security headers precede them. Any future middleware that must see all responses faces the same constraint — worth remembering rather than rediscovering. |
| **Build-time frontend configuration** | Forces two build artifacts. Accepted (D-15), with runtime configuration recorded as a possible later improvement. |