Sluijsens 8072025e0b Completes master-cms-module: Build & Test, docs, and appsettings
Finishes the master-cms-module feature (Units 1-4): runs Build and
Test across master-backend, slave-availability-extension and
frontend-cms-page, fixes a missing Availability EF migration for
MasterRegistration and a TanStack Query v5 mutation-callback type
break, adds the missing MasterModule appsettings section, and
documents the module in README.md. Also seeds a tech-debt-backlog
feature to track dead config and pre-existing/introduced frontend
lint findings for later cleanup.
2026-07-01 23:09:15 +02:00
2026-06-15 17:00:16 +02:00

SlpModularCms

Een modulaire monolith CMS gebouwd met .NET 10.

Projectstructuur

  • src/SlpModularCms.Api: De host applicatie en API shell.
  • src/SlpModularCms.Core: Kern functionaliteiten, data modellen en interfaces.
  • src/SlpModularCms.Modules.*: Onafhankelijke functionele modules.
  • frontend/: De CMS admin web-UI (Vite + React + TypeScript). Bewust buiten src/ gehouden om de .NET solution schoon te houden.

Development Setup

Vereisten

  • .NET 10 SDK
  • Podman of Docker (voor SQL Server)

1. Database opstarten

Start een SQL Server container met de volgende opdracht:

podman run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=MSSQL_s3cr3t_pw!" -p 1433:1433 --name sql-server -d mcr.microsoft.com/mssql/server:2022-latest

2. Configuratie

De applicatie maakt gebruik van een drie-bestanden patroon voor configuratie:

  • appsettings.json: Productie baseline.
  • appsettings.Development.json: Ontwikkelinstellingen.
  • appsettings.local.json: Lokale overrides (niet in Git).

Zorg dat er een src/SlpModularCms.Api/appsettings.local.json aanwezig is met de juiste connection string:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=127.0.0.1,1433;User ID=sa;Password=MSSQL_s3cr3t_pw!;Database=SlpModularCms;TrustServerCertificate=True;MultipleActiveResultSets=true"
  }
}

3. Applicatie starten

Voer de applicatie uit vanaf de root:

dotnet run --project src/SlpModularCms.Api

De API is daarna bereikbaar op https://localhost:7221 (of de geconfigureerde poort). De OpenAPI documentatie (Scalar) is beschikbaar op /scalar.

Initiële Setup (Bootstrapping)

...

Authenticatie & Security (Unit 0)

De API gebruikt een beveiligde flow voor authenticatie:

  • Login: POST /api/v1/auth/login. Retourneert een accessToken in de body en een refreshToken in een beveiligde httpOnly cookie.
  • Refresh: POST /api/v1/auth/refresh. Gebruikt de refreshToken cookie om een nieuwe accessToken en refreshToken (rotatie) te genereren.
  • Revoke: POST /api/v1/auth/revoke. Trekt het token in en wist de cookie.

Belangrijke NFR Details:

  • CORS: Alleen toegestane origins uit appsettings.json → Cors:AllowedOrigins worden geaccepteerd. De frontend moet draaien op een van deze origins.
  • Cookies: De refreshToken cookie is httpOnly, SameSite=Strict en heeft het pad /api/v1/auth.
  • Rate Limiting: Login endpoints hebben rate limiting (Fixed window 5/min, Sliding window 20/min).
  • Error Handling: Foutmeldingen volgen de RFC 9457 ProblemDetails standaard.

Frontend Development (CMS Admin UI)

