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,372 +1,105 @@
# Les 7: Database Principles
# Les 7: Van In-Memory naar Supabase (Introductie)
---
## Hoofdstuk
**Deel 2: Technical Foundations** (Les 4-8)
**Deel 2: Technical Foundations** (Les 4-9)
## Beschrijving
Leer de basisprincipes van relationele databases voordat we Supabase gaan gebruiken. Begrijp tabellen, relaties, keys en normalisatie - essentiële kennis voor elke developer.
Eerste kennismaking met Supabase. Studenten maken hun QuickPoll uit Les 6 af, leren wat een relationele database is via de Supabase GUI (geen SQL nodig), en koppelen voor het eerst een echte database aan hun Next.js app.
> **Reflectie na geven:** Te veel materiaal voor één les. Studenten kwamen niet door Deel 3 heen. Daarom is Les 8 toegevoegd waarin de Supabase-koppeling rustig opnieuw wordt doorlopen, plus een /create pagina.
---
## Te Behandelen
## Lesopbouw
### Wat is een Relationele Database?
### Deel 1 — Poll afmaken (30 min, klassikaal)
Onaffe stukken uit Les 6 wegwerken:
- `votePoll()` functie in `data.ts`
- POST route die echt verwerkt (geen `console.log` meer)
- **Server Component + VoteForm split** — kernmoment van de les
- GET route + visuele percentage bars in `PollItem`
**Een database is:** Een georganiseerde verzameling van data.
### Deel 2 — Supabase Introductie, No Code (45 min)
Voor de meeste studenten hun eerste database ervaring.
- Wat is Supabase? Open-source Firebase alternatief op Postgres
- Project aanmaken (via GitHub login)
- `polls` tabel aanmaken via Table Editor (id, question, created_at)
- `options` tabel aanmaken met foreign key naar polls (CASCADE)
- RLS policies uitleggen en SELECT policies aanzetten
- Testdata invoeren via de GUI
- SQL Editor: eerste `SELECT`, `WHERE` en `JOIN` query
**Relationeel betekent:** Data is opgeslagen in tabellen die aan elkaar gerelateerd zijn.
### Pauze (15 min)
**Vergelijk het met Excel:**
- Database = Excel workbook
- Tabel = Excel sheet
- Kolom = Excel kolom (field)
- Rij = Excel rij (record)
### Deel 3 — Supabase koppelen aan Next.js (60 min)
- `npm install @supabase/supabase-js`
- `.env.local` met `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY`
- `lib/supabase.ts` client
- Types updaten (`Poll`, `Option`)
- `data.ts` herschrijven met Supabase queries (`select`, `eq`, `single`)
- Homepage async maken
- `PollItem`, `VoteForm`, detailpagina aanpassen
- Testen op localhost — data overleeft restart
### Vragen + Huiswerk (15 min)
**Huiswerk:** /create pagina bouwen (formulier → INSERT in Supabase) — voor de meeste studenten te zwaar gebleken, daarom in Les 8 herhaald.
---
### Tabellen, Kolommen en Rijen
**Voorbeeld: Users tabel**
| id | name | email | created_at |
|----|------|-------|------------|
| 1 | Tim | tim@email.com | 2024-01-15 |
| 2 | Anna | anna@email.com | 2024-01-16 |
| 3 | Jan | jan@email.com | 2024-01-17 |
**Terminologie:**
- **Tabel:** users
- **Kolommen:** id, name, email, created_at
- **Rijen:** 3 records (Tim, Anna, Jan)
- **Cell:** Eén specifieke waarde (bijv. "tim@email.com")
---
### Data Types
Elke kolom heeft een type:
| Type | Beschrijving | Voorbeeld |
|------|--------------|-----------|
| `text` / `varchar` | Tekst | "Tim", "Hello world" |
| `integer` / `int` | Hele getallen | 1, 42, -5 |
| `decimal` / `numeric` | Decimalen | 19.99, 3.14 |
| `boolean` | True/False | true, false |
| `timestamp` | Datum + tijd | 2024-01-15 14:30:00 |
| `uuid` | Unieke identifier | a1b2c3d4-e5f6-... |
**Kies het juiste type:**
- Prijs? → `decimal` (niet `integer`, want centen)
- Is actief? → `boolean`
- Naam? → `text`
- Aantal? → `integer`
---
### Primary Keys
**Wat:** Een kolom die elke rij UNIEK identificeert.
**Regels:**
- Moet uniek zijn per rij
- Mag nooit NULL zijn
- Verandert nooit
**Voorbeeld:**
```
users
------
id (PRIMARY KEY) | name | email
1 | Tim | tim@email.com
2 | Anna | anna@email.com
```
**Waarom niet `email` als primary key?**
- Emails kunnen veranderen
- `id` is stabiel en snel
---
### Foreign Keys
**Wat:** Een kolom die verwijst naar de primary key van een andere tabel.
**Voorbeeld: Posts tabel**
```
posts
------
id | title | user_id (FOREIGN KEY → users.id)
1 | "Mijn blog" | 1
2 | "Hello world" | 1
3 | "Tips" | 2
```
**Wat zegt dit?**
- Post 1 en 2 zijn van user 1 (Tim)
- Post 3 is van user 2 (Anna)
---
### Relatie Types
**One-to-Many (1:N)** - Meest voorkomend!
```
Eén user → meerdere posts
Eén category → meerdere products
```
**One-to-One (1:1)** - Zeldzaam
```
Eén user → één profile
```
**Many-to-Many (N:N)** - Via tussentabel
```
Posts ↔ Tags (een post heeft meerdere tags, een tag heeft meerdere posts)
```
---
### One-to-Many Voorbeeld
```
users posts
------ ------
id | name id | title | user_id
1 | Tim ←────────── 1 | "Blog 1" | 1
2 | Anna ←────┬───── 2 | "Blog 2" | 1
└───── 3 | "Tips" | 2
```
**Lees:** Tim heeft 2 posts, Anna heeft 1 post.
---
### Many-to-Many met Tussentabel
```
posts post_tags tags
------ --------- ------
id | title post_id | tag_id id | name
1 | "React tips" 1 | 1 1 | "react"
2 | "CSS guide" 1 | 2 2 | "frontend"
2 | 2 3 | "css"
2 | 3
```
**Lees:**
- Post 1 heeft tags: react, frontend
- Post 2 heeft tags: frontend, css
---
### Normalisatie Basics
**Probleem: Data duplicatie**
```
orders (SLECHT)
------
id | customer_name | customer_email | product_name | price
1 | Tim | tim@email.com | Laptop | 999
2 | Tim | tim@email.com | Phone | 699
3 | Anna | anna@email.com | Laptop | 999
```
**Problemen:**
- Tim's email staat 2x (als hij verandert: 2 plekken updaten)
- "Laptop" en prijs staan 2x
---
### Genormaliseerde Versie
```
users products orders
------ -------- ------
id | name | email id | name | price id | user_id | product_id
1 | Tim | tim@... 1 | Laptop | 999 1 | 1 | 1
2 | Anna | anna@... 2 | Phone | 699 2 | 1 | 2
3 | 2 | 1
```
**Voordelen:**
- Elk gegeven staat 1x
- Update op 1 plek
- Minder opslagruimte
---
### NULL Values
**NULL = "geen waarde" (niet 0, niet "")**
```
users
------
id | name | phone
1 | Tim | 0612345678
2 | Anna | NULL ← Geen telefoon bekend
```
**Wanneer NULL toestaan?**
- Optionele velden (phone, description)
- Niet bij verplichte velden (name, email)
---
### Defaults
**Automatische waarde als je niks opgeeft:**
```
todos
------
id | title | completed | created_at
| | DEFAULT: false | DEFAULT: now()
```
Bij `INSERT INTO todos (title) VALUES ('Test')`:
```
id | title | completed | created_at
1 | Test | false | 2024-01-15 10:30:00
```
---
### Database Schema Tekenen
**Tools:** draw.io, Excalidraw, pen en papier
**Conventie:**
```
┌──────────────┐ ┌──────────────┐
│ users │ │ posts │
├──────────────┤ ├──────────────┤
│ id (PK) │───┐ │ id (PK) │
│ name │ │ │ title │
│ email │ └────→│ user_id (FK) │
│ created_at │ │ content │
└──────────────┘ │ created_at │
└──────────────┘
```
PK = Primary Key
FK = Foreign Key
Pijl = Relatie richting
## Kernconcepten
- Server Component vs Client Component patroon
- Database-as-a-service (Supabase = Postgres + Auth + REST + Realtime)
- Tabellen, kolommen, primary keys, foreign keys, CASCADE
- Row Level Security (RLS) basics
- Environment variables in Next.js (`NEXT_PUBLIC_` prefix)
- Supabase JavaScript client: `from`, `select`, `eq`, `single`
---
## Tools
- Pen en papier / Excalidraw / draw.io
- Supabase Table Editor (vooruitblik)
- Next.js 15
- Supabase (Table Editor, SQL Editor)
- Cursor / VS Code
- TypeScript
- `@supabase/supabase-js`
---
## Lesopdracht (2 uur)
## Lesopdracht
Volg de docent klassikaal mee door Deel 1 → 3. Aan het eind draait je QuickPoll app met data uit Supabase.
### Database Design Oefening
**Deel 1: Blog Database Ontwerpen (45 min)**
Ontwerp een database voor een blog met:
- Users (kunnen posts schrijven)
- Posts (hebben een auteur)
- Comments (op posts, door users)
Voor elke tabel:
1. Teken de tabel met kolommen
2. Bepaal data types
3. Markeer Primary Keys
4. Markeer Foreign Keys
5. Teken de relaties
**Deel 2: Normalisatie Oefening (30 min)**
Gegeven deze "slechte" tabel:
```
library
-------
book_title | author_name | author_email | borrower_name | borrowed_date
"1984" | "Orwell" | orwell@... | "Tim" | 2024-01-15
"1984" | "Orwell" | orwell@... | "Anna" | 2024-01-10
"Dune" | "Herbert" | herbert@... | "Tim" | 2024-01-12
```
Normaliseer naar aparte tabellen:
1. Welke entiteiten zie je?
2. Maak aparte tabellen
3. Voeg relaties toe
**Deel 3: Eindproject Schema (45 min)**
Ontwerp het database schema voor jouw eindproject:
1. Welke entiteiten heb je nodig?
2. Teken elke tabel met kolommen
3. Bepaal relaties
4. Documenteer je keuzes
### Deliverable
- Blog database schema (tekening)
- Genormaliseerde library database
- Eindproject database schema
## Huiswerk
- /create pagina afmaken (formulier dat een nieuwe poll insert)
- Validatie toevoegen
- Eventueel: extra SQL queries proberen
---
## Huiswerk (2 uur)
### Verdieping en Voorbereiding
**Deel 1: Eindproject Schema Uitwerken (1 uur)**
Werk je database schema volledig uit:
1. **Per tabel:**
- Naam
- Alle kolommen met data types
- Primary key
- Foreign keys
- Defaults
- Nullable fields
2. **Documenteer:**
- Waarom deze structuur?
- Welke relaties?
- Eventuele alternatieve overwegingen
**Deel 2: Supabase Account (30 min)**
Bereid je voor op volgende les:
1. Maak account op [supabase.com](https://supabase.com)
2. Verken de interface
3. Bekijk de Table Editor
**Deel 3: Reflectie (30 min)**
Beantwoord deze vragen (kort):
1. Wat is het verschil tussen primary en foreign key?
2. Waarom normaliseren we data?
3. Wanneer gebruik je one-to-many vs many-to-many?
4. Welke tabellen heeft jouw eindproject nodig?
### Deliverable
- Volledig uitgewerkt database schema voor eindproject
- Supabase account aangemaakt
- Reflectie vragen beantwoord
## Lesmateriaal
- `Les07-Slide-Overzicht.md`
- `Les07-Docenttekst.md`
- `Les07-Live-Coding-Guide.md`
- `Les07-Lesopdracht.pdf`
- `Les07-Slides.pptx`
---
## Leerdoelen
Na deze les kan de student:
- Uitleggen wat een relationele database is
- Tabellen, kolommen en rijen beschrijven
- De juiste data types kiezen
- Primary keys en hun doel uitleggen
- Foreign keys en relaties begrijpen
- One-to-many en many-to-many relaties herkennen
- Het probleem van data duplicatie identificeren
- Een database normaliseren
- NULL values en defaults begrijpen
- Een database schema ontwerpen en tekenen
- Uitleggen wat Supabase is en wanneer je het inzet
- Een Supabase project aanmaken via de GUI
- Tabellen met relaties (foreign keys) aanmaken in de Table Editor
- RLS policies opzetten voor publieke read access
- De Supabase JavaScript client installeren en configureren
- Environment variables gebruiken voor API keys
- Data ophalen met `select`, `eq` en relaties (`options(*)`)
- Het Server Component + Client Component patroon toepassen
---
## Lessons Learned (voor v2)
- 3 hoofddelen in 1 les is te ambitieus voor het tempo van deze klas
- /create pagina als huiswerk werkt niet — studenten hebben begeleiding nodig bij hun eerste INSERT
- Splits Supabase introductie en concrete code-koppeling over twee lessen → **Les 8 voegt dit toe**