# 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 |