ID: S202512221450
Status: school
Tags: Avans 2-1 LU1, Presentatie
Avans 2-1 POC presentatie
Welkom bij de Avans Elective Hub. Dit is de Proof Of Concept voor de nieuwe keuzen module app van avans.
Stack keuze
Mijn app is gemaakt met React en NestJS en een zelfgehoste MongoDB container op mijn Docker vps. Bij het uitzoeken van frameworks had ik 2 dingen die ik belangrijk vond: het moest goed werken op mobile. Het moest werken met MongoDB en TypeScript. Nu bleek al snel dat een framework niet bepaald hoe goed iets werkt op mobile, en dat de frontend niks te maken heeft met de database die je kiest. Hoe ben ik dan wel op gekomen op React? Nou in de meeste frameworks zit niet echt een verschil, de grootste reden dat developers tegenwoordig een framework aan zullen raden is hun eigen bias. Dus toen ben ik gaan kijken naar de onderzoeks vragen.
| Criterium | React | Angular | Svelte | Vue |
|---|---|---|---|---|
| 1. Leesbaarheid & Voorbeelden | 8/10 | 6/10 | 9/10 | 9/10 |
| 2. TypeScript Ondersteuning | 8/10 | 10/10 | 9/10 | 9/10 |
| 3. Community Grootte (Actief) | 10/10 | 7/10 | 6/10 | 8/10 |
| 4. Framework Onderhoud & Updates | 9/10 | 9/10 | 8/10 | 9/10 |
| 5. CLI & Startsjablonen | 8/10 | 9/10 | 8/10 | 9/10 |
| 6. Documentatie Kwaliteit | 8/10 | 9/10 | 9/10 | 9/10 |
| 7. Bundle Size Performance | 7/10 | 4/10 | 10/10 | 8/10 |
| 8. Extensibility & Libraries | 10/10 | 8/10 | 7/10 | 9/10 |
| 9. Bedrijfsadoptie & Jobmarkt | 10/10 | 7/10 | 5/10 | 8/10 |
| 10. Toekomstbestendigheid (2026-2029) | 9/10 | 8/10 | 7/10 | 9/10 |
| TOTAAL | 87/100 | 77/100 | 78/100 | 87/100 |
Nu zie je hier dat Vue en React bovenaan staan, maar wat was dan de doorslaggevende klap? BIAS. Ik had bij het eerste onderzoek alleen artikelen gelezen van React developers wat er voor zorgde dat mijn data een BIAS had naar react toe, en pas bij de herkansing kwam ik er eigenlijk as achter hoe dicht de frameworks op elkaar staan. De belangrijkste verschillen tussen React en Vue zijn dat React een grotere community heeft met dus ook meer plugins en bedrijfsadoptie, waar vue meer / betere documentatie heeft, meer ssjablonene en meer voorbeelden. Achteraf gezien zou ik zijn gegaan voor Vue omdat ik daar nog geen kennis mee had, maar ik ging niet voor de herkansing helemaal opnieuw beginnen.
Hoe zit het met de backend? Nou daar is het verschil een stuk groter.
| Criterium | Express | NestJS | Fastify |
|---|---|---|---|
| 1. Leesbaarheid & Voorbeelden | 9/10 | 8/10 | 8/10 |
| 2. TypeScript Ondersteuning | 5/10 | 10/10 | 8/10 |
| 3. Community Grootte (Actief) | 10/10 | 8/10 | 6/10 |
| 4. Framework Onderhoud & Updates | 8/10 | 9/10 | 8/10 |
| 5. CLI & Startsjablonen | 3/10 | 10/10 | 4/10 |
| 6. Documentatie Kwaliteit | 8/10 | 10/10 | 8/10 |
| 7. MongoDB Integratie & ORM Support | 8/10 | 9/10 | 8/10 |
| 8. Built-in Testing & DI | 4/10 | 10/10 | 6/10 |
| 9. Bedrijfsadoptie & Jobmarkt | 9/10 | 8/10 | 5/10 |
| 10. Toekomstbestendigheid (2026-2029) | 8/10 | 9/10 | 8/10 |
| TOTAAL | 82/100 | 91/100 | 73/100 |
NestJS heeft een betere typescript ondersteuning, betere documentatie en heeft ingebouwde testing dan express js en fastify.
Onion architectuur
Mijn project heeft de ONION architecture toegepast. Dit zijn de lagen:
- Domain, dit zijn de Entities en interfaces. data structuur en niks meer.
- Application, dit zijn de use cases en de DTOs. Use cases zijn single responsability en afhankelijk van de entities en interfaces van laag 1.
- Infrastructure, De repositories en de mappers. Mappers worden gebruikt om te converteren tussen de Entities van laag 1 en de database modellen. Ook is er een persistence module die de dependency injection regelt.
- Presentation, dit zijn de controllers die dus alles aansturen gebaseerd op webrequests.
Nu is het onion architectuur een beetje misleidend, want het doet zich voor alsof het allemaal lagen zijn die op elkaar liggen, maar dan kom je aan bij de Infrastructure laag en dan klopt het niet echt, want de infrastructure laag zorgt er voor dat de dependency injection van de domain in de application laag werkt, dus eigenlijk moet de infrastructure laag tussen application en domain, als je kijkt in de logica van āalleen depending op lagen er onderā, maar dat klopt dan ook weer niet, dus daarom duurde het even voordat het klikte, en vind ik dat de bovenstaande schemas accurater zijn.
Realisatie
In mijn Proof of concept kan je inloggen als docent, admin en student. Als docent kan je modules toevoegen en studies aanpassen. Als admin kan je de vertalingen van de website aanpassen. Als student kan kan je een studie selecteren, en dan gebaseerd op je studie krijg je aanbevolen keuzen modules. Dit werkt zo want aan de studie en keuzenmodules hangen tags en op die manier ācross referencenā we de modules aan je studie. Dit vond ik het logischte voor deze POC want ik ging geen AI maken voor de POC.
Verder kan je als student ook favorieten selecteren, modules bekijken, filteren op modules. Ook is het mogelijk om deze app te installeren als PWA.
Voor het eindproduct moeten we denken aan de gebruiksvriendelijkheid, dus ik heb me veel gefocussed op het vertalen van alles. Alle text in de app is aanpasbaar door een admin of docent. En het nut hiervan is dat je engels en nederlands kan kiezen. dit vodn ik belangrijk aangezien avans ook veel engelse studenten heeft.
Requirements
Ik heb een hele waslijst met functionele requirements:
| Epic | Requirement | Beschrijving |
|---|---|---|
| 1 | FR1.1 | Student kan een lijst van beschikbare keuzemodules bekijken |
| 1 | FR1.2 | Student kan keuzemodules filteren op studiepunten (15 of 30 EC) |
| 1 | FR1.3 | Student kan keuzemodules filteren op niveau (NLQF-5 of NLQF-6) |
| 1 | FR1.4 | Student kan keuzemodules filteren op tags |
| 1 | FR1.5 | Student kan alle beschikbare tags bekijken |
| 2 | FR2.1 | Student kan gedetailleerde informatie over een keuzemodule bekijken (beschrijving, EC, type) |
| 2 | FR2.2 | Student kan keuzemodules aan favorieten toevoegen |
| 2 | FR2.3 | Student kan āmeer infoā knop gebruiken voor aanvullende details |
| 3 | FR3.1 | Student kan keuzemodules als favorieten opslaan |
| 3 | FR3.2 | Student kan keuzemodules uit favorieten verwijderen |
| 4 | FR4.1 | Student kan aanbevolen keuzemodules zien op basis van studierichting |
| 4 | FR4.2 | Aanbevelingen worden gegenereerd via een statisch/mock algoritme |
| 5 | FR5.1 | Gebruiker kan tussen Nederlands en Engels schakelen |
| 6 | FR6.1 | Student kan de app op telefoon installeren als PWA |
| 7 | FR7.1 | Communicatie tussen frontend en backend gebruikt JWT voor beveiliging |
| 7 | FR7.2 | Geen secrets of API-sleutels zijn hardcoded in code |
| 7 | FR7.3 | Mislukte requests worden elegant afgehandeld met duidelijke foutmeldingen |
| 8 | FR8.1 | Student kan een account registreren |
| 8 | FR8.2 | Docent kan een account registreren |
| 8 | FR8.3 | Student kan inloggen op account |
| 8 | FR8.4 | Docent kan inloggen op account |
| 8 | FR8.5 | Gebruiker blijft ingelogd na browser sessie sluiten |
| 8 | FR8.6 | Gebruiker kan uitloggen |
| 8 | FR8.7 | Gebruiker ziet duidelijke foutmeldingen bij mislukte login |
| 9 | FR9.1 | Docent kan nieuwe keuzemodules toevoegen |
| 9 | FR9.2 | Docent kan bestaande keuzemodules bewerken |
| 9 | FR9.3 | Docent kan keuzemodules verwijderen |
| 10 | FR10.1 | Docent kan vertalingen van keuzemodules bewerken |
| 10 | FR10.2 | Docent kan vertalingen van website UI bewerken |
| 10 | FR10.3 | Docent kan ongebruikte vertalingen bekijken |
| 10 | FR10.4 | Docent kan ongebruikte vertalingen verwijderen |
| 11 | FR11.1 | Student kan een studierichting selecteren |
| 11 | FR11.2 | Docent kan nieuwe studies toevoegen |
| 11 | FR11.3 | Docent kan studies bewerken |
| 11 | FR11.4 | Docent kan studies verwijderen |
| 11 | FR11.5 | Student kan eigen ingeschreven studierichting bekijken |
Non functional requirements:
| Epic | Requirement | Beschrijving |
|---|---|---|
| 5 | NFR5.1 | Applicatie ondersteunt meerdere talen (Nederlands, Engels) |
| 6 | NFR6.1 | Applicatie functioneert als Progressive Web App |
| 6 | NFR6.1a | App kan offline werken met caching |
| 6 | NFR6.1b | App kan op homescreen geĆÆnstalleerd worden |
| 7 | NFR7.1 | JWT tokens beveiligen API communicatie |
| 7 | NFR7.2 | Geen hardcoded secrets in broncode |
| 7 | NFR7.3 | Graceful error handling voor alle requests |
| 8 | NFR8.1 | Sessies blijven behouden over browser refresh |
| 8 | NFR8.2 | Foutmeldingen zijn duidelijk en informatief |
Testing
Testing was een belangrijk en nieuw deel, ik had al een keer eerder gewerkt met cypress, de front-end testing. Maar nog niet met een built-in testing framework zoals in NestJS zit.
Cypress
Ik gebruik Cypress om testen uit te voeren op de website. Hiermee kan ik testen of dat de functionaliteit het zelfde blijft. Zodra ik push naar main stuur doen we een cypress test, en als die een āsuccessā teruggeeft wordt mijn website gedeployed met CICD.
Waar test ik op? de meeste van mijn testen zijn om te kijken of dat je wel weggestuurd wordt als je een pagina bekijkt waarvoor je rechten moet hebben, wanneer je die rechten niet hebt. Een student die de beheer pgina bekijkt, of niet ingelogd zijn op de profiel pagina.
Unit testing
In de backend gebeurt iets soortgelijks, wanneer ik push naar main worden testen uitgevoerd, en als die goed zijn dan pas wordt de rest van de CICD gedaan. De backend testen zijn een feature van NestJS.

