Functionele architectuurcontext
23.1 Doel
Dit hoofdstuk vertaalt de beschikbare C4-architectuurdocumentatie naar functionele context voor het FO.
Het hoofdstuk is geen Technisch Ontwerp en geen volledige beschrijving van componentklassen, interne API’s, database-implementatie of deployment. Het beschrijft welke architectuurkeuzes functioneel relevant zijn voor rollen, processen, autorisatie, brondata, readmodels, realtime gedrag, background jobs, exports en externe afhankelijkheden.
De functionele architectuurcontext helpt vooral om consistent te blijven in de andere FO-hoofdstukken:
- welke systeemgrens OefenHub heeft;
- welke externe systemen functioneel afhankelijk zijn;
- welke onderdelen binnen de webapp bronhoudend zijn;
- welke onderdelen alleen presentatie, transport, export of afleiding leveren;
- waar server-side autorisatie opnieuw moet plaatsvinden;
- welke data historisch reconstrueerbaar moet blijven;
- welke technische middelen functioneel gedrag ondersteunen zonder zelf bron van waarheid te worden.
23.2 Domeinafbakening
| Onderwerp | Binnen scope van dit FO-hoofdstuk | Buiten scope van dit FO-hoofdstuk |
|---|---|---|
| Systeemgrens | OefenHub als Nederlandstalige webapplicatie met afgebakende rollen en externe afhankelijkheden. | Deploymenttopologie, hostingkeuzes, netwerksegmentatie en infrastructuurdetails. |
| C4-context | Functionele interpretatie van C4 niveau 1 t/m 4. | Volledige C4-brontekst of diagramgeneratie dupliceren. |
| Externe systemen | Functionele rol van Keycloak en mailvoorziening. | Identity-providerconfiguratie, mailserverconfiguratie, protocoldetails en secrets. |
| Webappcontainer | Functionele betekenis van de modulaire monolithische Blazor/.NET-webapp. | Interne class diagrams, namespaces, service-interfaces en technische dependency-injectie. |
| Databasecontainer | Relationele brondata, configuratie, historie, audit en operationele gegevens. | Fysiek databasemodel per tabel, indexstrategie en SQL-implementatie. |
| Realtime | SignalR of gelijkwaardige realtimefunctionaliteit als transport voor updates. | Hubimplementatie, reconnectprotocol op laag niveau en transportoptimalisatie. |
| Background jobs | Functionele verwerking van periodieke taken zoals cleanup en termijnverwerking. | Schedulerconfiguratie, workerhosting en retrymechaniek op infrastructuurniveau. |
| PDF-export | Functionele export vanuit historische runcontext. | QuestPDF-layoutimplementatie, fonts, rendering-code en technische streamafhandeling. |
| Autorisatie | Overkoepelende server-side contextcontrole en objectniveau-autorisatie. | Volledige autorisatiematrix per command; die blijft in de ontwerpbron en domeinhoofdstukken. |
Dit hoofdstuk beschrijft dus de functionele samenhang tussen architectuuronderdelen. Detailflows blijven in usecases, schermdocumentatie, database-informatie, ontwerpbronnen en domeinspecifieke FO-hoofdstukken staan.
23.3 Bronpositie
Voor functionele architectuurcontext gelden de volgende bronlagen.
| Bronlaag | Betekenis |
|---|---|
| C4-architectuurdocumentatie | Beschrijft systeemcontext, containers, componenten en interne bouwblokken op hoofdlijnen. |
| FO-hoofdstukken | Vertalen architectuurkeuzes naar functioneel gedrag per domein. |
| Usecases | Beschrijven concrete procesflows, precondities, postcondities en uitzonderingsstromen. |
| Database-informatie | Beschrijft persistente brondata, readmodels, auditobjecten en hybride payloadgrenzen. |
| Ontwerpbronnen | Leggen business rules, autorisatiematrix, statusmodellen, commands, events en popupkeys vast. |
| Schermdocumentatie | Beschrijft routecontext, zichtbare onderdelen, acties, lege toestanden en UX-gedrag per scherm. |
| Mockups | Ondersteunen visuele interpretatie, maar bepalen geen systeemgrens of brondata. |
De C4-documentatie is leidend voor architectuurbegrippen. Het FO vertaalt die begrippen alleen naar functionele consequenties.
23.4 Systeemgrens
OefenHub is één Nederlandstalige webapplicatie voor oefenen, voortgang, beheer en ondersteuning van leerlingen, ouders/voogden, docenten en beheerders.
Binnen de systeemgrens vallen functioneel onder meer:
- accountcontext binnen OefenHub;
- rollen en rolcontext;
- relaties en uitnodigingen;
- oefencatalogus;
- technische oefenmodules als geïntegreerde modulebibliotheek;
- oefenruns, voortgang, resultaten en geschiedenis;
- gedeelde oefeningen;
- live meekijken;
- systeemberichten en privéberichtthreads;
- meldingen en ticketafhandeling;
- contentbeheer, popups, templates, features en systeemnotificaties;
- beheerderfunctionaliteit;
- PDF-export vanuit resultaatcontext;
- audit, history en functionele logging.
Buiten de systeemgrens vallen functioneel onder meer:
- primaire authenticatie en credential lifecycle bij de identity provider;
- e-mailtransport via mailvoorziening;
- mobiele apps buiten de huidige productscope;
- publieke API’s voor externe consumenten;
- vrije CMS- of pagebuilderfunctionaliteit;
- externe rapportageplatformen die niet als OefenHub-functie zijn uitgewerkt.
23.5 Primaire actoren
De C4-systeemcontext benoemt vijf primaire actoren. Deze actoren corresponderen met rolcontexten in het FO, maar een rolnaam alleen is niet voldoende voor iedere actie.
| Actor | Functionele betekenis binnen OefenHub | Belangrijke grens |
|---|---|---|
| Leerling | Maakt oefeningen, hervat runs, bekijkt eigen resultaten en gebruikt gedeelde oefeningen. | Kan niet gecombineerd worden met ouder-/voogd-, docent- of beheerderrol. |
| Ouder/voogd | Bekijkt gekoppelde kinderen, resultaten en geschiedenis en kan live meekijken. | Kan geen oefening namens kind starten, beantwoorden, afronden, corrigeren of delen. |
| Docent | Beheert niveaus, categorieën, oefeningen en leerlingtoegang binnen docentcontext. | Ziet resultaten en livebeschikbaarheid alleen binnen geldige docentcontext. |
| Beheerder | Beheert accounts, centrale inhoud, categorieën, modules, meldingen, ondersteuning en instellingen. | Heeft geen vrije bypass op eindgebruikersflows en mag niet live meekijken in actieve leerlingruns. |
| TestDocent | Gebruikt testmodules in een gecontroleerde docentcontext. | Niet-publieke rol; testresultaten zijn geen blijvende leerlinggeschiedenis. |
Voor alle actoren geldt dat zichtbare routes, knoppen of UI-blokken geen autorisatiebewijs zijn. Iedere detail-, export-, mutatie- en liveactie voert opnieuw server-side contextcontrole uit.
23.6 Externe systemen
OefenHub heeft in de C4-context twee primaire externe systemen.
| Extern systeem | Functionele rol | Functionele grens |
|---|---|---|
| Keycloak / identity provider | Verzorgt authenticatie, registratie, sessies en credential lifecycle. | OefenHub beheert geen wachtwoorden, credential-reset, identity-providerrollen of tokens als domeindata. |
| Mailvoorziening | Verzorgt e-mailafhandeling voor verificaties, uitnodigingen en notificatiegerelateerde processen. | OefenHub bewaart niet de technische mailserverstatus als functionele domeinwaarheid, tenzij een domeinflow expliciet een OefenHub-record vereist. |
23.7 Keycloak en interne OefenHub-context
Authenticatie bij Keycloak of een gelijkwaardige identity provider geeft nog geen volledige OefenHub-toegang.
Na succesvolle externe authenticatie moet OefenHub server-side bepalen:
- of een intern OefenHub-account bestaat;
- of provisioning nodig en succesvol is;
- of
Users.IsActivetoegang toestaat; - welke rollen op het interne account actief zijn;
- welke rolcontext bruikbaar is;
- welke frontpage of vervolgroute veilig geopend mag worden;
- of aanvullende profiel- of niveaucontext nodig is.
Een geldig identity-providerresultaat mag dus niet rechtstreeks worden gelijkgesteld aan toegang tot een leerling-, docent-, ouder-/voogd- of beheerderroute.
Wanneer interne accountinitialisatie faalt, ontstaat geen gedeeltelijk bruikbare OefenHub-sessie. De gebruiker krijgt een veilige accountfout of contactroute, terwijl technische details alleen in beheer- of technische logging thuishoren.
23.8 Mailvoorziening
De mailvoorziening ondersteunt OefenHub-processen, maar is geen functionele bron van waarheid voor OefenHub-domeinen.
Voorbeelden van domeinen die mail kunnen gebruiken:
- registratie- en verificatieflows;
- relatie-uitnodigingen naar onbekende e-mailadressen;
- notificatiegerelateerde processen;
- mogelijk beheer- of supportcommunicatie wanneer later uitgewerkt.
Voor OefenHub geldt:
- een relatie-uitnodiging wordt functioneel vastgelegd in OefenHub, niet in het mailsysteem;
- een systeembericht ontstaat pas wanneer er een interne ontvanger bekend is;
- mails mogen geen autorisatie vervangen;
- klikken op een mail- of berichtlink vereist opnieuw server-side contextcontrole;
- mailfouten mogen geen gevoelige tokens, credentials of technische details aan eindgebruikers tonen.
23.9 Hoofdcontainers
De C4-containercontext kiest in de huidige fase bewust voor een modulaire monolithische opzet.
| Container | Functionele betekenis |
|---|---|
| OefenHub Webapp | Primaire Blazor/.NET-webapp waarin gebruikersinterface, usecase-orkestratie, domeinlogica, objectniveau-autorisatie, realtime updates, background jobs en PDF-export samenkomen. |
| OefenHub Database | Relationele opslag voor domeindata, configuratie, historie, auditrecords en operationele applicatiegegevens. |
Deze containerindeling betekent functioneel niet dat alle verantwoordelijkheden ongescheiden zijn. Binnen de modulaire monolithische webapp blijven domeingrenzen, usecasegrenzen, autorisatiegrenzen en brondata-afbakening verplicht. De technische concretisering van deze keuze staat in het Technisch Ontwerp: architectuuroverzicht en solution-opbouw.
23.10 Functionele betekenis van de modulaire monolithische webapp
De modulaire monolithische webapp ondersteunt in fase 1 eenvoud en consistentie.
Functionele voordelen zijn:
- één centrale plek voor server-side autorisatie;
- consistente verwerking van route-, rol-, relatie- en objectcontext;
- directe samenhang tussen schermacties en usecase-services;
- uniforme toegang tot domeindata en history;
- minder risico dat realtime, PDF, cleanup of mailboxlogica een eigen afwijkende bron van waarheid krijgt.
Functionele aandachtspunten zijn:
- UI-logica mag domeinregels niet vervangen;
- domeinen moeten logisch gescheiden blijven binnen de applicatie;
- beheerderfunctionaliteit mag niet onbedoeld eindgebruikersflows omzeilen;
- background jobs moeten dezelfde domeinregels respecteren als interactieve flows;
- realtime transport en exportlogica mogen geen zelfstandige mutatiepaden worden.
23.11 Database als functionele bron voor domeindata
De OefenHub Database is de persistente bron voor domeindata, configuratie, historie, audit en operationele gegevens.
Voorbeelden van brondata zijn:
- interne accounts en gebruikersinstellingen;
- rollen en roltoekenningen;
- relaties en uitnodigingen;
- niveaus, categorieën, oefeningen en modulemetadata;
- oefenruns, voortgang, resultaten en gedeelde oefeningen;
- systeemberichten, privéthreads en participants;
- tickets, discussies, closures en reopen requests;
- contentblokken, links, popups, templates, featuretoggles en systeemnotificaties;
- audit- en historyrecords.
Voor gewone raadpleegscenario’s geldt dat readmodels, schermwaarden, badges, tellers, exports en realtimeweergaven uit deze brondata of expliciet afgeleide readmodels worden opgebouwd.
23.12 Hybride opslag en modulepayloads
OefenHub gebruikt functioneel een hybride opslagmodel.
| Gegevenstype | Opslagkarakter | Functionele reden |
|---|---|---|
| Uniforme kernvelden | Relationele kolommen | Nodig voor filters, overzichten, autorisatie, geschiedenis, resultaten, statistieken en audit. |
| Modulespecifieke configuratie | JSON/base64-payload binnen concrete oefeningconfiguratie | Variatie per technische module zonder relationeel model per module. |
| Vraag- en antwoorddata | JSON/base64-payload binnen run- en voortgangscontext | Variatie in vraagvormen, antwoorden en modulespecifieke presentatie. |
| Voortgang en totalen | Uniforme run- en voortgangsvelden | Nodig voor hervatten, live meekijken, resultaten en snelle uitlezing. |
| History en audit | Domeinspecifieke history/auditrecords | Nodig voor reconstructie, beheeranalyse en support. |
Uitbreiding van technische contextobjecten leidt niet automatisch tot nieuwe databasekolommen. Alleen gegevens die persistent, historisch relevant, querybaar, rapporteerbaar of auditbaar moeten zijn, komen in aanmerking voor relationele uitbreiding.
23.13 Logische hoofdcomponenten binnen de webapp
De C4-componentcontext splitst de webapp logisch op in verantwoordelijkheden. Deze componenten zijn functionele grenzen, geen zelfstandige FO-hoofdstukken.
| Component | Functionele verantwoordelijkheid |
|---|---|
| Web UI / Blazor schermlaag | Toont pagina’s, componenten, navigatie, formulieren, feedback en interactie. |
| Application Services / usecase-orkestratie | Coördineert schermacties en domeinflows. |
| Autorisatie- en frontendcontextcomponent | Bepaalt actieve context, frontpage-opbouw, routecontext en objectniveau-autorisatie. |
| Identity- en accountlifecycle-integratie | Verwerkt provisioning, interne accountcontext, accountstatus en lifecycle-acties. |
| Relatie- en toegangsbeheer | Verwerkt relaties, uitnodigingen, niveauautorisaties, collaborators en toegangscontext. |
| Catalogus-, configuratie- en contentbeheer | Beheert niveaus, categorieën, oefeningen, modules, content en beheerbare instellingen binnen codegedreven grenzen. |
| Technische module-integratie en strategylaag | Ontsluit technische oefenmodules via vaste contracten. |
| Oefenrun-, resultaat- en statistiekverwerking | Verwerkt runs, voortgang, antwoordstatus, geschiedenis, statistieken en resultaatbrondata. |
| Realtime en live-view | Ondersteunt live meekijken, badges en realtime UI-updates als transport. |
| Mailbox- en systeemberichten | Verwerkt systeemberichten, privéthreads, participants, readstates en mailboxreadmodels. |
| Site-notificaties en UI-notificatieafhandeling | Verwerkt systeemnotificaties, doelgroepcontext en browsergebonden weergaveregels. |
| Ticketing en meldingsafhandeling | Verwerkt meldingen, discussie, closures, reopen requests, doorzetten en tickethistory. |
| Document- en PDF-export | Genereert tijdelijke resultaat-PDF’s vanuit historische runcontext. |
| Background jobs en cleanup | Verwerkt periodieke taken, cleanup en termijnverwerking. |
| Data access / persistence-laag | Leest en schrijft brondata, hybride payloads, history en auditrecords. |
23.14 Schermlaag en usecase-orkestratie
De schermlaag vertaalt domeinregels naar gebruikersinteractie.
Voor de schermlaag geldt functioneel:
- zij presenteert gegevens uit brondata of readmodels;
- zij toont alleen acties die in de actuele context zinvol lijken;
- zij mag nooit de enige autorisatiecontrole zijn;
- zij mag routeparameters, filters of browserstate niet als bron van toegang gebruiken;
- zij mag popupteksten of template-inhoud niet dupliceren wanneer registers of templates leidend zijn;
- zij mag mockupwaarden niet als definitieve domeinwaarden behandelen.
Usecase-orkestratie vormt de brug tussen UI-acties en domeinlogica.
Voor usecase-orkestratie geldt:
- precondities worden server-side gecontroleerd;
- domeinregels worden toegepast vóór mutatie;
- fouten worden veilig teruggegeven;
- bij mutaties worden history, events, systeemberichten of readmodelupdates veroorzaakt waar het domein dat voorschrijft;
- een schermactie mag niet rechtstreeks om domeinservices of autorisatie heen schrijven.
23.15 Autorisatie- en contextcomponent
De autorisatie- en contextcomponent heeft functioneel een centrale rol.
Deze component bepaalt of afleidt onder meer:
- actieve accountstatus;
- actieve rolcontext;
- leerlingniveaucontext;
- ouder-/voogdrelatiecontext;
- docentcontext;
- niveau-eigenaarschap of collaboratorstatus;
- beheerdercontext of supportcontext;
- toegestane frontpagecontext;
- objecttoegang voor detail-, mutatie-, export- en liveacties.
Voor alle afgeschermde domeinen geldt:
- frontend-zichtbaarheid is nooit voldoende;
- routeparameters zijn nooit voldoende;
- directe URL’s zijn nooit voldoende;
- oude clientstate is nooit voldoende;
- iedere kritieke actie herhaalt actuele server-side controle;
- bij ontbrekende toegang wordt geen gedeeltelijke gevoelige inhoud getoond.
23.16 Rolcontexten en combinatierollen
Rolcontext is een functionele architectuurgrens.
| Context | Functionele bepalers | Voorbeeld van vervolgcontrole |
|---|---|---|
| Leerlingcontext | Actieve leerlingrol, actief account, geldige niveaucontext en toegankelijke oefencatalogus. | Starten of hervatten van een oefening controleert oefening, niveau, categorie en modulebeschikbaarheid opnieuw. |
| Ouder-/voogdcontext | Actieve ouder-/voogdrol en actieve GuardianStudent-relatie. | Resultaatdetail, PDF-export en live meekijken controleren de relatie opnieuw per actie. |
| Docentcontext | Actieve docentrol, docent-leerlingrelatie, niveauautorisatie, eigenaarschap of collaboratorstatus. | Resultaatinzage, leerlingautorisatie en oefeningbeheer blijven begrensd tot docentcontext. |
| Beheerdercontext | Actieve beheerderrol en expliciete beheer- of supportflow. | Beheerderacties blijven domeingebonden en auditbaar; geen vrije bypass op eindgebruikersflows. |
| TestDocentcontext | Niet-publieke testrol binnen gecontroleerde docent-/modulecontext. | Testmodules en testruns tellen niet als normale leerlinggeschiedenis. |
Ouder/voogd, docent en beheerder kunnen gecombineerd voorkomen. De rol Leerling is niet combineerbaar met deze rollen. Combinatierollen worden runtime samengesteld; zij vormen geen aparte persistente architectuurcontext.
23.17 Frontpages en contextopbouw
Frontpages zijn architecturaal gezien afgeleide startweergaven, geen zelfstandige persistente domeinentiteiten.
Een frontpage wordt opgebouwd uit:
- accountcontext;
- rolcontext;
- relatie- of docentcontext;
- contentblokken;
- domeinreadmodels;
- tellerdefinities;
- systeemnotificatiebeoordeling na normale paginaload.
Voor frontpages geldt:
- zij zijn primair read-only oriëntatieschermen;
- zij starten geen diepe mutaties zonder vervolgselectie;
- samenvattingswaarden zijn readmodels;
- zichtbare blokken zijn geen autorisatiebewijs;
- gecombineerde frontpages worden runtime samengesteld;
- er worden geen aparte persistente frontpageontwerpen per rolcombinatie beheerd.
23.18 Relatie- en toegangsbeheer als architectuurgrens
Relaties en toegang zijn functioneel bronhoudend voor meerdere domeinen.
Voorbeelden:
- vriendschap bepaalt of een leerling oefeningen mag delen;
- ouder-/voogdrelatie bepaalt kinderen, resultaten, PDF en live meekijken;
- docent-leerlingrelatie en niveauautorisatie bepalen leerlingtoegang en docentinzage;
- docent-docentrelatie ondersteunt samenwerking en collaborators;
- beheerder-beheerderrelatie ondersteunt beheercommunicatie.
Relaties worden niet impliciet aangemaakt door berichten, frontpageweergave, live meekijken, gedeelde oefeningen of beheerondersteuning.
Ontkoppelen beëindigt toekomstige relatieafhankelijke toegang, maar herschrijft geen historische oefenruns, berichten, resultaten, auditrecords of PDF-broncontexten.
23.19 Oefendomeincomponenten
Het oefendomein bestaat functioneel uit meerdere samenhangende lagen.
| Laag | Functionele betekenis |
|---|---|
| Oefencatalogus | Niveaus, centrale categorieën, niveau-categorie-koppelingen en concrete oefeningen. |
| Module-integratie | Technische modulecontracten voor configuratie, generatie, antwoordcontrole, weergave en exportrepresentatie. |
| Oefenrunverwerking | Aanmaken, hervatten, voortgang opslaan, antwoorden verwerken en afronden van runs. |
| Resultaatverwerking | Uniforme totalen, statistieken, geschiedenisdetail en resultaatweergave. |
| Delen | Administratief shared-record en zelfstandige ontvangerruns. |
| PDF/export | Tijdelijke export vanuit historische runcontext. |
| Live-view | Read-only voortgangsweergave vanuit opgeslagen run- en voortgangsdata. |
Deze lagen mogen elkaar gebruiken, maar niet elkaars brondata vervangen.
Voorbeelden:
- een module levert logica, maar beheert geen autorisatie;
- een oefenrun bewaart historische context, ook na latere categorie- of modulewijzigingen;
- een gedeelde oefening maakt pas bij start een zelfstandige ontvangerrun;
- PDF-export leest resultaatdata en muteert geen run;
- live meekijken leest voortgang en muteert geen antwoorddata.
23.20 Technische module-integratie
Technische oefenmodules zijn geïntegreerde codecomponenten achter een vast modulecontract.
Functioneel geldt:
- beschikbare modules worden administratief beheerd via modulemetadata;
- modules worden niet willekeurig runtime ontdekt als vrije pluginbron;
- een concrete oefening verwijst naar precies één technische module;
- modulespecifieke configuratie wordt generiek opgeslagen als payload;
moduleKeyenschemaVersionin de bestaande payload zijn leidend voor schemaherleidbaarheid;- er wordt geen extra generieke databasekolom geïntroduceerd wanneer payloadvelden voldoende zijn;
- oude runs blijven interpreteerbaar via historische payloadcontext;
- modulemigraties herschrijven historische runs, resultaten of PDF-contexten niet.
De module-integratie is daarmee een functionele extensiegrens, geen vrije beheerbare scriptingomgeving.
23.21 Oefenruns, resultaten en geschiedenis
Oefenruns zijn de centrale functionele bron voor leerlingvoortgang, resultaten, geschiedenis, PDF-export en live meekijken.
Architecturaal geldt:
- een run ontstaat alleen door een geldige startactie;
- voortgang wordt server-side opgeslagen na bevestigde stappen;
- onderbreken rondt een run niet af;
- afronden gebeurt pas wanneer de laatste vraag definitief is verwerkt;
- uniforme totalen en statistieken worden op runniveau opgeslagen of consistent afgeleid volgens domeinregels;
- historische runcontext blijft leidend voor resultaatweergave en PDF-export;
- niet-afgeronde runs verschijnen niet als normale afgeronde geschiedenis;
- docenttestruns worden niet blijvend als leerlinggeschiedenis behandeld.
Deze regels zorgen dat frontpages, geschiedenis, live meekijken, ouderinzage, docentinzage en PDF-export niet ieder hun eigen interpretatie van resultaatdata krijgen.
23.22 Communicatie- en notificatiearchitectuur
OefenHub kent meerdere communicatielagen die functioneel gescheiden blijven.
| Communicatielaag | Functionele bron | Architectuurgrens |
|---|---|---|
| Mailbox-systeemberichten | SystemMessages | Gebruikergebonden systeemcommunicatie met eventuele domeinverwijzing. |
| Privéberichtthreads | Thread, participants, berichten en thread-events | Relatie- of systeemcontext bepaalt verzend- en leesrechten. |
| Ticketdiscussie | Ticketdiscussion binnen meldingen | Geen privéberichtthread, behalve expliciete doorzetflow. |
| Systeemnotificaties | SiteNotifications | Frontpage-overlay, geen mailboxitem en geen popupregister-popup. |
| Popupfeedback | Popupregister en PopupDetails | Actie-, validatie- of foutfeedback. |
| Realtime updates | SignalR of gelijkwaardig transport | Versnelt UI-updates, maar is geen bron van waarheid. |
Deze scheiding voorkomt dat bijvoorbeeld een systeemnotificatie een systeembericht vervangt, of dat ticketcommunicatie ongecontroleerd als privébericht wordt opgeslagen.
23.23 Realtime en live-view
Realtime-functionaliteit ondersteunt snelle gebruikerservaring, maar is functioneel nooit bron van waarheid.
Realtime kan worden gebruikt voor:
- live meekijken;
- voortgangsupdates;
- mailboxbadges;
- systeemcommunicatie-indicaties;
- online-overzichten;
- notificatie van relevante wijzigingen;
- statusupdates na acties.
Voor realtime geldt:
- opslag in de database blijft leidend;
- bij gemiste realtimeberichten wordt bij herladen opnieuw server-side gelezen;
- live meekijken is read-only;
- browsemodus in live meekijken is presentatiestate;
- realtime updates mogen autorisatie niet verruimen;
- reconnect mag geen data wijzigen;
- audit ontstaat bij domeingebeurtenissen, niet omdat transport actief is.
23.24 Background jobs en cleanup
Background jobs ondersteunen periodieke of asynchrone verwerking binnen OefenHub.
Functioneel relevante voorbeelden zijn:
- verlopen relatie-uitnodigingen verwerken;
- tijdelijke docenttestruns opschonen;
- verlopen ticket-heropentermijnen periodiek beoordelen;
- cacheverversing of afgeleide housekeeping waar expliciet uitgewerkt;
- toekomstige domeinspecifieke cleanup met expliciete regels.
Voor background jobs geldt:
- zij volgen dezelfde domeincriteria als interactieve flows;
- zij zijn idempotent waar dat functioneel vereist is;
- zij maken geen extra sluit- of historyrecords wanneer het domein dat uitsluit;
- zij versturen geen extra communicatie tenzij een domeinregel dat voorschrijft;
- falen van één record mag verwerking van andere kandidaten niet onnodig blokkeren;
- een gemiste run moet bij een volgende verwerking kunnen worden ingehaald wanneer het domein dat vereist.
Background jobs mogen geen verborgen alternatieve mutatieroute worden die autorisatie, statusmodellen of auditregels omzeilt.
23.25 PDF-export en documentgeneratie
PDF-export is functioneel een tijdelijke export vanuit bestaande historische brondata.
Voor resultaat-PDF’s geldt:
- de export gebruikt dezelfde historische runcontext als de resultaatweergave;
- de export muteert geen run, voortgang, resultaat of geschiedenis;
- er ontstaat geen verplicht permanent PDF-record;
- bestandsnaam, inhoud, tabellen, vervolgpagina’s en footerregels volgen het PDF-exporthoofdstuk;
- module-specifieke vraag- of antwoordpresentatie mag via module-exportrepresentatie worden ondersteund;
- roltoegang wordt opnieuw server-side gecontroleerd voor leerling, docent of ouder/voogd.
QuestPDF of een gelijkwaardige PDF-generator is dus technisch ondersteunend. De functionele bron blijft de geautoriseerde historische resultaatcontext.
23.26 Content, instellingen en beheerbare configuratie
OefenHub maakt onderscheid tussen codegedreven structuur en beheerbare inhoud.
| Onderdeel | Functionele regel |
|---|---|
| Contentblokken | Beheren tekst op vaste plekken; geen pagebuilder. |
| Footerlinks | Gebruiken herbruikbare URL-records en vaste footersecties. |
| Popups | Worden aangestuurd door popupkeys en popupregister; beheer wijzigt alleen toegestane velden. |
| Systeemberichttemplates | Beheren inhoud voor toekomstige systeemcommunicatie; concrete systeemberichten blijven eigen records. |
| Featuretoggles | Schakelen expliciet togglebare functies, maar verwijderen geen bestaande data. |
| Systeeminstellingen | Beheren bestaande configuratiesleutels met datatype en invoervorm. |
| Systeemnotificaties | Planbare overlays na frontpageload; geen mailboxitems. |
Beheerbare configuratie mag geen nieuwe technische domeinen, routes, popupflows, layoutstructuren of autorisaties creëren buiten code en documentatie om.
23.27 Beheerderfunctionaliteit binnen de architectuur
Beheerderfunctionaliteit is een expliciete beheercontext binnen OefenHub, geen onbeperkte technische toegang.
Voor beheerderacties geldt:
- iedere actie vereist actuele server-side beheercontext;
- acties blijven domeingebonden;
- beheerderondersteuning corrigeert of inspecteert binnen supportflows;
- beheerder kan niet vrij namens eindgebruikers alle eindgebruikershandelingen uitvoeren;
- beheerder mag geen leerlingrun live volgen buiten de toegestane live-meekijkrollen;
- mutaties zijn auditbaar wanneer het domein dat vereist;
- technische details blijven alleen zichtbaar waar beheerautorisatie en functionele noodzaak bestaan.
Deze grens is belangrijk omdat de webapp als één modulaire monolithische applicatie is gepositioneerd: beheerderfunctionaliteit zit technisch in dezelfde applicatie, maar functioneel in gescheiden flows.
23.28 Audit, historie en reconstructie
OefenHub gebruikt per domein passende vormen van audit en historie.
Voorbeelden:
RelationshipEventsvoor relatiegebeurtenissen;CategoryHistoryenExerciseHistoryvoor cataloguswijzigingen;- modulegeschiedenis en modulemigratiehistorie;
TicketHistory,TicketClosuresenTicketReopenRequestsvoor meldingen;LiveViewAuditvoor daadwerkelijk gestarte live-meekijksessies;- content-, popup-, template-, feature- en notificatiehistorie;
- accountlifecyclelogging;
- technische applicatielogs met beperkte persoonsgegevens.
Niet elk domein gebruikt hetzelfde patroon.
| Patroon | Voorbeeld | Functionele betekenis |
|---|---|---|
| Append-only history | Ticketclosures, reopen requests, historyrecords | Eerdere formele gebeurtenissen blijven intact. |
| Soft delete | URL-records, relaties, footerlinktoewijzingen waar relevant | Zichtbaarheid stopt, historie blijft. |
| IsActive / status | Rollen, categorieën, modules, oefeningen, relaties | Actuele beschikbaarheid zonder historische reconstructie te verliezen. |
| Auditrecord per sessie | LiveViewAudit | Vastleggen dat live meekijken daadwerkelijk is gestart. |
| Technische log | Accountlifecycle, provisioningfouten, schedulerfouten | Analyse zonder onnodige persoonsgegevens te tonen. |
Audit en historie zijn geen vrije gebruikersweergave. Welke history zichtbaar is, hangt af van rolcontext, beheercontext en domeinregels.
23.29 Events, commands en statusmodellen
Ontwerpbronnen zoals command-register, event-register, statusmodellen en business rules vormen een functionele brug tussen FO, TO en SRS.
Voor de architectuurcontext geldt:
- commands beschrijven welke functionele acties bestaan;
- events beschrijven relevante domeingebeurtenissen of auditmomenten;
- statusmodellen bepalen toegestane procesovergangen;
- business rules leggen domeinbrede regels vast;
- de autorisatiematrix bepaalt rol- en contextgrenzen per actie.
Dit hoofdstuk dupliceert die registers niet. Het legt alleen vast dat uitvoering van commands, events en statusovergangen via de server-side domeinlaag loopt en niet via losse UI-state.
23.30 Readmodels, tellers en samenvattingswaarden
Veel schermen tonen afgeleide waarden.
Voorbeelden:
- frontpageblokken;
- ongelezenbadges;
- meldingentellers;
- leerling-, docent- en ouder-/voogdoverzichten;
- populaire categorieën;
- recent geoefend;
- online-overzichten;
- beheerderfrontpage-indicatoren;
- resultaat- en geschiedenisfilters.
Voor readmodels geldt:
- zij zijn afgeleid uit brondata;
- zij verruimen geen autorisatie;
- zij mogen geen eigen afwijkende statuswaarheid introduceren;
- tellerdefinities moeten eenduidig zijn;
- filters en sortering zijn presentatiegedrag tenzij het domein anders bepaalt;
- cache mag geen context- of autorisatiegrens doorbreken.
23.31 Privacy- en securityprincipes
Functionele architectuurkeuzes ondersteunen de volgende privacy- en securityprincipes.
- Server-side autorisatie is leidend.
- Clientstate, routeparameters, browsergeschiedenis en filters verruimen toegang nooit.
- Bij geweigerde toegang wordt geen gedeeltelijke gevoelige inhoud getoond.
- Eindgebruikers zien geen stacktraces, tokens, technische payloads of interne identifiers.
- Beheerders zien alleen technische context waar dat functioneel nodig en geautoriseerd is.
- PDF-export, live meekijken, resultaatdetails en geschiedenis controleren opnieuw objecttoegang.
- Realtime transport en browserwaarden zijn geen autorisatiebron.
- Browserwaarden voor toegankelijkheid of
OncePerBrowsermogen geen persoonsgegevens of autorisatiedata bevatten. - Accountanonimisering beëindigt actuele toegang, maar behoudt audit en functionele reconstructie waar nodig.
23.32 Geen publieke API-scope
De huidige productscope gaat uit van een webapplicatie.
Er worden geen publieke API-endpoints ontworpen voor:
- een aparte mobiele app;
- externe integraties;
- derde partijen;
- openbare dataconsumptie;
- generieke rapportagetools.
Interne server calls, Blazor-interactie, SignalR-hubs of backendendpoints kunnen technisch bestaan, maar vallen buiten dit FO tenzij zij functioneel zichtbaar gedrag bepalen.
Wanneer later publieke API’s nodig zijn, vraagt dat een aparte scopebeslissing, autorisatie-uitwerking, datacontract, rate limiting, privacybeoordeling en documentatie.
23.33 Geen microservice- of pluginplatformscope
De huidige architectuurcontext beschrijft geen microserviceplatform.
Functioneel betekent dit:
- domeinen blijven logisch gescheiden, maar draaien binnen één webappcontext;
- modules zijn geïntegreerde technische componenten achter een vast contract, geen vrije externe plugins;
- beheer kan geen code of scripts uploaden om nieuwe modulelogica te maken;
- realtime, jobs, PDF en mail zijn ondersteunende onderdelen binnen dezelfde functionele applicatiegrens;
- externe systemen blijven beperkt tot de expliciet beschreven afhankelijkheden.
Wanneer later microservices, externe pluginmechanismen of publieke modulemarktplaatsen nodig zijn, vallen die buiten deze FO-scope.
23.34 Lege toestanden
Lege toestanden in de functionele architectuur zijn normale toestanden wanneer de gebruiker wel toegang heeft, maar er geen relevante data is.
Voorbeelden:
- gebruiker heeft geen actieve rolcontext;
- leerling heeft geen toegankelijke oefeningen;
- docent heeft geen leerlingen of niveaus;
- ouder/voogd heeft geen gekoppelde kinderen;
- beheerderfrontpage heeft geen recente wijzigingen;
- mailbox heeft geen berichten;
- systeemnotificatiebeoordeling vindt geen actieve notificatie;
- background job vindt geen kandidaten;
- PDF-export heeft geen toegang tot een afgeronde run;
- live-overzicht toont geen online leerlingen of kinderen.
Een lege toestand mag informatief zijn, maar mag geen verborgen objectnamen, technische details of autorisatie-informatie lekken.
23.35 Fouttoestanden
Fouttoestanden ontstaan wanneer de architectuurcontext niet veilig of consistent kan worden toegepast.
Voorbeelden:
- identity-providerlogin slaagt, maar interne provisioning faalt;
- account is inactief;
- rolcontext is ongeldig of ontbreekt;
- routeparameter verwijst naar een object buiten toegestane context;
- readmodelopbouw faalt;
- modulepayload kan niet veilig geïnterpreteerd worden;
- realtimeverbinding valt weg;
- background job faalt op één of meer records;
- PDF-export kan historische runcontext niet lezen;
- mailafhandeling faalt;
- databaseopslag of historyregistratie mislukt;
- beheerder probeert een technische read-only waarde via de GUI te wijzigen.
Bij fouttoestanden geldt:
- de gebruiker krijgt veilige foutfeedback;
- gevoelige inhoud wordt niet gedeeltelijk getoond;
- mutaties worden niet half functioneel zichtbaar wanneer transactieconsistentie vereist is;
- technische logging bevat voldoende correlatie voor analyse;
- tokens, credentials en identity-providerinterne gegevens worden niet als OefenHub-domeindata opgeslagen.
23.36 Functionele architectuurrelaties met andere FO-hoofdstukken
| FO-hoofdstuk | Relatie met functionele architectuurcontext |
|---|---|
| Bronnen en afbakening | Bepaalt bronhiërarchie, DRY-principes en linkbeleid. |
| Productvisie en scope | Bepaalt productscope, doelgroep en geen-publieke-API uitgangspunt. |
| Rollen, context en autorisatie | Werkt rolcontext, combinatierollen en autorisatieprincipes inhoudelijk uit. |
| Applicatieschil, header, footer en navigatie | Vertaalde schermcontext voor navigatie, badges en responsiviteit. |
| Frontpages en overzichtsschermen | Beschrijft frontpages als read-only afgeleide contextweergaven. |
| Account, profiel en voorkeuren | Beschrijft identity-providergrens, provisioning, profiel en voorkeuren. |
| Relatiebeheer | Beschrijft relaties als autorisatiebron voor meerdere domeinen. |
| Oefencatalogus, niveaus, categorieën en oefeningen | Beschrijft catalogus-, module- en oefeningstructuur. |
| Leerling: oefenen, voortgang en resultaten | Beschrijft run-lifecycle, voortgang, resultaten en geschiedenis. |
| Gedeelde oefeningen | Beschrijft shared-records, bronruns en ontvangerruns. |
| Docentfunctionaliteit | Beschrijft docentcontext, oefenaanbod, leerlingen, autorisaties en samenwerking. |
| Ouder-/voogdfunctionaliteit | Beschrijft ouder-/voogdcontext en read-only inzage. |
| Beheerderfunctionaliteit | Beschrijft beheercontext, support, centrale beheerfuncties en audit. |
| Berichten, communicatie en notificaties | Beschrijft communicatievormen en realtime/badgegrenzen. |
| Meldingen en ticketafhandeling | Beschrijft ticketlifecycle, statusmodellen, closures en heropenen. |
| Live meekijken | Beschrijft realtime read-only voortgangsweergave en LiveViewAudit. |
| Contentbeheer, vaste pagina’s en footer | Beschrijft codegedreven contentbeheergrenzen. |
| Popups, templates, features en systeemnotificaties | Beschrijft beheerbare feedback, templates, toggles en notificaties. |
| PDF-export en resultaatpresentatie | Beschrijft export vanuit historische resultaatcontext. |
| Functionele beslisregels en uitgangspunten | Bundelt domeinbrede beslisregels en uitgangspunten. |
| Open punten en buiten scope | Houdt resterende keuzes en uitgesloten onderwerpen bij. |
| Schermlaag en UX-specificaties | Beschrijft schermbronpositie, read-only gedrag en UX-principes. |
| Oefenmodules en modulepayloads | Beschrijft technische modulegrenzen en payloadinterpretatie. |
23.37 Gerelateerde bronverwijzingen
| Bron | Link |
|---|---|
| Technisch Ontwerp — architectuuroverzicht | Architectuuroverzicht en solution-opbouw |
| Technisch Ontwerp — applicatielagen | Applicatielagen, projectstructuur en dependency-richting |
| Technisch Ontwerp — domeinmodel | Domeinmodel en datamodel-overzicht |
| Technisch Ontwerp — background jobs | Background jobs, TickerQ en periodieke verwerking |
| Architectuur — intro | Architectuur |
| C4 — intro | C4 intro |
| C4 niveau 1 — System Context | System Context |
| C4 niveau 2 — Container Diagram | Container Diagram |
| C4 niveau 3 — Component Diagram | Component Diagram |
| C4 niveau 4 — Interne bouwblokken | Interne bouwblokken |
| Database-informatie — identiteit en autorisatie | Identiteit en autorisatie |
| Database-informatie — relatiebeheer | Relatiebeheer |
| Database-informatie — docentstructuur en leerlingtoegang | Docentstructuur en leerlingtoegang |
| Database-informatie — communicatie en notificaties | Communicatie en notificaties |
| Database-informatie — configuratie en contentbeheer | Configuratie en contentbeheer |
| Database-informatie — ticket- en meldingsbeheer | Ticket- en meldingsbeheer |
| Database-informatie — oefenruns, delen en voortgang | Oefenruns, delen en voortgang |
| Database-informatie — audit, historie en technische uitgangspunten | Audit, historie en technische uitgangspunten |
| Ontwerpbron — business rules | Business rules |
| Ontwerpbron — autorisatiematrix | Autorisatiematrix |
| Ontwerpbron — domeinobjecten | Domeinobjecten |
| Ontwerpbron — statusmodellen | Statusmodellen |
| Ontwerpbron — command-register | Command-register |
| Ontwerpbron — event-register | Event-register |
| FO — rollen, context en autorisatie | Rollen, context en autorisatie |
| FO — schermlaag en UX-specificaties | Schermlaag en UX-specificaties |
| FO — oefenmodules en modulepayloads | Oefenmodules en modulepayloads |