Initial commit with inital CMS

This commit is contained in:
2026-06-15 17:00:16 +02:00
commit 95d986790e
132 changed files with 7624 additions and 0 deletions
@@ -0,0 +1,353 @@
# User Stories — SlpModularCms.Api
## Overzicht
Dit document bevat alle INVEST-compliant user stories voor SlpModularCms.Api, georganiseerd per feature-domein. Elke story is getagd met het feature-domein en gekoppeld aan de relevante persona('s).
**Formaat per story:**
- Story: "Als [rol] wil ik [actie] zodat [doel]"
- `[Feature: ...]` — feature-domein tag
- `[Personas: ...]` — gekoppelde persona('s)
- Acceptatiecriteria (bullet-stijl of Given/When/Then)
---
## Feature: Authenticatie
### US-AUTH-01: Inloggen met e-mail en wachtwoord
**Story**: Als een geregistreerde gebruiker wil ik kunnen inloggen met mijn e-mailadres en wachtwoord zodat ik toegang krijg tot het systeem.
`[Feature: Authenticatie]` `[Personas: Eigenaar, Beheerder, Gebruiker]`
**Acceptatiecriteria:**
- **Gegeven** een geregistreerde gebruiker met geldig e-mailadres en wachtwoord
**Wanneer** de gebruiker `POST /api/auth/login` aanroept met correcte credentials
**Dan** ontvangt de gebruiker een JWT access token en een refresh token
- **Gegeven** een gebruiker met een ongeldig wachtwoord
**Wanneer** de gebruiker probeert in te loggen
**Dan** ontvangt de gebruiker een `401 Unauthorized` response
- **Gegeven** een niet-bestaand e-mailadres
**Wanneer** de gebruiker probeert in te loggen
**Dan** ontvangt de gebruiker een `401 Unauthorized` response (geen onderscheid voor security)
- Het JWT access token bevat de gebruikersrol als claim
- Het access token heeft een beperkte geldigheidsduur (bijv. 15 minuten)
---
### US-AUTH-02: Access token vernieuwen (refresh token rotation)
**Story**: Als een ingelogde gebruiker wil ik mijn access token kunnen vernieuwen via een refresh token zodat ik ingelogd blijf zonder opnieuw mijn wachtwoord in te voeren.
`[Feature: Authenticatie]` `[Personas: Eigenaar, Beheerder, Gebruiker]`
**Acceptatiecriteria:**
- **Gegeven** een gebruiker met een geldig refresh token
**Wanneer** de gebruiker `POST /api/auth/refresh` aanroept
**Dan** ontvangt de gebruiker een nieuw access token én een nieuw refresh token (rotation)
- Het oude refresh token is na gebruik ongeldig (eenmalig bruikbaar)
- **Gegeven** een al gebruikt of verlopen refresh token
**Wanneer** de gebruiker probeert te refreshen
**Dan** ontvangt de gebruiker een `401 Unauthorized` response
- Bij hergebruik van een al gebruikt refresh token worden alle tokens van de gebruiker ingetrokken (token reuse detection)
---
### US-AUTH-03: Uitloggen
**Story**: Als een ingelogde gebruiker wil ik kunnen uitloggen zodat mijn sessie veilig wordt beëindigd.
`[Feature: Authenticatie]` `[Personas: Eigenaar, Beheerder, Gebruiker]`
**Acceptatiecriteria:**
- **Gegeven** een ingelogde gebruiker
**Wanneer** de gebruiker `POST /api/auth/logout` aanroept
**Dan** wordt het refresh token ingetrokken en is het niet meer bruikbaar
- Na uitloggen geeft het ingetrokken refresh token een `401 Unauthorized` bij gebruik
- Het access token verloopt op zijn eigen geldigheidsduur (stateless JWT)
---
### US-AUTH-04: Wachtwoord instellen via uitnodigingslink
**Story**: Als een uitgenodigde gebruiker wil ik mijn wachtwoord instellen via de uitnodigingslink die ik per e-mail heb ontvangen zodat ik toegang krijg tot het systeem zonder dat een beheerder een wachtwoord voor mij instelt.
`[Feature: Authenticatie]` `[Personas: Eigenaar, Beheerder, Gebruiker]`
**Acceptatiecriteria:**
- **Gegeven** een uitnodigingstoken dat per e-mail is verstuurd
**Wanneer** de gebruiker `POST /api/auth/accept-invitation` aanroept met het token en een nieuw wachtwoord
**Dan** wordt het wachtwoord ingesteld en is de gebruiker actief
- Het uitnodigingstoken is eenmalig bruikbaar en heeft een vervaldatum
- **Gegeven** een verlopen of al gebruikt uitnodigingstoken
**Wanneer** de gebruiker probeert het wachtwoord in te stellen
**Dan** ontvangt de gebruiker een `400 Bad Request` met een duidelijke foutmelding
- Het wachtwoord moet voldoen aan de wachtwoordvereisten (minimale lengte, complexiteit)
- Na het instellen van het wachtwoord kan de gebruiker direct inloggen
---
## Feature: Gebruikersbeheer
### US-USER-01: Gebruiker uitnodigen via e-mail
**Story**: Als Eigenaar of Beheerder wil ik een nieuwe gebruiker kunnen uitnodigen via e-mail zodat de gebruiker zelf zijn wachtwoord kan instellen en toegang krijgt tot het systeem.
`[Feature: Gebruikersbeheer]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar of Beheerder
**Wanneer** `POST /api/users/invite` wordt aangeroepen met naam, e-mailadres en rol
**Dan** wordt een uitnodigingslink per e-mail verstuurd en wordt de gebruiker aangemaakt met status "Uitgenodigd"
- De uitnodigingslink bevat een uniek, tijdelijk token
- **Gegeven** een e-mailadres dat al in gebruik is
**Wanneer** een uitnodiging wordt verstuurd
**Dan** ontvangt de aanroeper een `409 Conflict` response
- Een Beheerder kan alleen de rol "Gebruiker" of "Beheerder" toewijzen (niet "Eigenaar")
- Een Eigenaar kan alle rollen toewijzen behalve een tweede Eigenaar via deze route (zie US-AUTHZ-02)
- Niet-geauthenticeerde gebruikers ontvangen `401 Unauthorized`
- Een Gebruiker die dit endpoint aanroept ontvangt `403 Forbidden`
---
### US-USER-02: Gebruikersgegevens bewerken
**Story**: Als Eigenaar of Beheerder wil ik de gegevens van een gebruiker kunnen bewerken zodat ik naam, e-mail of rol kan aanpassen bij functiewijzigingen.
`[Feature: Gebruikersbeheer]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar of Beheerder
**Wanneer** `PUT /api/users/{id}` wordt aangeroepen met gewijzigde gegevens
**Dan** worden de gegevens bijgewerkt en wordt `200 OK` teruggegeven
- Een Beheerder kan de rol van een Eigenaar niet wijzigen
- Een Beheerder kan geen andere Beheerder degraderen naar Gebruiker (alleen Eigenaar mag dit)
- **Gegeven** een niet-bestaande gebruiker-ID
**Dan** ontvangt de aanroeper `404 Not Found`
- Een Gebruiker die dit endpoint aanroept ontvangt `403 Forbidden`
---
### US-USER-03: Gebruiker verwijderen
**Story**: Als Eigenaar of Beheerder wil ik een gebruiker kunnen verwijderen zodat voormalige medewerkers geen toegang meer hebben tot het systeem.
`[Feature: Gebruikersbeheer]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar
**Wanneer** `DELETE /api/users/{id}` wordt aangeroepen voor een Beheerder of Gebruiker
**Dan** wordt de gebruiker verwijderd en ontvangt de aanroeper `204 No Content`
- Een Eigenaar kan niet worden verwijderd (ook niet door een andere Eigenaar via dit endpoint)
- Een Beheerder kan alleen Gebruikers verwijderen, niet andere Beheerders of Eigenaars
- **Gegeven** een Beheerder die probeert een andere Beheerder te verwijderen
**Dan** ontvangt de aanroeper `403 Forbidden`
- Alle actieve tokens van de verwijderde gebruiker worden ingetrokken
---
### US-USER-04: Lijst van gebruikers opvragen
**Story**: Als Eigenaar of Beheerder wil ik een overzicht van alle gebruikers kunnen opvragen zodat ik inzicht heb in wie toegang heeft tot het systeem.
`[Feature: Gebruikersbeheer]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar of Beheerder
**Wanneer** `GET /api/users` wordt aangeroepen
**Dan** ontvangt de aanroeper een lijst van alle gebruikers met naam, e-mail, rol en status
- De lijst bevat geen wachtwoorden of token-informatie
- Een Gebruiker die dit endpoint aanroept ontvangt `403 Forbidden`
---
### US-USER-05: Eigen profiel bewerken
**Story**: Als ingelogde gebruiker wil ik mijn eigen profielgegevens kunnen bewerken zodat mijn naam en wachtwoord up-to-date zijn.
`[Feature: Gebruikersbeheer]` `[Personas: Eigenaar, Beheerder, Gebruiker]`
**Acceptatiecriteria:**
- **Gegeven** een ingelogde gebruiker
**Wanneer** `PUT /api/users/me` wordt aangeroepen met gewijzigde naam of wachtwoord
**Dan** worden de gegevens bijgewerkt en wordt `200 OK` teruggegeven
- Een gebruiker kan zijn eigen e-mailadres **niet** wijzigen via dit endpoint
- Een gebruiker kan zijn eigen rol **niet** wijzigen via dit endpoint
- Bij wachtwoordwijziging moet het huidige wachtwoord worden meegegeven ter verificatie
- Het nieuwe wachtwoord moet voldoen aan de wachtwoordvereisten
---
## Feature: Autorisatie
### US-AUTHZ-01: Rol toewijzen aan gebruiker
**Story**: Als Eigenaar of Beheerder wil ik de rol van een gebruiker kunnen wijzigen zodat ik bevoegdheden kan aanpassen bij functiewijzigingen.
`[Feature: Autorisatie]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar
**Wanneer** `PATCH /api/users/{id}/role` wordt aangeroepen met een nieuwe rol
**Dan** wordt de rol bijgewerkt voor alle rollen (Beheerder, Gebruiker)
- Een Beheerder kan alleen de rol "Gebruiker" toewijzen aan een bestaande Gebruiker
- Een Beheerder kan **geen** Eigenaar-rol toewijzen of afnemen
- Een Beheerder kan **geen** andere Beheerder degraderen
- **Gegeven** een ongeldige rolwaarde
**Dan** ontvangt de aanroeper `400 Bad Request`
---
### US-AUTHZ-02: Eigenaarschap overdragen
**Story**: Als Eigenaar wil ik eigenaarschap kunnen overdragen aan een andere gebruiker zodat de organisatie een nieuwe primaire beheerder kan aanwijzen.
`[Feature: Autorisatie]` `[Personas: Eigenaar]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar
**Wanneer** `POST /api/users/{id}/make-owner` wordt aangeroepen
**Dan** krijgt de doelgebruiker de Eigenaar-rol en behoudt de huidige Eigenaar ook zijn Eigenaar-rol
- Het systeem kan meerdere Eigenaars hebben
- De doelgebruiker moet een bestaande actieve gebruiker zijn
- Een Beheerder die dit endpoint aanroept ontvangt `403 Forbidden`
- **Gegeven** een niet-bestaande gebruiker-ID
**Dan** ontvangt de aanroeper `404 Not Found`
---
### US-AUTHZ-03: Hiërarchische bevoegdheidsgrenzen handhaven
**Story**: Als systeembeheerder wil ik dat het systeem automatisch hiërarchische bevoegdheidsgrenzen handhaaft zodat gebruikers nooit meer rechten kunnen toewijzen dan ze zelf hebben.
`[Feature: Autorisatie]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- Een Beheerder kan geen acties uitvoeren op gebruikers met een hogere of gelijke rol (Eigenaar, andere Beheerder)
- Een Gebruiker kan geen beheersacties uitvoeren
- Pogingen om boven de eigen bevoegdheid te handelen resulteren in `403 Forbidden`
- De rolhiërarchie is: Eigenaar > Beheerder > Gebruiker
---
## Feature: Setup
### US-SETUP-01: Eerste Eigenaar aanmaken via seed script (development)
**Story**: Als ontwikkelaar wil ik een seed script kunnen uitvoeren zodat er automatisch een eerste Eigenaar-account wordt aangemaakt in de development-omgeving.
`[Feature: Setup]` `[Personas: Eigenaar]`
**Acceptatiecriteria:**
- Het seed script maakt een Eigenaar-account aan als er nog geen Eigenaar bestaat
- De seed-gegevens (e-mail, wachtwoord) zijn configureerbaar via omgevingsvariabelen of appsettings
- Het script is idempotent: meerdere uitvoeringen maken geen duplicaten
- Het script is alleen beschikbaar/uitvoerbaar in de development-omgeving
---
### US-SETUP-02: Eerste Eigenaar aanmaken via setup-endpoint (productie)
**Story**: Als systeembeheerder wil ik een beveiligd setup-endpoint kunnen aanroepen zodat ik de eerste Eigenaar kan aanmaken bij de initiële productie-installatie.
`[Feature: Setup]` `[Personas: Eigenaar]`
**Acceptatiecriteria:**
- **Gegeven** een systeem zonder bestaande Eigenaar
**Wanneer** `POST /api/setup/initialize` wordt aangeroepen met naam, e-mail en wachtwoord
**Dan** wordt de eerste Eigenaar aangemaakt en wordt `201 Created` teruggegeven
- **Gegeven** een systeem waar al een Eigenaar bestaat
**Wanneer** het setup-endpoint wordt aangeroepen
**Dan** ontvangt de aanroeper `409 Conflict` (setup al voltooid)
- Het endpoint is na de eerste succesvolle aanroep permanent uitgeschakeld
- Het endpoint vereist geen authenticatie (het systeem heeft immers nog geen gebruikers)
---
## Feature: Modules
### US-MOD-01: Module laden bij applicatiestart
**Story**: Als systeembeheerder wil ik dat modules automatisch worden geladen bij het opstarten van de applicatie zodat de geconfigureerde functionaliteit direct beschikbaar is.
`[Feature: Modules]` `[Personas: Eigenaar]`
**Acceptatiecriteria:**
- Bij applicatiestart worden alle geconfigureerde modules automatisch geladen
- Modules worden geregistreerd als aparte class libraries (.csproj)
- Als een module niet geladen kan worden, wordt dit gelogd en start de applicatie zonder die module
- De applicatie start ook als er geen modules zijn geconfigureerd
---
### US-MOD-02: Module uitschakelen
**Story**: Als Eigenaar of Beheerder wil ik een module kunnen uitschakelen zodat de functionaliteit van die module niet meer beschikbaar is voor gebruikers.
`[Feature: Modules]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar of Beheerder
**Wanneer** `POST /api/modules/{moduleId}/disable` wordt aangeroepen
**Dan** is de module uitgeschakeld en zijn de endpoints van die module niet meer bereikbaar
- Uitgeschakelde module-endpoints geven `503 Service Unavailable` of `404 Not Found`
- Een Gebruiker die dit endpoint aanroept ontvangt `403 Forbidden`
- De modulestatus wordt opgeslagen zodat deze na herstart behouden blijft
---
### US-MOD-03: Module-specifieke rechten instellen per Gebruiker
**Story**: Als Eigenaar of Beheerder wil ik module-specifieke rechten kunnen instellen per Gebruiker zodat ik per klant/tenant kan bepalen welke functionaliteit een Gebruiker mag gebruiken.
`[Feature: Modules]` `[Personas: Eigenaar, Beheerder]`
**Acceptatiecriteria:**
- **Gegeven** een Eigenaar of Beheerder
**Wanneer** `PUT /api/users/{id}/module-permissions` wordt aangeroepen met module-rechten
**Dan** worden de module-specifieke rechten opgeslagen voor die gebruiker
- Modules kunnen eigen rechten definiëren die via dit endpoint worden ingesteld
- Een Gebruiker zonder specifiek module-recht heeft standaard geen toegang tot die module-functionaliteit
- Een Gebruiker die dit endpoint aanroept ontvangt `403 Forbidden`
---
## Feature: Beschikbaarheidscontrole
### US-AVAIL-01: Beschikbaarheid controleren via placeholder service
**Story**: Als systeembeheerder wil ik dat het systeem een beschikbaarheidscontrole uitvoert via een placeholder service zodat de architectuur klaar is voor toekomstige integratie met een externe availability-API of master-API.
`[Feature: Beschikbaarheidscontrole]` `[Personas: Eigenaar]`
**Acceptatiecriteria:**
- Het systeem bevat een `IAvailabilityService` interface als placeholder
- De standaard implementatie (`StubAvailabilityService`) retourneert altijd "beschikbaar" (stub)
- De stub-implementatie is vervangbaar door een echte implementatie via dependency injection
- De beschikbaarheidscontrole wordt niet geblokkeerd in de MVP (stub retourneert altijd succes)
- De interface is gedocumenteerd met de verwachte toekomstige contracten
---
## Story Overzicht
| Story ID | Omschrijving | Feature | Personas |
|---|---|---|---|
| US-AUTH-01 | Inloggen met e-mail en wachtwoord | Authenticatie | Eigenaar, Beheerder, Gebruiker |
| US-AUTH-02 | Access token vernieuwen (refresh rotation) | Authenticatie | Eigenaar, Beheerder, Gebruiker |
| US-AUTH-03 | Uitloggen | Authenticatie | Eigenaar, Beheerder, Gebruiker |
| US-AUTH-04 | Wachtwoord instellen via uitnodigingslink | Authenticatie | Eigenaar, Beheerder, Gebruiker |
| US-USER-01 | Gebruiker uitnodigen via e-mail | Gebruikersbeheer | Eigenaar, Beheerder |
| US-USER-02 | Gebruikersgegevens bewerken | Gebruikersbeheer | Eigenaar, Beheerder |
| US-USER-03 | Gebruiker verwijderen | Gebruikersbeheer | Eigenaar, Beheerder |
| US-USER-04 | Lijst van gebruikers opvragen | Gebruikersbeheer | Eigenaar, Beheerder |
| US-USER-05 | Eigen profiel bewerken | Gebruikersbeheer | Eigenaar, Beheerder, Gebruiker |
| US-AUTHZ-01 | Rol toewijzen aan gebruiker | Autorisatie | Eigenaar, Beheerder |
| US-AUTHZ-02 | Eigenaarschap overdragen | Autorisatie | Eigenaar |
| US-AUTHZ-03 | Hiërarchische bevoegdheidsgrenzen handhaven | Autorisatie | Eigenaar, Beheerder |
| US-SETUP-01 | Eerste Eigenaar via seed script (dev) | Setup | Eigenaar |
| US-SETUP-02 | Eerste Eigenaar via setup-endpoint (productie) | Setup | Eigenaar |
| US-MOD-01 | Module laden bij applicatiestart | Modules | Eigenaar |
| US-MOD-02 | Module uitschakelen | Modules | Eigenaar, Beheerder |
| US-MOD-03 | Module-specifieke rechten instellen per Gebruiker | Modules | Eigenaar, Beheerder |
| US-AVAIL-01 | Beschikbaarheid controleren via placeholder service | Beschikbaarheidscontrole | Eigenaar |