Fase 0: Fundament
20 user stories, 7 scenario’s + 1 edge case.
S-0.1 Monorepo opzetten en valideren
Section titled “S-0.1 Monorepo opzetten en valideren”Een developer clonet de repo, installeert dependencies en checkt of de basis tooling werkt.
Dekt: 0.1.1, 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6
Voorwaarden: Lege repo, Node 20, pnpm geinstalleerd
- Clone de repo en draai
pnpm install - Check mapstructuur:
apps/web,apps/api,apps/docs,packages/shared - Draai
pnpm typecheck, geen fouten - Draai
pnpm lint, geen warnings - Open
packages/shared/src/types.ts, bevat gedeelde types - Open
packages/shared/src/validation.ts, bevat Zod schemas - Check dat
apps/webTailwind CSS +cn()helper heeft - Check dat shadcn/ui componenten beschikbaar zijn
- Check dat
apps/apieen Hono app is op Cloudflare Workers - Check dat
apps/docseen Starlight site is
Resultaat: Alle tools werken, strict mode actief, geen lint warnings, shared package is bruikbaar vanuit web en api.
S-0.2 Database en RLS valideren
Section titled “S-0.2 Database en RLS valideren”Developer checkt of de Supabase database correct is opgezet met alle kerntabellen en RLS policies.
Dekt: 0.2.1, 0.2.2, 0.2.3
Voorwaarden: Supabase project aangemaakt
- Draai de eerste migratie
- Controleer dat tabellen bestaan:
clients,dogs,vaccinations,users,services - Controleer dat
servicestabel seed data bevat (alle diensten + prijzen) - Log in als klant, probeer data van een andere klant op te vragen. Geblokkeerd door RLS.
- Check RLS policy:
client_id = (SELECT auth.uid())op klanttabellen - Log in als admin, check dat alle data zichtbaar is via admin RLS policy (
role IN ('admin', 'medewerker')) - Probeer als anonieme gebruiker data op te vragen. Geblokkeerd.
Resultaat: Alle tabellen bestaan, seed data aanwezig, RLS blokkeert ongeautoriseerde toegang.
S-0.3 Klant registreert en logt in
Section titled “S-0.3 Klant registreert en logt in”Een nieuwe klant maakt een account aan via /register en wordt correct gerouteerd.
Dekt: 0.3.1, 0.3.2, 0.3.5
Voorwaarden: App draait, database klaar
- Ga naar
/register - Controleer dat het formulier drie velden heeft: Naam, Email en Wachtwoord
- Vul een naam in (min. 2 karakters), email en wachtwoord (min. 8 tekens)
- Klik op “Account aanmaken”
- Check dat PKCE flow wordt gebruikt (geen implicit grant)
- Check dat een rij in de
clientstabel wordt aangemaakt metonboarding_completed = false - Na registratie, redirect naar
/onboarding - Log uit
- Ga naar
/login, klik op “Wachtwoord vergeten?” (linkt naar/forgot-password) - Vul email in, klik op “Verstuur resetlink”
- Check dat de melding altijd hetzelfde is: “Als dit emailadres bij ons bekend is, ontvang je een resetlink.”
- Open de resetlink uit de email. Komt op
/reset-passwordmet token in de URL. - Vul “Nieuw wachtwoord” en “Bevestig wachtwoord” in
- Klik “Wachtwoord opslaan”
- Check redirect naar
/loginmet succesmelding “Wachtwoord gewijzigd. Je kunt nu inloggen.” - Log in met nieuw wachtwoord, redirect naar klant dashboard
- Vul twee wachtwoorden in die niet overeenkomen. Check foutmelding “Wachtwoorden komen niet overeen.”
- Vul een wachtwoord in korter dan 8 tekens. Check foutmelding “Wachtwoord moet minimaal 8 karakters zijn.”
- Gebruik een verlopen token (>1 uur). Check foutmelding “Deze resetlink is verlopen. Vraag een nieuwe aan.”
- Gebruik een ongeldig/verminkt token. Check foutmelding “Ongeldige link. Vraag een nieuwe resetlink aan.”
Resultaat: Account aangemaakt via PKCE, redirect naar onboarding, wachtwoord reset werkt, alle foutpaden bij reset geven de juiste melding.
S-0.4 Admin logt in en role-based routing
Section titled “S-0.4 Admin logt in en role-based routing”Een admin logt in en wordt naar het admin panel gerouteerd. Klanten worden correct geweerd van admin routes.
Dekt: 0.3.3, 0.3.5
Voorwaarden: Admin account bestaat in database met role = 'admin'
- Ga naar
/login - Log in als admin met email + wachtwoord
- Check redirect naar
/admin(niet/dashboard) - Log uit
- Log in via magic link: klik “Inloggen met magic link”, vul email in, ontvang link
- Open de magic link, check redirect naar
/admin - Log in als klant (met voltooide onboarding). Check redirect naar
/dashboard. - Als klant, probeer handmatig naar
/adminte navigeren. Check redirect naar/dashboard. - Log in als admin, probeer handmatig naar
/dashboardte navigeren. Check redirect naar/admin. - Log uit, probeer
/dashboardte bezoeken. Check redirect naar/login. - Check dat de oorspronkelijke URL bewaard wordt: na redirect naar
/loginen opnieuw inloggen, kom je terug op de originele pagina. - Log in als klant met
onboarding_completed = false. Check redirect naar/onboarding, ongeacht welke route je probeerde.
Resultaat: Admin wordt correct gerouteerd via wachtwoord en magic link. Auth guards werken: klanten komen niet bij admin, admins niet bij klant dashboard, onboarding is verplicht.
S-0.5 API basis en beveiliging
Section titled “S-0.5 API basis en beveiliging”Developer checkt of de API correct beveiligd is.
Dekt: 0.3.4, 0.4.1, 0.4.2, 0.4.3
Voorwaarden: API draait op Cloudflare Workers
GET /healthzonder token, moet 200 OK geven met body{ status: "ok" }GET /api/bookingszonder token, moet 401 Unauthorized gevenGET /api/bookingsmet geldige JWT, moet 200 gevenPOST /api/bookingsmet ongeldige data, moet 400 geven met Zod validatiefout- Check CORS: request vanuit andere origin wordt geblokkeerd. Alleen
APP_ORIGINis toegestaan. - Check dat CORS op localhost werkt als
ENVIRONMENT !== 'production' - Check dat foutmeldingen geen interne details bevatten (geen stack traces, geen
error.message) - Check dat
/payments/webhookgeen auth vereist (uitgezonderde route) - Check dat alle queries een
.limit()hebben (200-500 range)
Resultaat: Health endpoint open met correct format, alle andere routes beveiligd, CORS actief, input gevalideerd, geen interne details in foutmeldingen.
S-0.6 Basis UI en meertaligheid
Section titled “S-0.6 Basis UI en meertaligheid”Klant en admin zien de juiste layout, navigatie werkt in meerdere talen.
Dekt: 0.5.1, 0.5.2, 0.5.3
Voorwaarden: App draait, gebruiker ingelogd
- Log in als klant. Check navigatie-items: Dashboard (
/dashboard), Mijn honden (/dogs), Boekingen (/bookings), Facturen (/invoices), Account (/account). - Check header: logo Dog Hotel Aruba, taalwissel (NL/EN), gebruikersnaam met dropdown (account, uitloggen).
- Check dat de actieve route visueel gemarkeerd is in de navigatie.
- Check sidebar op desktop, hamburger menu op mobiel (375px breed). Menu opent als overlay.
- Klik op de taalwissel, kies EN. Alle UI-teksten wisselen direct (geen pagina-reload, via react-i18next).
- Wissel terug naar NL.
- Check dat de taalvoorkeur wordt opgeslagen in
localStoragevoor niet-ingelogde gebruikers. - Check dat voor ingelogde klanten de taalvoorkeur ook wordt opgeslagen in het profiel (
preferred_languageinclientstabel). - Log uit en weer in. Check dat de taalvoorkeur behouden is (uit profiel geladen).
- Log in als admin. Check navigatie-items: Dashboard (
/admin), Klanten (/admin/clients), Honden (/admin/dogs), Boekingen (/admin/bookings), Facturen (/admin/invoices), Instellingen (/admin/settings). - Controleer dat admin layout een ander kleurenschema/accent heeft dan klant layout.
- Controleer dat de browser-taal wordt gedetecteerd voor niet-ingelogde gebruikers: als browser NL of EN is, wordt die gebruikt. Anders fallback naar EN.
- Zet browser-taal op FR (niet ondersteund). Check dat de app terugvalt op EN.
Resultaat: Beide layouts correct met juiste navigatie en routes, taalwissel werkt zonder reload, voorkeur persistent over sessies, browser-taal fallback werkt.
S-0.7 CI/CD pipeline
Section titled “S-0.7 CI/CD pipeline”Push naar main triggert automatische deploys.
Dekt: 0.6.1
Voorwaarden: GitHub Actions geconfigureerd
- Push een kleine wijziging naar
apps/web/. Check dat alleen web deploy start (naar Cloudflare Pages). - Push een wijziging naar
apps/api/. Check dat alleen API deploy start (naar Cloudflare Workers). - Push een wijziging naar
apps/docs/. Check dat alleen docs deploy start (naar Cloudflare Pages). - Controleer dat path filtering werkt (geen onnodige deploys)
- Open een PR. Check dat typecheck en lint als quality gate draaien.
- Controleer dat alle drie deploys succesvol zijn op Cloudflare
Resultaat: Drie onafhankelijke workflows, path filtering actief, quality gate op PRs, deploys succesvol.
Edge cases
Section titled “Edge cases”EC-1 Registratie en authenticatie edge cases
Section titled “EC-1 Registratie en authenticatie edge cases”Alle foutpaden bij het aanmaken en gebruiken van accounts.
Versterkt: S-0.3, S-0.4, S-0.5
- Ga naar
/register. Registreer met een emailadres dat al bestaat. Check foutmelding: “Dit emailadres is al geregistreerd. Probeer in te loggen.” (link naar/login). - Registreer met ongeldig emailformat (bijv. “test@”). Check inline validatiefout: “Voer een geldig emailadres in.”
- Registreer met naam korter dan 2 karakters. Check inline validatiefout.
- Registreer met wachtwoord korter dan 8 tekens. Check foutmelding: “Wachtwoord moet minimaal 8 karakters zijn.”
- Registreer maar sluit browser voor bevestiging. Check dat registratie niet wordt afgerond.
- Gebruik verlopen magic link (>1 uur). Check foutmelding, niet een 500 error.
- Gebruik dezelfde magic link twee keer. Tweede keer geweigerd.
- Verstuur API request met verlopen JWT. Moet 401 geven, niet 500.
- Verstuur API request met JWT van klant A voor data van klant B. Moet 403 of lege response geven (IDOR check).
- Klant probeert admin-only API route te benaderen. Moet 403 geven.
- Medewerker met rol “trainer” probeert admin-only actie (bijv. dienst aanmaken). Geblokkeerd.
- Check dat
/payments/webhookgeen auth vereist (AC 0.3.4) - Server error bij registratie (bijv. database down). Check generieke foutmelding: “Er ging iets mis. Probeer het later opnieuw.”
- Na login, laat de sessie verlopen (of verwijder de token). Check redirect naar
/login.
Resultaat: Alle foutpaden geven duidelijke, generieke meldingen zonder interne details. Verlopen magic links en sessies leiden tot correcte redirects.