Files
slp-modular-cms/aidlc-docs/_shared/reverse-engineering/dependencies.md
T
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

9.9 KiB
Raw Blame History

Dependencies

Internal Dependencies

graph TD
    api["SlpModularCms.Api<br/>Client"]
    slave["SlpModularCms.Api.Slave<br/>Client"]
    core["SlpModularCms.Core"]
    mid["Modules.Identity"]
    mav["Modules.Availability"]
    mma["Modules.Master"]
    tcore["Core.Tests"]
    tid["Modules.Identity.Tests"]
    tav["Modules.Availability.Tests"]
    tma["Modules.Master.Tests"]
    fe["frontend<br/>admin SPA"]

    api --> core
    api --> mid
    api --> mav
    api --> mma
    slave --> core
    slave --> mid
    slave --> mav
    mid --> core
    mav --> core
    mma --> core
    tcore --> core
    tid --> mid
    tav --> mav
    tma --> mma
    fe -->|"REST at runtime"| api
    api -->|"pnpm build at publish"| fe

    classDef client fill:#90cdf4,stroke:#2b6cb0,stroke-width:1px,color:#000;
    classDef corelayer fill:#fbd38d,stroke:#c05621,stroke-width:1px,color:#000;
    classDef module fill:#9ae6b4,stroke:#2f855a,stroke-width:1px,color:#000;
    classDef test fill:#e2e8f0,stroke:#4a5568,stroke-width:1px,color:#000;
    classDef frontend fill:#d6bcfa,stroke:#6b46c1,stroke-width:1px,color:#000;
    class api,slave client;
    class core corelayer;
    class mid,mav,mma module;
    class tcore,tid,tav,tma test;
    class fe frontend;

Text alternative: Both host projects reference Core and their modules; every module references only Core; each test project targets its own production project; the admin SPA calls the API at runtime and is itself built by the API project at publish time — a bidirectional coupling between backend and frontend.

Dependency Details

SlpModularCms.ApiSlpModularCms.Core

  • Type: Compile
  • Reason: AddCoreInfrastructure, AddCmsCors, AddCmsRateLimiting, ModuleOrchestrator, ApiPrefixConvention.

SlpModularCms.ApiModules.Identity, Modules.Availability, Modules.Master

  • Type: Compile (present to force the module DLLs into the output directory)
  • Reason: ModuleOrchestrator discovers modules by globbing SlpModularCms.Modules.*.dll in the app base directory, so a project reference is how a module ends up deployed. The code itself does not call into the modules directly. Consequence for deployment: which modules an instance has is determined by which DLLs the published output contains.

SlpModularCms.Api.SlaveCore, Modules.Identity, Modules.Availability

  • Type: Compile
  • Reason: Same as above, minus the Master module — the omission is the entire point of this host.

Modules.IdentityCore

  • Type: Compile
  • Reason: Identity entities, IAuthService, IInvitationService, ISetupService, request/response models, authorization policies.

Modules.AvailabilityCore

  • Type: Compile
  • Reason: IAvailabilityService, AvailabilityStatus, AvailabilityOptions, MasterControlledAvailabilityException, IModule.

Modules.MasterCore

  • Type: Compile
  • Reason: IModule, authorization policies, shared exception types.

Test projects → their production project (and transitively Core)

  • Type: Test
  • Reason: Each suite mirrors one production project, per the solution-folder rules in CLAUDE.md.

