Performance, beschikbaarheid en fallbackgedrag
22.1 Doel en scope
Dit hoofdstuk beschrijft hoe OefenHub technisch omgaat met performance, beschikbaarheid, degradatie en fallbackgedrag binnen de gekozen middel-zware modulaire monoliet.
De uitgangspunten uit de Software Requirements Specification en architectuur blijven leidend. Dit hoofdstuk voegt geen nieuwe functionele eisen toe, maar vertaalt bestaande niet-functionele verwachtingen naar technische ontwerpkeuzes, meetpunten en implementatieafspraken.
Performance en beschikbaarheid worden niet opgelost door modulegrenzen te doorbreken. Ook onder belasting blijven de basisregels gelden:
OefenHub.Webgebruikt publieke modulecontracten en geen directe DbContext- of entitytoegang.- Module-eigen data blijft eigendom van de module die het bijbehorende schema beheert.
- Readmodels, caching en materialisatie zijn optimalisatielagen en geen bron van waarheid.
- Fallbackgedrag mag nooit autorisatie, privacy, relatiegrenzen of historische brondata omzeilen.
- SignalR, caching, PDF-bestanden en tijdelijke exportbestanden zijn transport- of afgeleide lagen, geen primaire brondata.
22.2 Relatie met andere hoofdstukken binnen het Technisch Ontwerp
| Technisch Ontwerp-hoofdstuk | Relatie met performance en fallback |
|---|---|
| 02 Architectuuroverzicht en solution-opbouw | Bepaalt de modulaire monoliet, projectindeling en runtimecontext. |
| 03 Applicatielagen, projectstructuur en dependency-richting | Bepaalt waar performanceoptimalisatie mag plaatsvinden zonder dependencyregels te schenden. |
| 07 Databaseontwerp, migraties, seeddata en constraints | Bepaalt indexen, querygrenzen, schema-eigenaarschap en soft link/snapshotgedrag. |
| 15 Realtime live meekijken met SignalR | Bepaalt live-updategedrag, reconnect en live-fallback. |
| 16 PDF-export met QuestPDF | Bepaalt PDF-rendering, tijdelijke bestanden en export-fallback. |
| 17 Readmodels, tellers, badges, caching en materialisatie | Bepaalt caching, readmodelactualiteit en tellerfallback. |
| 18 Background jobs, TickerQ en periodieke verwerking | Bepaalt retrybare naverwerking, jobstatussen en periodieke herstelacties. |
| 19 Logging, audit, securitylogging en technische foutafhandeling | Bepaalt correlation, foutregistratie en veilige foutrespons. |
| 20 Security, infrastructuur, secrets en omgevingen | Bepaalt pipeline, headers, rate limiting, secrets en securitygrenzen. |
| 21 Beheerbeleid, monitoring, backup, restore en operatie | Bepaalt operationele monitoring, health checks, incidentafhandeling en herstelprocedures. |
| 23 Teststrategie, acceptatieherleidbaarheid en kwaliteitsgrenzen | Bepaalt loadtests, integratietests en kwaliteitsgrenzen. |
22.3 Performanceprincipes
OefenHub hanteert de volgende technische performanceprincipes:
| Principe | Toelichting |
|---|---|
| Server-side autorisatie eerst | Queries worden altijd server-side gescoped voordat data wordt opgehaald of gepresenteerd. |
| Brondata blijft leidend | Caches, readmodels en badges mogen brondata versnellen, maar niet vervangen. |
| Meetbaar boven impliciet | Performancegrenzen worden gekoppeld aan meetpunten, logging en tests. |
| Geen stille onvolledigheid | Fallback mag een veilige lege toestand tonen, maar geen misleidende nulwaarden. |
| Bounded queries | Overzichten gebruiken paginering, filters en expliciete limieten. |
| Module-eigen optimalisatie | Een module optimaliseert eigen queries, indexes, readmodels en caching. |
| Cross-module compositie via contracts | Samengestelde schermen vragen data via publieke query-services, niet via directe databasejoins over modulegrenzen. |
| Asynchroon waar veilig | Niet-kritieke naverwerking mag via Scheduling/TickerQ verlopen, mits idempotent en beheerbaar. |
| Snel falen waar nodig | Bij ongeldige context, ontbrekende autorisatie of kritieke dependency-fout wordt veilig en duidelijk gefaald. |
22.4 Prestatiecategorieën
Niet iedere functie heeft dezelfde performance-eisen. Het Technisch Ontwerp onderscheidt daarom categorieën.
| Categorie | Voorbeelden | Technische benadering |
|---|---|---|
| Interactieve UI | navigatie, frontpages, overzichten, detailpagina’s | korte requestduur, bounded queries, readmodels waar nuttig |
| Kritieke commands | oefening starten, antwoord verwerken, relatie accepteren, ticket sluiten | transactioneel betrouwbaar, geen zware bijtaken in de requestflow |
| Realtime transport | live meekijken, badges, online-status | kleine payloads, reconnect, bronherstel vanuit database |
| Zware output | PDF-export, grote geschiedenisoverzichten | streaming/tijdelijke output, limieten, eventueel jobmatige verwerking |
| Periodieke verwerking | cleanup, verlopen uitnodigingen, verlopen heropentermijnen | TickerQ, idempotentie, retries, monitoring |
| Beheeranalyse | beheerlogs, history, supportanalyse | paginering, filters, indexen, geen onbeperkte exports in UI |
22.5 Richtwaarden en meetpunten
De V1.0-baseline gebruikt bewuste, lichte performancegrenzen. OefenHub is geen grootschalige 24/7-applicatie en krijgt geen top-tier latency- of beschikbaarheidsdoelen. De grenzen hieronder zijn technische ontwerp- en testwaarden voor een acceptabele gebruikerservaring bij representatieve belasting, niet een externe SLA.
De meting gebruikt waar mogelijk de 95e percentielwaarde (p95) in een representatieve test- of acceptatieomgeving met realistische testdata, een warme applicatie en normale netwerkcondities. Externe identity-providerlatency, browserextensies, lokale apparaatvertraging en internetstoringen vallen buiten deze richtwaarden.
| Onderdeel | Meetpunt | Technische aandacht |
|---|---|---|
| Frontpage laden | requestduur, querytijd, aantal modulecalls | page composition mag geen onbegrensde cross-module cascade worden |
| Oefening starten | commandduur, modulegeneratietijd, databasecommit | vraaggeneratie en runopslag moeten binnen één veilige startflow passen |
| Antwoord bevestigen | verwerkingstijd, commitduur, SignalR-publicatietijd | databasecommit is leidend; SignalR is vervolgtransport |
| Geschiedenisoverzicht | querytijd, paginagrootte, indexgebruik | alleen afgeronde toegestane runs ophalen |
| Resultaatdetail | laadtijd, payloadgrootte, module-renderhulp | payload parsing begrenzen en fouten veilig afhandelen |
| PDF-export | renderduur, bestandsgrootte, geheugengebruik | tijdelijke opslag, time-outs en cleanup verplicht |
| Live meekijken | update-latency, reconnecttijd, stale-state herstel | reconnect haalt actuele voortgang opnieuw uit Practice |
| Badges/tellers | actualiteit, queryduur, cache-hitratio | badges mogen tijdelijk achterlopen, niet brondata wijzigen |
| Jobs | wachttijd, pogingen, foutpercentage | CorrelationId, JobId en failed-status verplicht |
| Login/provisioning | provider-retourduur, interne contextopbouw | providerlogin is pas bruikbaar na interne accountcontrole |
22.5.1 V1.0-performancegrenzen per hoofdflow
De volgende waarden sluiten het open punt over performancegrenzen per hoofdflow af. Zij zijn bedoeld als realistische kwaliteitsgrens voor een kleine tot middelgrote applicatie. Een incidentele overschrijding is geen architectuurincident, maar structurele overschrijding vraagt analyse van query's, indexen, readmodels, caching, paginering of jobmatige verwerking.
| Hoofdflow | V1.0-richtwaarde | Meetpunt | Afbakening |
|---|---|---|---|
| Login afronden en interne gebruikerscontext opbouwen | p95 ≤ 3 s na terugkomst van de identity provider | interne contextresolving, accountstatuscontrole, rolcontext | externe providerlatency valt buiten de meting |
| Normale navigatie, frontpage en dashboardblokken laden | p95 ≤ 4 s | serverrequest plus eerste benodigde page-compositiondata | afbeeldingen, browserrendering en externe netwerkvertraging vallen buiten de servermeting |
| Overzicht openen, filteren of sorteren | p95 ≤ 4 s voor de eerste pagina | querytijd, filtervalidatie, page viewmodel | alleen server-side paginering; geen onbeperkte lijsten |
| Detailpagina openen | p95 ≤ 4 s | querytijd en detail-viewmodel | zware subdetails mogen lazy geladen worden |
| Oefening starten | p95 ≤ 4 s | modulevalidatie, runaanmaak, eerste vraag/context | zeer zware modulegeneratie moet worden begrensd of voorbereid |
| Antwoord bevestigen binnen een oefening | p95 ≤ 2 s | validatie, opslag, score-/voortgangsupdate | SignalR-publicatie is vervolgtransport en mag niet de commit blokkeren |
| Relatie-, autorisatie-, bericht- of ticketactie uitvoeren | p95 ≤ 3 s | commandvalidatie, autorisatie, transactiecommit | niet-kritieke badges/notificaties mogen retrybaar of asynchroon zijn |
| Geschiedenis- of resultaatdetail openen | p95 ≤ 5 s | toegangscontrole, query, payloadvalidatie, viewmodel | grote historie gebruikt filters, paginering en geen volledige dataset in één response |
| Ouder-/voogd- en docentresultaatsamenvattingen laden | p95 ≤ 5 s | readmodel/query, contextscope, aggregatie | samenvattingen mogen cache of readmodel gebruiken, brondata blijft leidend |
| Live meekijkupdate zichtbaar maken | p95 ≤ 3 s na opgeslagen voortgang | publish-latency en clientupdate | reconnectbaseline: 0, 2, 10, 30 en 60 seconden met maximaal 5 automatische pogingen |
| Badges en tellers verversen | maximaal 5 min achterstand | readmodel/cache-actualiteit | badges mogen tijdelijk achterlopen en zijn nooit bron van waarheid |
| PDF-export voor normale resultaatsets | p95 ≤ 60 s | exportmodel ophalen, renderen, tijdelijk bestand registreren | grote of uitzonderlijke exports krijgen veilige fout, limiet of jobmatige verwerking |
| Beheercontent, instellingen, features of modulebeheer opslaan | p95 ≤ 4 s | validatie, autorisatie, audit/history, transactiecommit | preview/rendering mag apart worden uitgevoerd |
| Beheeranalyse, logs en supportoverzichten openen | p95 ≤ 8 s | gefilterde query, paginering, audit-/supportviewmodel | brede analyse vereist filters; onbeperkte exports zijn geen V1.0-uitgangspunt |
| Niet-kritieke achtergrondverwerking zichtbaar verwerken | binnen de geconfigureerde jobinterval, normaal ≤ 15 min | joblatency, failed-status, retrybare side-effects | retrydefaults per jobtype volgen de vastgelegde defaultmatrix in hoofdstuk 18 |
Deze grenzen zijn niet bedoeld om dure high-performance-infrastructuur af te dwingen. Wanneer een flow structureel buiten de richtwaarde valt, wordt eerst gekozen voor bounded queries, indexes, kleinere payloads, paginering, readmodels, caching of asynchrone naverwerking binnen de bestaande modulaire monoliet.
22.6 Performance per applicatielaag
22.6.1 Web/UI-laag
OefenHub.Web is verantwoordelijk voor responsieve UI-compositie, maar niet voor domeinlogica of directe dataoptimalisatie.
Technische regels:
- Componenten vragen data op via publieke query-services of page composition services.
- Pagina’s laden alleen data die voor de eerste weergave nodig is.
- Zware details worden pas opgehaald na expliciete selectie.
- Tabellen en overzichten gebruiken paginering, filtering en server-side sortering.
- UI-loadingstates mogen geen autorisatiebeslissingen maskeren.
- Browserstate mag performance ondersteunen, maar nooit autorisatie, rolcontext of objecttoegang bepalen.
Voorbeeld:
Docentfrontpage
Web/PageComposition
→ Catalog query-service voor niveaus en oefenaanbodsummary
→ Practice query-service voor relevante samenvattingswaarden
→ Support query-service voor actie-indicatoren
Web composeert viewmodel
Web voert geen directe databasequery uit
22.6.2 Modulelaag
Elke module is verantwoordelijk voor performance binnen de eigen brondata en eigen schema.
| Module | Performancefocus |
|---|---|
Identity | snelle interne accountlookup na providerlogin, accountstatuscontrole |
Authorization | contextresolving, policy-evaluatie, objecttoegang zonder brede queries |
Relationships | relatiechecks, uitnodigingstatussen, conflictdetectie |
Catalog | toegankelijke niveaus/categorieën/oefeningen, modulemetadata, configuratievalidatie |
Practice | runstart, antwoordverwerking, geschiedenis, statistieken, snapshotdata |
Communication | mailboxoverzicht, badges, readstate, notificaties |
Support | ticketoverzichten, statusfilters, discussie en history |
LiveMonitoring | livebeschikbaarheid, auditstart/einde, presence-informatie |
Reporting | exportmodel ophalen en PDF-rendering orkestreren |
Scheduling | jobselectie, retries, failed-statussen, dashboarddata |
Admin | beheercontent, templates, instellingen en beheerhistory |
22.6.3 Databaselaag
Performance in de database wordt module-eigen ontworpen.
Technische regels:
- Elke module beheert eigen indexen vanuit eigen querypatronen.
- Cross-module directe joins zijn geen standaard optimalisatiepad.
- Soft links worden querymatig gevalideerd via modulecontracts, niet via willekeurige joins.
- Overzichten lezen bij voorkeur uniforme kolommen/readmodels in plaats van grote payloads.
- JSON/base64-payloads worden niet gebruikt als standaard filter- of sorteerbron.
- Tabellen met verwachte groei krijgen vanaf het ontwerp aandacht voor indexen, paginering en cleanup.
Voorbeelden van groeigevoelige tabellen:
| Domein | Voorbeelden | Performance-aandacht |
|---|---|---|
practice | ExerciseRuns, ExerciseRunProgress, gedeelde oefeningen | filtering op gebruiker, niveau, oefening, status en afrondmoment |
communication | systeemberichten, privéberichten, readstate | mailboxqueries, ongelezenbadges, retentie privéberichten |
support | tickets, discussies, history | statusfilters, actie-indicatoren, beheerzoeken |
live | LiveViewAudit, presence/readmodels | actieve sessies versus historische audit |
scheduling | TickerQ/jobtabellen | pending/failed/selectie op due time en status |
22.7 Beschikbaarheidsprincipes
Beschikbaarheid betekent binnen OefenHub niet dat elke onderliggende functie altijd volledig bruikbaar moet blijven. Het betekent dat de applicatie veilig, voorspelbaar en herstelbaar reageert wanneer een dependency of deelproces faalt.
| Situatie | Gewenst gedrag |
|---|---|
| Identity provider niet beschikbaar | Geen nieuwe login; bestaande sessies blijven alleen bruikbaar zolang zij geldig en veilig zijn. |
| Database niet beschikbaar | Geen bronmutaties; gebruiker krijgt veilige foutafhandeling. |
| SignalR tijdelijk verbroken | Liveweergave probeert reconnect en haalt actuele voortgang opnieuw uit Practice. |
| TickerQ/jobverwerking vertraagd | Jobs blijven persistent pending; beheer kan status zien. |
| PDF-rendering faalt | Geen half bestand aanbieden; fout loggen met correlation-id. |
| Readmodel achterhaald | Indien veilig: bronquery of melding dat gegevens worden bijgewerkt; geen misleidende nulwaarde. |
| Externe of interne notificatie vertraagd | Afhankelijk van workflow: retrybaar of kritieke transactie faalt. |
| Cache niet beschikbaar | Terugvallen op bronquery wanneer dit veilig en performant verantwoord is. |
22.8 Fallbackclassificatie
Fallbackgedrag wordt per functionaliteit geclassificeerd.
| Klasse | Betekenis | Voorbeeld |
|---|---|---|
| Geen fallback | Actie mag niet doorgaan zonder dependency | nieuwe login zonder identity provider |
| Veilige foutrespons | Actie stopt en toont generieke fout | databasecommit faalt |
| Bronfallback | Readmodel/cache faalt, brondata wordt gelezen | beperkte geschiedenisquery vanuit Practice |
| Retrybare naverwerking | Actie is niet direct vereist voor gebruikersuitkomst | cleanup, badge-refresh, niet-kritieke notificatie |
| Kritieke transactie | Meerdere stappen moeten samen slagen | relatie-uitnodiging met primaire systeemberichtingang |
| Degraded view | UI toont beperkte maar correcte informatie | live reconnect toont laatst bekende status met herstelpoging |
| Beheerbare failed-status | Proces stopt veilig en vraagt beheeranalyse | job overschrijdt retrylimiet |
22.9 Geen misleidende fallback
OefenHub mag bij storing of ontbrekende data geen waarden tonen die functioneel onjuist lijken.
Niet toegestaan:
- teller op 0 zetten wanneer query is mislukt
- lege geschiedenis tonen zonder onderscheid tussen “geen resultaten” en “niet beschikbaar”
- oude autorisatiecontext gebruiken omdat actuele controle faalt
- PDF genereren met ontbrekende vraagdetails zonder duidelijke fout
- live meekijken voortzetten alsof de leerling nog actief is terwijl de bronstatus onbekend is
Wel toegestaan:
- veilige foutmelding zonder technische details
- melding dat gegevens tijdelijk niet beschikbaar zijn
- lege toestand wanneer server-side is vastgesteld dat de dataset echt leeg is
- readmodel opnieuw opbouwen vanuit brondata
- failed job zichtbaar maken voor beheer
22.10 Fallback per domein
22.10.1 Identity en login
Login is afhankelijk van de externe identity provider en interne OefenHub-contextopbouw.
| Foutscenario | Gedrag |
|---|---|
| Identity provider onbereikbaar | Nieuwe login of registratie faalt veilig; geen lokale credentialfallback. |
| Providerlogin gelukt, interne provisioning faalt | Geen reguliere sessie; generieke accountfout/contactroute. |
| Interne accountstatus inactief | Toegang blokkeren; geen frontpage of rolcontext. |
| Rolcontext ontbreekt | Beperkte veilige context zonder impliciete rolrechten. |
| Pending invitation reconciliation faalt | Provisioning mag alleen slagen wanneer de noodzakelijke kritieke stappen correct zijn afgehandeld of veilig retrybaar zijn gemaakt. |
22.10.2 Authorization en objecttoegang
Autorisatiefallback is strikt.
- Bij twijfel wordt toegang geweigerd.
- Een niet-beschikbare autorisatiebron leidt niet tot ruimere toegang.
- Oude clientstate wordt niet gebruikt als fallback.
- Een fout in objecttoegangscontrole toont geen gedeeltelijke objectdata.
- Access-denied logging mag geen gevoelige payloads bevatten.
22.10.3 Catalog
Catalogusdata bepaalt wat leerlingen, docenten en beheerders mogen zien of configureren.
Fallbackregels:
- Als modulemetadata niet geladen kan worden, wordt configureren/testen/starten veilig geblokkeerd.
- Als een categorie-/oefeningquery faalt, toont Web geen lege “alles is weg”-toestand zonder foutcontext.
- Historische runweergave gebruikt snapshots vanuit
Practicewanneer actuele catalogusdata niet meer passend is. - Categorie- of modulemigratie mag historische runs niet onleesbaar maken.
22.10.4 Practice
Practice is bron van oefenruns, voortgang, resultaten en geschiedenis.
Fallbackregels:
- Antwoordverwerking moet bronmutatie betrouwbaar committen voordat vervolgtransport plaatsvindt.
- SignalR-fouten mogen antwoordopslag niet terugdraaien wanneer de databasecommit geslaagd is.
- Niet-afgeronde runs blijven herstelbaar zolang de opgeslagen voortgang geldig is.
- Resultaatweergave gebruikt opgeslagen runvelden en payloads; geen clientstate-fallback.
- Geschiedenis toont alleen server-side geautoriseerde afgeronde runs.
22.10.5 Communication
Communicatie kent kritieke en niet-kritieke berichten.
| Communicatiestap | Mogelijk beleid |
|---|---|
| Systeembericht als primaire ingang | kritisch, atomair met bronworkflow waar nodig |
| Badge-update | afgeleid/retrybaar |
| Niet-kritieke notificatie | retrybaar met begrensde pogingen |
| Maildispatch na bronmutatie | bronmutatie blijft leidend; mailfout wordt herleidbaar en eventueel retrybaar gemaakt |
| Privébericht verzenden | command moet slagen of falen; geen half zichtbaar bericht |
| Thread-event | onderdeel van threadmutatie en readstatebeleid |
Tijdens actieve leerling-oefeningen worden badges en notificatie-indicaties visueel uitgesteld, maar server-side readstate en berichten blijven correct opgeslagen.
Mailfouten mogen de gebruiker niet misleiden over de status van de bronactie. Wanneer een domeinactie succesvol is vastgelegd maar e-maildispatch faalt, toont de applicatie de status van de domeinactie volgens de brondata en wordt de mailfout technisch herleidbaar en waar toegestaan retrybaar verwerkt. Wanneer e-mail functioneel kritiek is voor het bereiken van de ontvanger, bepaalt de workflow of de mailaanvraag binnen de kritieke transaction boundary valt.
22.10.6 Support
Ticketflows kunnen meerdere domeinen raken. Per workflow wordt bepaald welke stappen kritiek zijn.
Voorbeelden:
| Workflow | Kritiek | Mogelijk retrybaar |
|---|---|---|
| Nieuwe melding maken | ticket + eerste history/discussie volgens domeinregel | systeembericht wanneer niet primaire ingang of veilig retrybaar gemaakt |
| Aanvullende informatie vragen | statuswijziging + extern bericht wanneer dit de actie bepaalt | badge/readmodel |
| Oplossing plaatsen | closure + status/history | notificatie als niet de enige ingang is |
| Doorzetten naar docent | supportsluiting + forwardregistratie + noodzakelijke communicatie volgens workflowdefinitie | aanvullende badges/readmodels |
22.10.7 LiveMonitoring en SignalR
Live meekijken moet herstellen vanuit brondata.
Fallbackregels:
- SignalR reconnect haalt actuele voortgang opnieuw op via
Practice. - Stale clientstate wordt niet als bron gebruikt.
- Bij reconnect-falen eindigt de liveweergave veilig en wordt
LiveViewAuditwaar nodig afgesloten. - Browse-modus is lokale UI-state en mag livebrondata niet wijzigen.
- Online-status is afgeleid en mag niet als autorisatiebewijs gelden.
22.10.8 Reporting en PDF
PDF-export mag geen half of onjuist document aanbieden.
Fallbackregels:
- Export gebruikt een server-side geautoriseerd exportmodel.
- Tijdelijke bestanden worden pas aangeboden na succesvolle render.
- Bij renderfout wordt geen gedeeltelijk PDF-bestand aangeboden.
- Module-specifieke rendering mag fallbacktekst leveren voor bekende veilige representaties, maar niet stilzwijgend inhoud weglaten.
- Oude tijdelijke bestanden zijn niet de bron; download wordt opnieuw opgebouwd uit databasegegevens en snapshots.
22.10.9 Scheduling
Jobs zijn persistent en beheerbaar.
Fallbackregels:
- Een app-herstart mag pending jobs niet verliezen.
- Retries zijn begrensd per jobtype.
- Na overschrijding van retrylimiet eindigt de job in een failed-status.
- Failed jobs zijn zichtbaar voor interne beheeranalyse.
- Domeinacties binnen jobs moeten idempotent zijn of expliciet beschermd tegen dubbele uitvoering.
- Multi-domain jobs leggen per jobtype vast of atomaire uitvoering, compensatie of failed-status nodig is.
22.11 Time-outs en limieten
Time-outs voorkomen dat één zware actie de applicatie onnodig blokkeert. De waarden hieronder zijn V1.0-bovengrenzen voor implementatie en testinrichting; zij vervangen geen functionele validatie of autorisatiecontrole.
| Onderdeel | Technische regel | V1.0-grens |
|---|---|---|
| HTTP-requests | Commands blijven bounded; zware naverwerking waar mogelijk buiten requestflow. | normale interactieve request-time-out ≤ 30 s |
| Databasequeries | Overzichten gebruiken limieten, paginering en server-side filters. | querycommand-time-out ≤ 30 s; streefwaarde per hoofdflow volgens 22.5.1 |
| Overzichtspaginering | Eerste weergave gebruikt server-side paginering. | standaard 25 regels, configureerbaar tot maximaal 100 regels per pagina |
| Zoek-/filtervelden | Filteren gebeurt server-side en bounded. | minimale debounce of expliciete zoekactie; geen query per toetsaanslag zonder begrenzing |
| PDF-export | Renderduur en bestandsgrootte krijgen technische limieten. | normale export p95 ≤ 60 s; absolute requestgrens ≤ 120 s; grotere exports beperken of jobmatig verwerken |
| SignalR | Reconnectpogingen zijn begrensd; daarna veilige beëindiging. | update p95 ≤ 3 s; reconnectbaseline: 0, 2, 10, 30 en 60 seconden; daarna veilige verbroken status |
| Jobs | Per jobtype retry- en executionlimieten vastleggen. | niet-kritieke side-effects normaal binnen 15 min zichtbaar of failed beheerbaar |
| Rich text sanitizing | Maximale berichtgrootte en verwerkingslimieten toepassen. | concrete tekstlengtes per veld in validatie/configuratie vastleggen |
| Payload parsing | JSON/base64-payloads valideren op grootte, versie en vorm. | payloadgrootte per module expliciet begrenzen; geen onbeperkte parsing in requestflow |
Limieten mogen per module strenger worden gemaakt wanneer dat functioneel of technisch nodig is. Verruiming boven deze baseline vereist een bewuste ontwerp- of implementatiekeuze met aandacht voor memorygebruik, databasebelasting, logging en gebruikersfeedback.
22.12 Capaciteit en schaalbaarheid binnen fase 1
OefenHub schaalt in de eerste baseline primair als één deploybare applicatie met één database. De modulegrenzen zijn bedoeld om onderhoudbaarheid en toekomstige schaalopties te verbeteren, niet om in fase 1 al microservices te introduceren.
Schaalprincipes:
- Optimaliseer eerst queries, indexen, readmodels en caching binnen de monoliet.
- Houd payloads klein bij realtime updates.
- Maak zware output tijdelijk en cleanupbaar.
- Gebruik module-eigen readmodels voor veelgebruikte overzichten.
- Gebruik Scheduling voor periodieke of retrybare verwerking.
- Monitor groeigevoelige tabellen en querypatronen vanaf het begin.
Geen fase-1-uitgangspunt:
- aparte databases per module
- aparte databasegebruikers per module
- RabbitMQ of externe message broker
- microservices
- publieke mobiele API
22.13 Caching en materialisatie
Caching wordt voorzichtig toegepast omdat autorisatie- en contextgrenzen sterk zijn.
| Cachevorm | Gebruik | Voorwaarde |
|---|---|---|
| Request-scope cache | hergebruik binnen één request | geen autorisatieverbreding |
| Memory cache | stabiele referentiedata of korte tellerwaarden | korte TTL en contextveilige key |
| Materialized readmodel | zware overzichten/tellers | module-eigenaarschap en rebuildpad |
| Browser cache/storage | toegankelijkheidsweergave of UI-voorkeuren | geen persoons-, rol- of autorisatiedata |
| Tijdelijke bestandsopslag | PDF/exportoutput | buiten webroot, cleanup en autorisatie bij download |
Cachekeys moeten minimaal rekening houden met gebruiker, rolcontext, objectscope en relevante filters wanneer data contextgevoelig is.
De initiële materialisatiekandidaten staan in hoofdstuk 17. Performanceproblemen worden in de eerste baseline eerst opgelost met indexing, queryscoping, cache-inrichting of de daar genoemde materialisaties voordat modulegrenzen worden doorbroken of een nieuw readmodelproject wordt geïntroduceerd.
22.14 Degradatie van UI
De UI mag functies tijdelijk beperken wanneer onderliggende data of services niet beschikbaar zijn.
Voorbeelden:
| UI-onderdeel | Degradatiegedrag |
|---|---|
| Frontpageblok | blok toont veilige fout/“tijdelijk niet beschikbaar” in plaats van misleidende nulwaarde |
| Badge | badge kan tijdelijk verborgen of verouderd zijn, maar readstate blijft server-side leidend |
| Live meekijken | reconnect of veilige beëindiging met melding |
| PDF-knop | uitgeschakeld of foutrespons wanneer exportbron niet beschikbaar is |
| Beheer-dashboard | failed-job/status toont technische beheerinformatie zonder gevoelige payloads |
| Geschiedenisfilter | ongeldige of niet-beschikbare filters leiden tot veilige fout of lege gevalideerde set |
22.15 Health checks en monitoringinput
Hoofdstuk 21 beschrijft operatie en monitoring. Voor performance en beschikbaarheid levert hoofdstuk 22 de technische meetobjecten.
Minimaal te monitoren:
| Onderdeel | Signaal |
|---|---|
| Webhost | requestduur, foutpercentages, rate limiting hits |
| Database | connectiviteit, queryduur, deadlocks/time-outs, migratiestatus |
| Identity provider | login errors, provider latency, provisioning failures |
| SignalR | connection count, reconnects, disconnects, hub errors |
| Scheduling | pending jobs, failed jobs, retry counts, job latency |
| PDF-export | renderduur, foutpercentage, bestandsgrootte, cleanupresultaat |
| Readmodels | rebuildstatus, stale count, fallback naar bronquery |
| Security | access denied spikes, verdachte patronen, CSRF/rate-limit events |
Alle relevante signalen gebruiken correlation-id’s waar zij voortkomen uit een request, command of jobflow.
22.16 Logging bij performance- en fallbackscenario’s
Performance- en fallbacklogging moet analyse mogelijk maken zonder gevoelige data te lekken.
Logvelden:
CorrelationId
UserId indien toegestaan
RoleContext indien relevant
ModuleName
OperationName
ObjectType
ObjectId indien veilig
DurationMs
FallbackType
RetryAttempt
JobId indien relevant
ResultStatus
ErrorCode
Niet loggen:
wachtwoorden
tokens
volledige antwoordpayloads van leerlingen
volledige privéberichtinhoud
volledige PDF-inhoud
gevoelige persoonsgegevens in vrije tekst
22.17 Performance- en fallbacktests
De teststrategie in hoofdstuk 23 moet voor performance en fallback minimaal de volgende testtypen ondersteunen.
| Testtype | Doel |
|---|---|
| Queryperformance-tests | controleren dat veelgebruikte overzichten bounded en geïndexeerd blijven |
| Loadtests | representatieve leerling-, docent-, ouder- en beheerflows testen |
| SignalR-reconnecttests | verbinding verbreken en herstel vanuit Practice valideren |
| PDF-stresstests | grote resultaten en lange tabellen renderen zonder geheugenproblemen |
| Job-retrytests | retries, failed-statussen en idempotentie controleren |
| Readmodel-rebuildtests | materialisatie opnieuw opbouwen vanuit brondata |
| Fallbacktests | fouten in dependencies simuleren en veilige UI-respons valideren |
| Security-performance tests | rate limits, access denied logging en veilige foutrespons testen |
| Transaction boundary tests | kritieke workflows zonder halve toestand laten falen |
22.18 Implementatiechecklist
Bij implementatie van performance- of fallbackgevoelige functionaliteit moet minimaal worden gecontroleerd:
- Is de brondata-eigenaar duidelijk?
- Is de query bounded, gepagineerd of bewust gelimiteerd?
- Zijn benodigde indexen binnen het module-eigen schema beschreven?
- Is autorisatie server-side toegepast vóórdat data wordt samengesteld?
- Is duidelijk of de workflow kritisch, retrybaar of degradeerbaar is?
- Is fallbackgedrag niet misleidend?
- Is er een correlation-id in logs en jobs?
- Is gevoelige data uitgesloten van logs?
- Is idempotentie geborgd bij retries?
- Is failed-status beheerbaar wanneer retrylimieten zijn bereikt?
- Is cachegebruik contextveilig?
- Is er een test voor fout- of fallbackgedrag?
- Is documentatie-impact op Technisch Ontwerp, database-informatie, Software Requirements Specification of Functioneel Ontwerp beoordeeld?
22.19 Implementatieverificaties
| Punt | Controle |
|---|---|
| Concrete NFR-grenswaarden | Software Requirements Specification en niet-functionele requirementregisters nalopen en meetpunten koppelen aan implementatietests. |
| Loadtestprofielen | Representatieve datasets en scenario’s definiëren voor leerling, docent, ouder/voogd en beheerder. |
| PDF-limieten | Maximale renderduur, bestandsgrootte en tijdelijke bewaartermijn vastleggen. |
| SignalR-capaciteit | Verwachte gelijktijdige live-meekijksessies en reconnectgedrag technisch testen. |
| TickerQ-dashboard | Interne beschikbaarheid, autorisatie en monitoring van failed jobs verifiëren. |
| Cachebeleid | TTL’s, invalidatie en contextveilige cachekeys per readmodel concretiseren. |
| Database-indexen | Per module querypatronen vertalen naar concrete indexvoorstellen. |
| Fallbackteksten | Gebruikersgerichte fout- en tijdelijke-onbeschikbaarteksten koppelen aan popup-/meldingsregisters waar van toepassing. |
| Monitoringprovider | Keuze voor technische monitoring/loggingprovider vastleggen in operatie- of infrastructuurdocumentatie. |