De frontend is een Vite + React 19 + TypeScript single-page application in de map frontend/. Hij gebruikt TanStack Router, Tailwind v4 (hoofdkleur #ac0000) met shadcn/ui-stijl componenten, react-i18next (NL/EN), en MSW voor mocking in tests.

Vereisten

  • Node.js 20+ (getest met v24)
  • pnpm 9+ (getest met v11)

Snel starten

cd frontend
pnpm install
pnpm dev

De dev-server draait op http://localhost:5173.

Configuratie

De frontend leest de API-basis-URL uit een environment-variabele (zie frontend/.env.example):

VITE_API_BASE_URL=http://localhost:5000

Kopieer .env.example naar .env.local en pas de waarde aan indien nodig. Optioneel kan met VITE_ENABLE_MSW=true de MSW-mockbackend in de browser worden ingeschakeld voor frontend-ontwikkeling zonder draaiende API.

Vereiste backend

De app verwacht de .NET API (Unit 0) draaiend op de geconfigureerde origin met:

  • CORS die de frontend-origin (http://localhost:5173) toestaat met credentials.
  • De httpOnly refreshToken cookie op pad /api/v1/auth (silent refresh bij opstarten).
  • RFC 9457 ProblemDetails foutmeldingen.

Let op: de API-poort in .env.example (5000) moet overeenkomen met de werkelijke API-poort en de Cors:AllowedOrigins configuratie van de backend.

Scripts

pnpm dev            # ontwikkelserver (HMR)
pnpm build          # type-check (tsc) + productie-build
pnpm preview        # productie-build lokaal bekijken
pnpm test           # unit/integratietests (Vitest + Testing Library + MSW)
pnpm test:coverage  # tests met coverage-rapport
pnpm lint           # ESLint
pnpm format         # Prettier (4-space indent)

Database Migraties

Alle database commando's moeten worden uitgevoerd vanaf de root van de projectmap.

Nieuwe migratie toevoegen

Wanneer je wijzigingen aanbrengt in de modellen (in SlpModularCms.Core):

dotnet ef migrations add <NaamVanDeMigratie> --project src\SlpModularCms.Core --startup-project src\SlpModularCms.Api

Database bijwerken

Om de migraties toe te passen op de database:

dotnet ef database update --project src\SlpModularCms.Core --startup-project src\SlpModularCms.Api

Per-module migraties

Sommige modules (SlpModularCms.Modules.Master, SlpModularCms.Modules.Availability) hebben een eigen DbContext met eigen migraties, los van SlpModularCms.Core. Deze worden automatisch toegepast bij het opstarten van de applicatie (via Database.Migrate() in de module's UseModule-methode), maar een nieuwe migratie genereren doe je expliciet per project:

dotnet ef migrations add <NaamVanDeMigratie> --project src\SlpModularCms.Modules.Master --startup-project src\SlpModularCms.Api
dotnet ef migrations add <NaamVanDeMigratie> --project src\SlpModularCms.Modules.Availability --startup-project src\SlpModularCms.Api --context AvailabilityDbContext

Let op: voor SlpModularCms.Modules.Availability is --context AvailabilityDbContext verplicht, omdat de API-startup-project meerdere DbContext-typen samenvoegt en de EF CLI anders niet kan bepalen welke bedoeld wordt.

Nieuwe Module Toevoegen

Het systeem is ontworpen om eenvoudig uitgebreid te worden met nieuwe functionele modules. Volg deze stappen om een nieuwe module toe te voegen:

1. Project aanmaken

Maak een nieuw .NET 10 Class Library project aan in de src/ map. Gebruik de naamconventie SlpModularCms.Modules.<Naam>.

dotnet new classlib -n SlpModularCms.Modules.MijnNieuweModule -o src\SlpModularCms.Modules.MijnNieuweModule -f net10.0

2. Referenties toevoegen

Voeg de benodigde referentie naar Core toe en voeg het project toe aan de solution:

dotnet add src\SlpModularCms.Modules.MijnNieuweModule reference src\SlpModularCms.Core
dotnet sln SlpModularCms.sln add src\SlpModularCms.Modules.MijnNieuweModule

3. IModule implementeren

Maak een class aan die de IModule interface implementeert:

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using SlpModularCms.Core.Modules;

namespace SlpModularCms.Modules.MijnNieuweModule;

public class MijnNieuweModule : IModule
{
    public string Name => "MijnNieuweModule";
    public string Version => "1.0.0";

    public void RegisterServices(IServiceCollection services)
    {
        // Registreer hier module-specifieke services
    }

    public void UseModule(IApplicationBuilder app)
    {
        // Configureer hier middleware of andere pipeline zaken
    }
}

4. Registreren in de API

Om ervoor te zorgen dat de module tijdens ontwikkeling wordt meegenomen in de build-output van de API (zodat de ModuleOrchestrator de DLL kan vinden), voeg je een referentie toe aan het API project:

dotnet add src\SlpModularCms.Api reference src\SlpModularCms.Modules.MijnNieuweModule

De ModuleOrchestrator zal de module nu automatisch ontdekken en laden bij het opstarten.

Master CMS Module

De SlpModularCms.Modules.Master module laat een Owner op één "Master"-CMS de beschikbaarheid van andere ("slave") CMS-instanties centraal beheren. Elke slave die de SlpModularCms.Modules.Availability-module draait, respecteert een master-gecontroleerde aan/uit-status naast zijn eigen lokale beschikbaarheidsschakelaar.

Architectuur

  • Master (SlpModularCms.Modules.Master): eigen MasterDbContext met de CmsInstance-entiteit (URL, versleutelde API key, status). Bevat CmsInstanceController (/CmsInstances, Owner-only), SlaveApiClient (uitgaande HTTP-calls naar slaves) en IntegrityCheckBackgroundService (periodieke reconciliatie, standaard elk uur).
  • Slave-extensie (SlpModularCms.Modules.Availability): eigen MasterRegistration-entiteit, MasterController (interne endpoints onder /api/v1/master/*, buiten de beschikbaarheids-gate om) en een uitgebreide AvailabilityMiddleware die zowel de lokale als de master-gate evalueert.

Registratie- en statusflow

  1. Owner voegt op de Master /cms-pagina een slave toe met diens URL.
  2. De Master genereert een API key, versleutelt deze (Data Protection) en slaat hem op bij de CmsInstance.
  3. De Master pusht de registratie naar de slave: POST /api/v1/master/register met header X-Master-Api-Key.
  4. Zet de Owner de status van een slave om (Available / NotAvailable / Inactive), dan pusht de Master dit synchroon door naar de slave.
  5. Fail-open: lukt de push niet, dan wordt de statuswijziging op de Master niet teruggedraaid — IntegrityCheckBackgroundService haalt de reconciliatie in tijdens de volgende cyclus (MasterModuleOptions.IntegrityCheckIntervalMinutes). Een slave die herstart voordat de Master opnieuw pusht, staat standaard weer open (_masterIsAvailable = true bij opstarten) — er is bewust geen TTL op de laatst bekende status.

Configuratie

Nieuwe sectie MasterModule in appsettings.json (zie ook appsettings.Development.json):

"MasterModule": {
  "IntegrityCheckIntervalMinutes": 60,
  "HttpTimeoutSeconds": 10,
  "MasterUrl": "https://jouw-master-domein"
}
  • MasterUrl is de publieke URL van déze master-instantie, gebruikt door IntegrityCheckBackgroundService (buiten een HTTP-requestcontext heeft de background service geen HttpContext om dit uit af te leiden).

Productie Setup

1. Build & Publish

Compileer de applicatie voor productie:

dotnet publish src/SlpModularCms.Api -c Release -o ./publish

2. Runtime Configuratie

In productie moeten gevoelige instellingen worden doorgegeven via Environment Variables:

  • ConnectionStrings__DefaultConnection
  • JwtSettings__Secret
  • JwtSettings__Issuer
  • JwtSettings__Audience
  • MasterModule__MasterUrl — publieke URL van deze master-instantie (alleen relevant als de Master CMS Module actief is)

2a. Data Protection key ring (Master CMS Module)

De API keys van geregistreerde slaves worden versleuteld opgeslagen met ASP.NET Core Data Protection, standaard met een bestandssysteem-key-store. Voor gecontaineriseerde of multi-instance deployments moet een persistente key ring geconfigureerd worden (bijv. PersistKeysToDbContext of PersistKeysToAzureBlobStorage). Zonder dit worden alle opgeslagen API keys onleesbaar zodra de container herstart, waardoor master↔slave-communicatie stopt totdat instanties opnieuw worden toegevoegd.

3. Database

Zorg dat de doeltabel bestaat en de migraties zijn uitgevoerd. In productie kan dit via een CI/CD pipeline worden afgehandeld met dotnet ef migrations script of door de applicatie bij startup migraties te laten draaien (indien geconfigureerd).

S
Description
No description provided
Readme
3.3 MiB
Languages
C# 57.4%
TypeScript 40.9%
JavaScript 1.1%
CSS 0.3%
HTML 0.3%