fix: les 9

This commit is contained in:
2026-04-22 07:05:35 +02:00
parent d5599a601c
commit 4606e96dcc
9 changed files with 3125 additions and 763 deletions

View File

@@ -1,305 +1,116 @@
# Les 8: Supabase: Auth & CRUD
# Les 8: Van In-Memory naar Supabase (Self-Paced + /create)
---
## Hoofdstuk
**Deel 2: Technical Foundations** (Les 4-8)
**Deel 2: Technical Foundations** (Les 4-9)
## Beschrijving
Supabase Authentication en CRUD operaties. Implementeer email/password auth, JWT tokens, Row Level Security (RLS) policies, realtime subscriptions en volledige CRUD functionaliteit in je full-stack app.
Vervolg op Les 7. Studenten kregen vorige les niet alles af, dus loopt de docent de Supabase-koppeling rustig opnieuw door — nu in een **self-paced PDF** met copy-paste blokken en TODO-blokken. Daarna bouwen studenten zelfstandig de **/create pagina** (hun eerste INSERT).
**Aanpak:** Deel 1-3 doet de docent klassikaal door de PDF heen. Deel 4 (de /create pagina) doen studenten zelfstandig met de docent als coach.
---
## Te Behandelen
## Lesopbouw (3 uur)
### Wat is Supabase?
**Supabase = Database + Auth in één**
- PostgreSQL database (gratis tier: 500MB)
- Ingebouwde authenticatie
- Real-time subscriptions
- File storage
- Auto-generated API
**Waarom Supabase voor beginners:**
- Geen eigen server nodig
- Visuele Table Editor (geen SQL kennis nodig)
- Simpele JavaScript SDK
- Gratis tier is ruim voldoende
| Tijd | Onderwerp | Vorm |
|------|-----------|------|
| 09:0009:15 | Welkom + Intro + PDF uitdelen | Klassikaal |
| 09:1509:45 | **PDF Deel 1** — Setup (npm, .env, supabase.ts, types, vote_option SQL) | Klassikaal |
| 09:4510:00 | **PDF Deel 2** — Queries (`getPolls`, `getPollById`, `votePoll`) | Klassikaal |
| 10:0010:15 | **PDF Deel 3** — Componenten (page, PollItem, VoteForm, [id]) | Klassikaal |
| 10:1510:30 | Pauze | — |
| 10:3010:45 | Uitleg INSERT theorie + RLS policy + start Deel 4 | Klassikaal |
| 10:4511:30 | **PDF Deel 4** — /create pagina bouwen | **Zelfstandig** |
| 11:3012:00 | Vragen + Huiswerk + Vooruitblik Auth | Klassikaal |
---
### Supabase Project Aanmaken
## Lesopdracht (PDF)
Studenten krijgen één PDF met vier delen. Grijze blokken zijn copy-paste, gele TODO-blokken vullen ze zelf in.
**Stap 1:** Ga naar [supabase.com](https://supabase.com) en maak account
### Deel 1 — Setup (klassikaal)
1. `npm install @supabase/supabase-js`
2. `.env.local` met SUPABASE URL + ANON KEY
3. `lib/supabase.ts` client
4. `types/index.ts` updaten (`Poll`, `Option`)
5. **vote_option SQL functie** aanmaken in Supabase SQL Editor (voorkomt PGRST202 error)
**Stap 2:** Klik "New Project"
- Naam: `todo-app`
- Database Password: (bewaar deze!)
- Region: `West EU (Frankfurt)` (dichtst bij NL)
### Deel 2 — Queries (klassikaal, TODO's invullen)
- `getPolls()``select("*, options(*)")`
- `getPollById(id)``eq("id", id).single()`
- `votePoll(optionId)``rpc("vote_option", { option_id })`
**Stap 3:** Wacht ~2 minuten tot project klaar is
### Deel 3 — Componenten (klassikaal, copy-paste)
- `app/page.tsx` (async Server Component)
- `components/PollItem.tsx` (Client, percentage bars)
- `components/VoteForm.tsx` (Client)
- `app/poll/[id]/page.tsx` (Server Component, **Next.js 15 `params` is een Promise**)
**Stap 4:** Ga naar Settings → API en kopieer:
- `Project URL`
- `anon public` key
### Deel 4 — /create pagina (zelfstandig)
1. RLS INSERT policy voor `polls` en `options`
2. INSERT theorie (poll inserten → id terugkrijgen → options met `poll_id`)
3. `app/create/page.tsx` — volledig formulier in PDF, alleen `handleSubmit` TODO invullen
---
### Je Database Schema Implementeren
In Les 7 heb je een database schema ontworpen. Nu gaan we dat implementeren!
**In Supabase Dashboard → Table Editor:**
1. Klik "New Table"
2. Gebruik je schema uit Les 7
3. Voeg kolommen toe met de juiste types
4. Definieer Primary Keys en Foreign Keys
**Voorbeeld: todos tabel**
| Name | Type | Default | Primary |
|------|------|---------|---------|
| id | int8 | - | ✓ (auto) |
| title | text | - | |
| completed | bool | false | |
| created_at | timestamptz | now() | |
---
### Environment Variables
**Wat zijn environment variables?**
- Configuratie die NIET in je code hoort
- API keys, database URLs, secrets
- Verschillend per omgeving (lokaal vs productie)
**Maak `.env.local` in je project root:**
```bash
# .env.local - NOOIT committen naar Git!
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
```
**Maak ook `.env.example` (WEL committen):**
```bash
# .env.example - template voor anderen
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
```
---
### Supabase SDK Installeren
```bash
npm install @supabase/supabase-js
```
**Maak `src/lib/supabase.ts`:**
```typescript
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
```
---
### CRUD Operaties
**C - Create (toevoegen):**
```typescript
const { data, error } = await supabase
.from('todos')
.insert({ title: 'Nieuwe taak' })
```
**R - Read (ophalen):**
```typescript
const { data, error } = await supabase
.from('todos')
.select('*')
.order('created_at', { ascending: false })
```
**U - Update (wijzigen):**
```typescript
const { data, error } = await supabase
.from('todos')
.update({ completed: true })
.eq('id', todoId)
```
**D - Delete (verwijderen):**
```typescript
const { error } = await supabase
.from('todos')
.delete()
.eq('id', todoId)
```
---
### Authenticatie met Auth UI
**Installeer auth packages:**
```bash
npm install @supabase/auth-ui-react @supabase/auth-ui-shared
```
**Login component:**
```tsx
import { Auth } from '@supabase/auth-ui-react'
import { ThemeSupa } from '@supabase/auth-ui-shared'
import { supabase } from '@/lib/supabase'
export function LoginForm() {
return (
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
providers={[]}
magicLink={true}
/>
)
}
```
**Huidige user checken:**
```typescript
const { data: { user } } = await supabase.auth.getUser()
if (user) {
// User is ingelogd
console.log('Logged in as:', user.email)
} else {
// Redirect naar login
}
```
---
### Deployment naar Vercel
**Stap 1: Push naar GitHub**
```bash
git add .
git commit -m "Add Supabase integration"
git push
```
**Stap 2: Deploy op Vercel**
1. Ga naar [vercel.com](https://vercel.com)
2. "Add New Project"
3. Import je GitHub repo
4. **BELANGRIJK:** Voeg Environment Variables toe!
- `NEXT_PUBLIC_SUPABASE_URL`
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
5. Klik "Deploy"
**Stap 3: Supabase Redirect URLs**
1. Ga naar Supabase → Authentication → URL Configuration
2. Voeg toe bij "Redirect URLs":
- `https://jouw-app.vercel.app/**`
## Belangrijke leermomenten
- **Self-paced PDF werkt beter dan live coding** voor deze klas — studenten kunnen op eigen tempo
- **Next.js 15 breaking change:** `params` is nu een `Promise<{ id: string }>`. Je moet `const { id } = await params`
- **Supabase RPC functies:** `vote_option` aanmaken in SQL Editor — anders PGRST202 error
- **RLS policies:** Zonder INSERT policy faalt elke `.insert()` met "row-level security violation"
- **Server vs Client Components:** Server haalt data (`async` + `await`), Client doet interactie (`'use client'` + `useState`)
---
## Tools
- Supabase
- Next.js
- OpenCode/WebStorm
- Vercel
- Git
- Next.js 15
- Supabase (SQL Editor, Table Editor, RLS)
- `@supabase/supabase-js`
- TypeScript
- Cursor / VS Code
---
## Lesopdracht (2 uur)
## Huiswerk
**Verplicht:**
- /create pagina afmaken (als niet klaar)
- Validatie toevoegen (vraag niet leeg, minimaal 2 opties)
### Bouw een Todo App met Supabase
**Groepsdiscussie (15 min):**
Bespreek klassikaal de database schemas uit Les 7 - wie heeft welke structuur gekozen en waarom?
**Deel 1: Supabase Setup (30 min)**
1. Maak Supabase account en project
2. Maak je tabellen via Table Editor (gebaseerd op Les 7 schema)
3. Kopieer credentials
4. Installeer `@supabase/supabase-js`
5. Maak `src/lib/supabase.ts`
6. Configureer `.env.local`
Test: `npm run dev` werkt zonder errors
**Deel 2: CRUD Interface (1 uur)**
Bouw UI voor todos:
1. Lijst van todos tonen
2. Form om nieuwe todo toe te voegen
3. Checkbox om todo af te vinken
4. Delete button per todo
Gebruik AI hulp voor de components!
**Deel 3: Authenticatie (30 min)**
1. Installeer auth packages
2. Maak login pagina met Auth UI
3. Toon alleen app voor ingelogde users
4. Test: login met magic link
### Deliverable
- Werkende Todo app lokaal
- GitHub repository met code
- Screenshot van werkende app
**Extra:**
- Delete functionaliteit
- SQL queries direct testen in Supabase
- Realtime subscriptions uitproberen
- Styling polish
---
## Huiswerk (2 uur)
### Deploy naar Productie + Uitbreiden
**Deel 1: Deployment (30 min)**
1. Push naar GitHub
2. Deploy naar Vercel
3. Configureer env vars in Vercel
4. Voeg Vercel URL toe aan Supabase Redirect URLs
5. Test: app werkt op productie URL!
**Deel 2: Features Uitbreiden (1 uur)**
Voeg toe:
1. Filter buttons: Alle / Actief / Voltooid
2. Sorteer op datum (nieuwste eerst)
3. Loading state tijdens data ophalen
4. Error state bij problemen
5. Empty state: "Geen todos gevonden"
**Deel 3: Polish (30 min)**
1. Styling verbeteren met Tailwind
2. Responsive design (mobile friendly)
3. Kleine animaties (fade in/out)
### Deliverable
- Deployed app op Vercel (werkende URL!)
- Alle features werken in productie
- Screenshot van productie app
## Lesmateriaal
- `Les08-Slide-Overzicht.md`
- `Les08-Docenttekst.md`
- `Les08-Lesopdracht.pdf` (de self-paced handleiding)
- `Les08-Slides.pptx`
---
## Leerdoelen
Na deze les kan de student:
- Een Supabase project aanmaken en configureren
- Database schema implementeren via Table Editor
- Environment variables correct beheren
- De Supabase client installeren en configureren
- CRUD operaties uitvoeren met de Supabase SDK
- Authenticatie implementeren met Auth UI
- Deployen naar Vercel met environment variables
- Database principles uit Les 7 toepassen in de praktijk
- De Supabase JavaScript client installeren en configureren
- Environment variables gebruiken voor API keys
- Data ophalen via Supabase queries (`select` met relaties, `eq`, `single`)
- Een PostgreSQL function aanroepen via `.rpc()`
- Het verschil uitleggen tussen Server en Client Components in Next.js 15
- Een formulier bouwen dat data INSERT in Supabase
- RLS policies schrijven voor publieke read en insert
- Veelvoorkomende Supabase errors herkennen en oplossen (PGRST202, RLS violation)
---
## Voorbereiding docent
- [ ] QuickPoll project werkt lokaal op localhost:3000
- [ ] Supabase project met `polls` + `options` tabellen
- [ ] `vote_option` RPC functie aangemaakt
- [ ] SELECT RLS policies staan aan
- [ ] Lesopdracht PDF gedeeld met studenten (digitaal)
- [ ] Whiteboard voor de vier query-patronen