# đ Bouwplan â Auth Flow Incrementele Uitbreiding
**Projectnaam:** Mini EPD - Auth Features Toevoegen
**Versie:** v1.0 (Incrementeel)
**Datum:** 18-01-2025
**Auteur:** Colin (met Claude Code)
**Scope:** Alleen TOEVOEGEN wat ontbreekt (geen refactor van bestaande code)
---
## 1. Wat Hebben We Al? â
**Bestaande Features (BLIJVEN ZOALS ZE ZIJN):**
- â
Login page met split-screen design (bento grid + form)
- â
Magic Link login (signup + login in ĂŠĂŠn)
- â
Password login (demo accounts)
- â
Quick demo button (auto-fill + submit)
- â
Toggle tussen magic/demo
- â
Success/error messaging
- â
Auth callback handler (`/auth/callback`)
- â
Logout handler (`/auth/logout`)
- â
Middleware (route protection)
- â
Supabase integration
**Wat Ontbreekt:**
- â Password reset flow (forgot password)
- â Set password optie (na magic link signup)
- â "Wachtwoord vergeten?" link op login page
---
## 2. Wat Gaan We TOEVOEGEN?
### **Minimale Toevoegingen (Production-Ready Auth):**
| Feature | Wat | Waarom | Tijd |
|---------|-----|--------|------|
| Password Reset | Forgot password â email â new password | Must-have voor production | 2 uur |
| Set Password | Optioneel password instellen na magic link | Power users willen sneller inloggen | 1 uur |
| Links Toevoegen | "Wachtwoord vergeten?" link in login form | UX improvement | 10 min |
**Totaal: ~3 uur werk**
---
## 3. Epics & Stories (Minimaal)
| Epic ID | Titel | Wat Doen We? | Stories | Tijd |
|---------|-------|--------------|---------|------|
| E1 | Password Reset Flow | 2 nieuwe pagina's + 1 email template | 3 | 2 uur |
| E2 | Set Password (Optional) | 1 nieuwe pagina + link in onboarding | 2 | 1 uur |
| E3 | UX Polish | Link toevoegen + testing | 1 | 15 min |
**Totaal: 3 uur werk, 6 stories**
---
## 4. Epic 1 â Password Reset Flow
**Wat:** Users kunnen vergeten wachtwoord resetten via email.
| Story ID | Wat Bouwen? | Bestanden | Story Points |
|----------|-------------|-----------|--------------|
| E1.S1 | Reset request page | `app/reset-password/page.tsx` (NIEUW) | 2 |
| E1.S2 | Update password page | `app/update-password/page.tsx` (NIEUW) | 3 |
| E1.S3 | Email template configureren | Supabase dashboard (config) | 1 |
### E1.S1 - Reset Request Page
**Nieuw bestand:** `app/reset-password/page.tsx`
```typescript
'use client'
import { useState } from 'react'
import { supabase } from '@/lib/supabase/client'
import Link from 'next/link'
export default function ResetPasswordPage() {
const [email, setEmail] = useState('')
const [loading, setLoading] = useState(false)
const [sent, setSent] = useState(false)
const [error, setError] = useState('')
async function handleResetRequest(e: React.FormEvent) {
e.preventDefault()
setLoading(true)
setError('')
try {
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/update-password`
})
if (error) throw error
setSent(true)
} catch (err: any) {
setError(err.message || 'Er ging iets mis')
} finally {
setLoading(false)
}
}
if (sent) {
return (
âď¸
Email Verstuurd!
Check je inbox voor de reset link. De link is 1 uur geldig.
Niet ontvangen? Check je spam folder.
â Terug naar login
)
}
return (
Wachtwoord Vergeten?
Geen probleem! Vul je email in en we sturen je een reset link.
{error && (
{error}
)}
â Terug naar login
)
}
```
### E1.S2 - Update Password Page
**Nieuw bestand:** `app/update-password/page.tsx`
```typescript
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { supabase } from '@/lib/supabase/client'
export default function UpdatePasswordPage() {
const router = useRouter()
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const [success, setSuccess] = useState(false)
async function handleUpdatePassword(e: React.FormEvent) {
e.preventDefault()
setError('')
// Validation
if (password !== confirmPassword) {
setError('Wachtwoorden komen niet overeen')
return
}
if (password.length < 8) {
setError('Wachtwoord moet minimaal 8 tekens zijn')
return
}
setLoading(true)
try {
const { error } = await supabase.auth.updateUser({
password
})
if (error) throw error
setSuccess(true)
setTimeout(() => router.push('/login'), 2000)
} catch (err: any) {
setError(err.message || 'Er ging iets mis')
} finally {
setLoading(false)
}
}
if (success) {
return (
â
Wachtwoord Gewijzigd!
Je wordt doorgestuurd naar de login pagina...
)
}
return (
Nieuw Wachtwoord Instellen
Kies een sterk wachtwoord (minimaal 8 tekens).
{error && (
{error}
)}
)
}
```
### E1.S3 - Email Template Configureren
**Waar:** Supabase Dashboard â Authentication â Email Templates â Reset Password
**Template:**
```html
Wachtwoord Resetten
Je hebt een wachtwoord reset aangevraagd voor je Mini EPD account.
Reset Wachtwoord
Deze link is 1 uur geldig. Heb je deze reset niet aangevraagd? Negeer deze email.
```
---
## 5. Epic 2 â Set Password (Optional)
**Wat:** Na magic link signup kunnen users een password instellen.
| Story ID | Wat Bouwen? | Bestanden | Story Points |
|----------|-------------|-----------|--------------|
| E2.S1 | Set password page | `app/set-password/page.tsx` (NIEUW) | 2 |
| E2.S2 | Link toevoegen | Update `app/auth/callback/route.ts` | 1 |
### E2.S1 - Set Password Page
**Nieuw bestand:** `app/set-password/page.tsx`
```typescript
'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import { supabase } from '@/lib/supabase/client'
export default function SetPasswordPage() {
const router = useRouter()
const [password, setPassword] = useState('')
const [confirmPassword, setConfirmPassword] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
async function handleSetPassword(e: React.FormEvent) {
e.preventDefault()
setError('')
if (password !== confirmPassword) {
setError('Wachtwoorden komen niet overeen')
return
}
if (password.length < 8) {
setError('Wachtwoord minimaal 8 tekens')
return
}
setLoading(true)
try {
const { error } = await supabase.auth.updateUser({ password })
if (error) throw error
router.push('/epd/clients')
} catch (err: any) {
setError(err.message)
} finally {
setLoading(false)
}
}
function handleSkip() {
router.push('/epd/clients')
}
return (
Stel een Wachtwoord In (Optioneel)
Met een wachtwoord kun je sneller inloggen zonder magic link.
{error && (
{error}
)}
)
}
```
### E2.S2 - Update Callback Handler
**Bestand:** `app/auth/callback/route.ts`
**Wat wijzigen:**
```typescript
// TOEVOEGEN aan einde van success flow:
if (data.user) {
// Check if new user (first login)
const isNewUser = new Date(data.user.created_at).getTime() ===
new Date(data.user.last_sign_in_at || '').getTime()
if (isNewUser) {
// Optie: redirect naar set-password voor nieuwe users
return NextResponse.redirect(`${requestUrl.origin}/set-password`)
}
// Bestaande redirect naar dashboard
return NextResponse.redirect(`${requestUrl.origin}/epd/clients`)
}
```
---
## 6. Epic 3 â UX Polish
**Wat:** Kleine verbeteringen aan bestaande login page.
| Story ID | Wat Doen? | Bestand | Story Points |
|----------|-----------|---------|--------------|
| E3.S1 | "Wachtwoord vergeten?" link toevoegen | `app/login/page.tsx` | 1 |
### E3.S1 - Forgot Password Link
**Bestand:** `app/login/page.tsx` (line ~346)
**TOEVOEGEN na password input field:**
```typescript
{/* Password Input */}
```
---
## 7. Checklist - Wat Moet Er Gebeuren?
### **Nieuwe Bestanden Aanmaken:**
- [ ] `app/reset-password/page.tsx` (E1.S1)
- [ ] `app/update-password/page.tsx` (E1.S2)
- [ ] `app/set-password/page.tsx` (E2.S1)
### **Bestaande Bestanden Wijzigen:**
- [ ] `app/login/page.tsx` - Voeg "Wachtwoord vergeten?" link toe (E3.S1)
- [ ] `app/auth/callback/route.ts` - Optionele redirect naar set-password (E2.S2)
### **Supabase Configuratie:**
- [ ] Email template configureren (E1.S3)
- [ ] Test reset email wordt verstuurd
### **Testing:**
- [ ] Test forgot password flow (request â email â reset)
- [ ] Test set password na magic link signup
- [ ] Test alle links werken
- [ ] Test error handling (wrong email, weak password, etc.)
---
## 8. Implementatie Volgorde
**Stap 1:** Password Reset (E1) - 2 uur
1. Maak `reset-password/page.tsx`
2. Maak `update-password/page.tsx`
3. Configureer email template in Supabase
4. Test hele flow
**Stap 2:** Set Password (E2) - 1 uur
1. Maak `set-password/page.tsx`
2. Update `auth/callback/route.ts`
3. Test flow
**Stap 3:** UX Polish (E3) - 15 min
1. Voeg "Wachtwoord vergeten?" link toe
2. Final testing
**Totaal: ~3 uur werk**
---
## 9. Testing Checklist
| Test Case | Scenario | Expected |
|-----------|----------|----------|
| TC1 | Click "Wachtwoord vergeten?" | Redirect naar /reset-password |
| TC2 | Submit valid email for reset | Email sent, success message |
| TC3 | Click reset link in email | Redirect naar /update-password |
| TC4 | Set new password (valid) | Success, redirect to login |
| TC5 | Set new password (mismatch) | Error: "Wachtwoorden komen niet overeen" |
| TC6 | Set new password (too short) | Error: "Minimaal 8 tekens" |
| TC7 | Magic link signup (new user) | Redirect naar /set-password |
| TC8 | Skip set password | Redirect naar /epd/clients |
| TC9 | Set password after signup | Success, redirect to dashboard |
---
## 10. Wat NIET Doen
â **Bestaande login page NIET refactoren**
â **GEEN nieuwe UI components maken** (gebruik bestaande styling)
â **GEEN email verification** (nice-to-have, niet kritiek)
â **GEEN OAuth/SSO** (overkill voor prototype)
â **GEEN complexe state management** (useState is prima)
---
## 11. Definition of Done
â
**E1-E3 compleet wanneer:**
- 3 nieuwe pagina's werken (reset-password, update-password, set-password)
- "Wachtwoord vergeten?" link zichtbaar op login page
- Email template geconfigureerd in Supabase
- Alle flows getest en werkend
- Geen breaking changes aan bestaande auth
- Git commit: `feat: Add password reset and set password flows`
---
**Status:** âł Ready for Implementation
**Geschatte Tijd:** 3 uur
**Next Step:** Maak eerst `app/reset-password/page.tsx`