frontendSlpModularCms.Api

  • Type: Runtime (HTTP/REST)
  • Reason: All data comes from /api/v1/** at VITE_API_BASE_URL, with credentials so the refresh cookie travels.

SlpModularCms.Apifrontend (build-time, reverse direction)

  • Type: Build
  • Reason: The BuildAndCopyAdminFrontend MSBuild target runs pnpm install --frozen-lockfile and pnpm build in frontend/ before publish and copies dist/** into wwwroot/admin/. This makes Node and pnpm hard prerequisites of dotnet publish on any build agent.

Cross-instance runtime dependencies

Not project references, but real coupling between deployed instances:

  • A Master instance calls each registered slave's POST /api/v1/master/register and POST /api/v1/master/status, authenticated with X-Master-Api-Key, through a resilience pipeline (2 retries, exponential backoff with jitter, configurable timeout).
  • Each slave calls its Master's GET /api/v1/SlaveStatus on a timer (MasterPolling:PollIntervalSeconds), and fails open to Available after MasterPolling:FailOpenAfterMinutes of unreachability.
  • Both directions require the two instances to be reachable over HTTP from one another, which is a deployment/network consideration rather than a code one.

External Dependencies

Backend — SlpModularCms.Core

Package Version Purpose License
Microsoft.EntityFrameworkCore.SqlServer 10.0.9 SQL Server persistence MIT
Microsoft.AspNetCore.Identity.EntityFrameworkCore 10.0.9 Users, roles, password hashing MIT
Microsoft.AspNetCore.Authentication.JwtBearer 10.0.9 Bearer token validation MIT
Microsoft.AspNetCore.OpenApi 10.0.9 OpenAPI document generation MIT
Asp.Versioning.Mvc 10.0.0 API version reporting MIT
Microsoft.Extensions.DependencyInjection.Abstractions 10.0.9 DI abstractions MIT
Microsoft.Extensions.Hosting.Abstractions 10.0.9 Hosting abstractions MIT
Microsoft.Extensions.Logging.Abstractions 10.0.9 Logging abstractions MIT
FrameworkReference: Microsoft.AspNetCore.App net10.0 Lets a class library use ASP.NET Core types, incl. Data Protection MIT

Backend — SlpModularCms.Api

Package Version Purpose License
Asp.Versioning.Mvc 10.0.0 API versioning MIT
Microsoft.AspNetCore.Authentication.JwtBearer 10.0.9 Bearer auth MIT
Microsoft.AspNetCore.OpenApi 10.0.9 OpenAPI MIT
Microsoft.EntityFrameworkCore.Design 10.0.9 (PrivateAssets) dotnet ef tooling MIT
Scalar.AspNetCore 2.16.3 /scalar API reference, Development only MIT

SlpModularCms.Api.Slave carries Microsoft.EntityFrameworkCore.Design and Scalar.AspNetCore at the same versions.

Backend — modules

Project Package Version Purpose License
Modules.Master Microsoft.Extensions.Http.Resilience 9.6.0 Retry/timeout for master→slave calls (pulls in Polly) MIT
Modules.Availability No external packages beyond Core's transitives
Modules.Identity No external packages beyond Core's transitives

Version note: Microsoft.Extensions.Http.Resilience 9.6.0 is a 9.x package on net10.0 targets. It works, but it is the one dependency out of step with the otherwise uniform 10.0.x line — worth pinning deliberately rather than by accident in any CI setup.

Backend — test projects (all four, identical set)

Package Version Purpose License
Microsoft.NET.Test.Sdk 17.14.1 Test host MIT
xunit 2.9.3 Test framework Apache-2.0
xunit.runner.visualstudio 3.1.4 Test adapter Apache-2.0
FluentAssertions 8.10.0 Assertions Dual: free for non-commercial / paid commercial from v8 — worth verifying against how this project is used
NSubstitute 5.3.0 Mocking BSD-3-Clause
AutoFixture 4.18.1 Test data generation MIT
Microsoft.EntityFrameworkCore.InMemory 10.0.9 In-memory provider for tests MIT
coverlet.collector 6.0.4 Coverage collection MIT

Frontend — runtime (frontend/package.json dependencies)

Package Version Purpose License
react, react-dom ^19.2.6 UI framework MIT
@tanstack/react-router ^1.170.16 Routing (honours BASE_URL, so /admin works) MIT
@tanstack/react-query ^5.101.0 Server state MIT
@radix-ui/react-{dialog,dropdown-menu,label,select,slot} 1.x2.x Accessible primitives MIT
react-hook-form ^7.79.0 Forms MIT
@hookform/resolvers ^5.4.0 Validation bridge MIT
zod ^4.4.3 Schema validation (also validates app config) MIT
i18next, react-i18next, i18next-browser-languagedetector 26 / 17 / 8 NL/EN localisation MIT
lucide-react ^1.21.0 Icons ISC
sonner ^2.0.7 Toasts MIT
class-variance-authority, clsx, tailwind-merge 0.7 / 2.1 / 3.6 Class composition MIT

Frontend — build and test (devDependencies)

Package Version Purpose License
vite ^8.0.12 Build tool / dev server MIT
@vitejs/plugin-react ^6.0.1 React support MIT
typescript ~6.0.2 Type checking (tsc -b gates the build) Apache-2.0
tailwindcss, @tailwindcss/vite ^4.3.1 Styling MIT
vitest, @vitest/coverage-v8 ^4.1.9 Tests and coverage MIT
jsdom ^29.1.1 DOM for tests MIT
@testing-library/{react,jest-dom,user-event} 16.3 / 6.9 / 14.6 Component testing MIT
msw ^2.14.6 Request mocking MIT
eslint, typescript-eslint, eslint-plugin-react-hooks, eslint-plugin-react-refresh, @eslint/js, globals 10 / 8.59 / 7.1 / 0.5 / 10 / 17.6 Linting MIT
prettier ^3.8.4 Formatting MIT
concurrently ^9.1.2 Runs dev:all (master + slave dev servers) MIT
@types/{node,react,react-dom} 24 / 19.2 / 19.2 Type definitions MIT

Lockfiles and reproducibility

  • frontend/pnpm-lock.yaml exists, and the publish target uses --frozen-lockfile, so frontend installs are reproducible.
  • There is no packages.lock.json for any .NET project — NuGet restore is not locked, so dotnet restore can resolve differently over time on floating transitive versions. Relevant if reproducible CI builds matter.

Dependencies that are absent but expected by this feature

No package currently provides uptime, analytics, error tracking or structured logging. Adding Sentry (a Sentry.AspNetCore package on the backend and @sentry/react on the frontend) and Umami (a script tag, no package) would be new dependencies; UptimeRobot is external and needs only an HTTP endpoint to probe.