# Application Design Plan — SlpSoftware Production API Dit plan beschrijft hoe de high-level applicatie-ontwerp-artefacten voor deze feature worden opgesteld. Beantwoord eerst de vragen hieronder; na jouw goedkeuring wordt het plan uitgevoerd. Context die ik al heb geverifieerd in de code (niet aangenomen): - `ModuleOrchestrator` (`SlpModularCms.Core/Hosting/ModuleOrchestrator.cs`) ontdekt modules **dynamisch** door `.dll`-bestanden op schijf te scannen — er is nergens een expliciete "welke modules host ik"-lijst in `Program.cs`. Dat betekent: welke modules een Client-project host, wordt volledig bepaald door welke Module-projecten dat `.csproj` referenceert, niet door code in `Program.cs` zelf. - `SlpModularCms.Api/Program.cs` bevat, op de bootstrap-regels na (`WebApplication.CreateBuilder`, `appsettings.local.json`), **geen enkele project-specifieke branch** — alles is generiek/config-gedreven. Dat maakt een verregaande extractie (FR-3) haalbaar. - `SlpModularCms.Modules.Master` volgt het patroon: `Controllers/` → `Services/` (`I{X}Service`/`{X}Service`) → `Repositories/` (`I{X}Repository`/`{X}Repository`) → `Data/{X}DbContext.cs`, plus `Models/` voor DTO's/requests en `{Module}Module.cs` (`IModule`-implementatie). ## Uitvoeringschecklist - [x] Stap A — `components.md`: componenten identificeren (CmsHost-extractie, Offerings-module met sub-componenten) met verantwoordelijkheden - [x] Stap B — `component-methods.md`: methode-signaturen per component (geen gedetailleerde business rules — dat komt in Functional Design) - [x] Stap C — `services.md`: servicedefinities en orkestratiepatronen (o.a. featured-exclusiviteit, reorder-logica uit de user stories) - [x] Stap D — `component-dependency.md`: afhankelijkheidsmatrix + datastroom (Core ↔ Api ↔ Api.SlpSoftware ↔ Offerings) - [x] Stap E — `application-design.md`: consolidatie van bovenstaande in één document - [x] Stap F — Consistentiecontrole: komt het ontwerp overeen met requirements.md (FR-1..FR-9) en stories.md (US-01..US-12)? --- ## Vragen ### Vraag 1 — Vorm van de `CmsHost`-extractie (FR-3) `Api/Program.cs` bevat, buiten de bootstrap-regels, geen project-specifieke logica. Dat maakt twee uitersten mogelijk voor de extractie. Hoe ver moet de extractie naar `SlpModularCms.Core` gaan? A) **Eén volledig entrypoint** — `CmsHost.RunAsync(string[] args)` bevat de hele samenstelling (services + pipeline + `app.Run()`); beide `Program.cs`-bestanden worden dan letterlijk een paar regels (`return CmsHost.RunAsync(args);` + evt. bootstrap-overrides). Minimaliseert duplicatie/drift maximaal, maar geeft een individueel project weinig ruimte om ooit af te wijken zonder de gedeelde methode te wijzigen. B) **Twee gedeelde methodes** — `CmsHost.ConfigureServices(WebApplicationBuilder)` en `CmsHost.ConfigurePipeline(WebApplication)`, die elk project vanuit zijn eigen dunne `Program.cs` aanroept (zoals vandaag al met `AddCoreInfrastructure` etc. gebeurt, maar dan als één samengestelde aanroep per fase). Iets meer code per project, maar elk project behoudt een zichtbaar `Program.cs` waarin het makkelijk is om ooit één stap toe te voegen/over te slaan zonder `Core` te wijzigen. X) Anders (beschrijf hieronder na de [Answer]:-tag) [Answer]: B ### Vraag 2 — Architectuurpatroon voor de Offerings-module `Modules.Master` gebruikt een Repository+Service-laag (`ICmsInstanceRepository` → `ICmsInstanceService` → Controller). Bij Requirements Analysis heb je de Property-Based Testing-extensie overgeslagen met als reden dat dit een eenvoudige CRUD-achtige module is zonder significante bedrijfslogica. Moet de Offerings-module hetzelfde Repository+Service-patroon volgen (consistent met Master), of is dat voor deze module onnodige indirectie? A) Repository+Service (consistent met Master) — `IOfferingRepository` + `IOfferingsService`, ook al is de module zelf simpel B) Alleen Service, geen Repository — `IOfferingsService` praat direct met `OfferingsDbContext` (minder indirectie voor een module die je zelf als eenvoudige CRUD hebt gekarakteriseerd) X) Anders (beschrijf hieronder na de [Answer]:-tag) [Answer]: A ### Vraag 3 — Controllersplitsing publiek vs. admin Requirements.md scheidt al duidelijk het publieke `GET /api/v1/offerings` (FR-6, anoniem) van de admin-CRUD (FR-7, `AdminOnly`). Moet dit ook twee aparte controllers worden, of één controller met gemengde autorisatie per actie? A) Twee controllers — `OfferingsController` (publiek, alleen `GET`) en `OfferingsAdminController` (CRUD + reorder, `AdminOnly`) — duidelijke scheiding, moeilijker om per ongeluk een admin-actie anoniem te laten B) Eén controller — `OfferingsController` met `[AllowAnonymous]` op de publieke `GET` en `[Authorize(Policy = "AdminOnly")]` op de rest X) Anders (beschrijf hieronder na de [Answer]:-tag) [Answer]: B ### Vraag 4 — Id-strategie voor nieuw aangemaakte offerings De drie bestaande referentiewaarden (FR-8) gebruiken leesbare slugs (`pakket_01`, `pakket_02`, `pakket_03`). Het publieke contract (FR-6) verwacht een `string`-veld `id`, dus zowel een GUID als een handmatige slug is technisch mogelijk. Hoe moet de `Id` van een **nieuw** aangemaakte offering tot stand komen? A) Automatisch gegenereerd (GUID as string) — simpel, geen validatie op uniekheid/formaat nodig, consistent met andere entiteiten in dit systeem (bijv. `CmsInstance.Id`) B) Door de CMS Administrator zelf opgegeven als leesbare slug — consistent met de bestaande `pakket_XX`-stijl, vereist wel validatie (uniek, toegestane tekens) X) Anders (beschrijf hieronder na de [Answer]:-tag) [Answer]: A ### Vraag 5 — Verwijdersemantiek Requirements.md signaleert een nog open punt bij SECURITY-13 (audit-trail op content-mutaties). US-06/US-07 beschrijven "verwijderen" zonder te specificeren of dat een echte database-delete is of een soft-delete. Hoe moet "een offering verwijderen" op databaseniveau werken? A) Hard delete — de rij wordt echt verwijderd uit `OfferingsDbContext`; simpelst, maar draagt niet bij aan het SECURITY-13-openpunt B) Soft delete — een `IsDeleted`/`DeletedAt`-veld, verwijderde offerings worden uit alle queries gefilterd maar blijven in de database staan; simpele, gedeeltelijke invulling van het SECURITY-13-openpunt (geen volledige audit trail, maar wel behoud van de laatste staat vóór verwijdering) X) Anders (beschrijf hieronder na de [Answer]:-tag) [Answer]: B