208 lines
6.8 KiB
Markdown
208 lines
6.8 KiB
Markdown
# Les 8 — Docenttekst
|
||
## Van In-Memory naar Supabase
|
||
|
||
---
|
||
|
||
## Lesoverzicht
|
||
|
||
| Gegeven | Details |
|
||
|---------|---------|
|
||
| **Les** | 8 van 18 |
|
||
| **Onderwerp** | Supabase koppelen aan Next.js |
|
||
| **Duur** | 3 uur (09:00 – 12:00) |
|
||
| **Voorbereiding** | Werkend QuickPoll project, Supabase project met polls/options tabellen |
|
||
| **Benodigdheden** | Laptop, Cursor/VS Code, browser, Supabase account |
|
||
| **Lesmateriaal** | Lesopdracht PDF (studenten werken hier zelfstandig doorheen) |
|
||
|
||
## Leerdoelen
|
||
|
||
Na deze les kunnen studenten:
|
||
1. De Supabase JavaScript client installeren en configureren
|
||
2. Environment variables gebruiken voor API keys
|
||
3. Data ophalen via Supabase queries (select met relaties, eq, single)
|
||
4. Het verschil uitleggen tussen Server Components en Client Components
|
||
5. Een formulier bouwen dat data INSERT in Supabase
|
||
|
||
---
|
||
|
||
## Aanpak
|
||
|
||
Studenten krijgen een **Lesopdracht PDF** met alle component-code (volledige UI). Ze hoeven alleen de **Supabase queries** zelf te schrijven (gemarkeerd als TODO-blokken). De docent legt concepten uit met slides, doet een korte demo, en loopt daarna rond.
|
||
|
||
---
|
||
|
||
## Lesplanning
|
||
|
||
### 09:00–09:15 | Welkom & Uitleg aanpak (15 min)
|
||
📌 Slide 1, 2, 3
|
||
|
||
**Wat te zeggen:**
|
||
- "Vorige week: werkende polling app met in-memory data."
|
||
- "Vandaag koppelen we Supabase: onze database-as-a-service."
|
||
- "Jullie werken vandaag **zelfstandig** met een PDF. Alle UI-code staat erin. Jullie schrijven de Supabase queries."
|
||
- "Ik leg eerst de concepten uit, dan gaan jullie aan de slag."
|
||
|
||
**Check:**
|
||
- Iedereen heeft Supabase account met polls en options tabellen
|
||
- Iedereen heeft QuickPoll project lokaal draaiend
|
||
- Deel de Lesopdracht PDF uit (digitaal)
|
||
|
||
---
|
||
|
||
### 09:15–09:45 | Uitleg concepten (30 min)
|
||
📌 Slide 4, 5, 6
|
||
|
||
#### 09:15 | Slide 4: Van Array naar Database
|
||
|
||
**Zeg:**
|
||
"Tot nu toe stond jullie data in een array. Dat werkt, maar is weg zodra je de server herstart. Supabase geeft ons een echte PostgreSQL database."
|
||
|
||
Toon het verschil:
|
||
```
|
||
// OUD: in-memory
|
||
const polls = [{ question: "...", votes: [0, 0] }]
|
||
|
||
// NIEUW: Supabase
|
||
supabase.from("polls").select("*, options(*)")
|
||
```
|
||
|
||
#### 09:25 | Slide 5: Supabase queries
|
||
|
||
**Toon de vier belangrijkste operaties:**
|
||
1. `.from("polls").select("*, options(*)")` → Haal alles op met relaties
|
||
2. `.eq("id", 5).single()` → Filter op 1 record
|
||
3. `.insert({ question })` → Nieuw record toevoegen
|
||
4. `.rpc("vote_option", { option_id })` → Database functie aanroepen
|
||
|
||
**Demo:** Open Supabase dashboard, toon Table Editor met polls en options tabel. Laat de relatie zien (foreign key).
|
||
|
||
#### 09:35 | Slide 6: Server vs Client
|
||
|
||
**Zeg:**
|
||
"Belangrijk patroon: Server Components zijn `async` — die halen data op. Client Components hebben `'use client'` — die zijn interactief (forms, klikken). In de PDF zien jullie dit terug."
|
||
|
||
---
|
||
|
||
### 09:45–10:15 | Deel 1: Setup + Queries (30 min, zelfstandig)
|
||
📌 Slide 5 (blijft staan als referentie)
|
||
|
||
**Zeg:**
|
||
"Open de Lesopdracht PDF. Werk Deel 1, 2 en 3 door. Dat is de setup, queries schrijven, en componenten kopiëren. Na de pauze doen we Deel 4: de /create pagina."
|
||
|
||
**Studenten doen nu:**
|
||
- Deel 1 (PDF): npm install, .env, supabase client, types
|
||
- Deel 2 (PDF): lib/data.ts — TODO blokken invullen (getPolls, getPollById, votePoll)
|
||
- Deel 3 (PDF): Componenten kopiëren (page.tsx, PollItem, VoteForm, poll/[id])
|
||
|
||
**Jij loopt rond. Veelvoorkomende issues:**
|
||
|
||
| Probleem | Oplossing |
|
||
|----------|-----------|
|
||
| npm install failed | Check internet, node_modules verwijderen en opnieuw |
|
||
| Env vars undefined | NEXT_PUBLIC_ prefix? Dev server herstart? |
|
||
| getPolls() returns [] | Query syntax checken. Staat er data in Supabase? |
|
||
| TypeScript errors | Import vergeten? Types kloppen met database? |
|
||
| "RLS policy violation" | RLS uitschakelen of SELECT policy toevoegen |
|
||
|
||
**Check-in (10:00):**
|
||
"Wie heeft de homepage al werkend met Supabase data? Steek je hand op."
|
||
→ Als minder dan de helft: kort voordoen op beamer.
|
||
→ Als meer dan de helft: doorgaan, help de rest individueel.
|
||
|
||
---
|
||
|
||
### 10:15–10:30 | PAUZE (15 min)
|
||
📌 Slide 7
|
||
|
||
---
|
||
|
||
### 10:30–10:45 | Uitleg INSERT + /create (15 min)
|
||
📌 Slide 8
|
||
|
||
**Zeg:**
|
||
"Nu gaan jullie een /create pagina bouwen. Het formulier staat al in de PDF — jullie schrijven alleen de INSERT logica."
|
||
|
||
**Toon op beamer:**
|
||
```typescript
|
||
// 1. Insert poll
|
||
const { data: poll } = await supabase
|
||
.from("polls")
|
||
.insert({ question: "Mijn vraag" })
|
||
.select()
|
||
.single();
|
||
|
||
// 2. Insert options met poll.id
|
||
await supabase.from("options").insert([
|
||
{ poll_id: poll.id, text: "Optie A", votes: 0 },
|
||
{ poll_id: poll.id, text: "Optie B", votes: 0 },
|
||
]);
|
||
```
|
||
|
||
**Zeg:**
|
||
- "Eerst insert je de poll → je krijgt het id terug"
|
||
- "Dan insert je de options met dat poll_id"
|
||
- "En dan redirect je naar de homepage"
|
||
|
||
**RLS policy:**
|
||
"Voordat het werkt: voeg INSERT policies toe. Staat in Deel 4, Stap 4.1 van de PDF."
|
||
|
||
---
|
||
|
||
### 10:45–11:30 | Deel 2: /create pagina (45 min, zelfstandig)
|
||
|
||
**Studenten doen nu:**
|
||
- Deel 4 (PDF): RLS policy toevoegen, handleSubmit implementeren
|
||
- Testen: poll aanmaken → verschijnt op homepage
|
||
|
||
**Jij loopt rond. Veelvoorkomende issues:**
|
||
|
||
| Probleem | Oplossing |
|
||
|----------|-----------|
|
||
| "RLS policy violation" bij INSERT | SQL policy uitgevoerd in dashboard? |
|
||
| poll is undefined na insert | .select().single() vergeten? |
|
||
| Opties worden niet opgeslagen | poll.id doorgeven aan options insert? |
|
||
| Form refresht de pagina | e.preventDefault() in handleSubmit? |
|
||
| Redirect werkt niet | useRouter van "next/navigation"? |
|
||
|
||
**Check-in (11:15):**
|
||
"Wie heeft succesvol een poll aangemaakt? Open Supabase dashboard en toon dat ie erin staat."
|
||
→ Toon op beamer als demo.
|
||
|
||
---
|
||
|
||
### 11:30–11:45 | Vragen & Reflectie (15 min)
|
||
|
||
**Mogelijke vragen:**
|
||
|
||
**V: Waarom async/await?**
|
||
A: Supabase is over het netwerk. We moeten wachten op antwoord.
|
||
|
||
**V: Wat is het verschil tussen Server en Client Component?**
|
||
A: Server = async, data fetching, geen interactiviteit. Client = 'use client', useState, onClick.
|
||
|
||
**V: Kan ik realtime updates zien?**
|
||
A: Later! Supabase heeft realtime subscriptions.
|
||
|
||
---
|
||
|
||
### 11:45–12:00 | Huiswerk & Afsluiting (15 min)
|
||
📌 Slide 9, 10
|
||
|
||
**Huiswerk:**
|
||
1. /create pagina afmaken (als niet klaar)
|
||
2. Validatie: vraag niet leeg, min 2 opties, foutmeldingen
|
||
3. Extra: delete functionaliteit, styling
|
||
|
||
**Slide 10: Afsluiting**
|
||
"Volgende les: Supabase Auth. Inloggen, registreren, en bepalen wie wat mag. Tot dan!"
|
||
|
||
---
|
||
|
||
## Tips voor docenten
|
||
|
||
1. **Niet te veel voordoen.** De PDF is self-contained. Studenten leren meer door zelf te doen.
|
||
2. **Loop ronde, spot problemen vroeg.** De eerste 10 minuten na "ga aan de slag" zijn cruciaal.
|
||
3. **Check-ins doen.** Vraag om handopsteken. Als <50% het heeft: kort voordoen.
|
||
4. **Toon Supabase dashboard.** "Zie je? De data staat echt in de database!"
|
||
5. **Authenticatie is volgende les.** Zeg het af en toe, zodat ze weten dat RLS nog tijdelijk is.
|