Waar test ik op? De grootste gedeelte van mijn testen zijn validatie van het json formaat dat de api endpoints teruggeven. Maar ook tesen op de gebruikers input om te kijke of de limitaties nogsteeds werken. Op elk endpoint zijn er testen toegevoegd.
CICD
Ik heb alles zelfgehost behalven de react app. De mongodb container draait op mijn VPS. Ik verind hiermee via de mongodb compass app, en in de backend via Mongoose. Mijn backend wordt ook gedraaid op deze VPS. Zodra ik commit op Main doet CICD mijn unit testen, en als die succeeden dan maak ik een Docker container. Daarna gaat de CICD via SSH mijn VPS in en deployed hij de nieuwe docker container. Op deze manier gaat het compleet automatisch. Mijn frontend wordt gehost op github pages, aangezien het een statische front-end is. Maar het is een half uurtje werk om dat om te zetten op een vergelijkbare manier als de backend. Het is wel belangrijk om te vermelden dat er geen credentials staan in mijn CD, dezen staan allemaal in de repository secrets.
Ook is het mogelijk om een andere versie die niet de nieuwste is te deployen als een rollback nodig is, want we gebruiken dockerub.

Database
Ik gebruik mongodb, maar ik heb het ingedeeld als een relationele database. Ik weet dat het idee van mongodb is dat je veel data er gewoon in kan kwakken, maar ik heb de approach gekozen die voor mij het logischte leek qua uitbereidbaarheid en leesbaarheid. Ik heb hierbij wel lijsten gebruikt met IDās naar andere elementen. En achteraf gezien zou ik de studie en keuzenmodule collectie samen kunnen voegen. Maar hier heb ik niet aan gedacht tijdens het ontwerpen.
De reden dat ik overal IDās gebruik in plaats van het behouden van data is omdat ik niet hou van duplicate data, ik heb tijdens dit project ook met de vertalingen het zo gedaan dat vertalingen hergebruikt worden als ze het zelfde zijn. Dit is gedaan uit de reden dat als ik 1 aanpassing maak ik het overal aangepast wil hebben, en omdat ik efficient wil omgaan met opslag.
Demo
Als we gaan kijken kunnen we inloggen als henk, henk is een student, Henk kan dus ook niet het management tabje zien. Als we gaan naar het profiel zien we dat henk architectuur studeert. Als we dan gaan kijken bij de aanbevolen modules zien we een 40% match met interieur ontwerp. Dit komt omdat de tags van de module overeen komen met die van zijn studie. Nou willen we dat natuurlijk in het echte project doen met AI. Nu we kijken naar deze module kunnen we hem toevoegen aan onze favorieten. en als we dan terug gaan naar de lijst zie we hem bij favorieten staan. nu is deze demo vanaf de geinstalleerde app, want we hebben PWA support. als ik nu itlog en inlog als mara zen we de beheer functies. Hier kunnen we bijvoorbeeld de keuzen modules aanpassen. Verder kunnen we ook de studies aanpassen, of de vertaling van de app.
Wat zou ik anders doen
De volgende keer zou ik beter onderzoek willen doen naar het framework want mijn informatie was vooral BIASED door react developers. Ook zou ik van tevoren een database schema maken waardoor ik dingen die erg op elkaar lijken kan samenvoegen, want mijn studie en keuzenmodule collectie zijn grotendeels het zelfde.