final lessons
This commit is contained in:
346
Les07-Supabase/Les07-Lesstof.md
Normal file
346
Les07-Supabase/Les07-Lesstof.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# Les 7 — Lesstof
|
||||
## Supabase Setup + eerste queries
|
||||
|
||||
**Vak:** Technical Foundations
|
||||
**Vorige les:** Les 6 — Next.js QuickPoll deel 2
|
||||
**Volgende les:** Les 8 — Supabase CRUD + Mutations
|
||||
|
||||
---
|
||||
|
||||
## Inhoud
|
||||
|
||||
1. [Wat is Supabase](#1-wat-is-supabase)
|
||||
2. [Supabase vs alternatieven](#2-supabase-vs-alternatieven)
|
||||
3. [Account + project aanmaken](#3-account--project-aanmaken)
|
||||
4. [Postgres basics](#4-postgres-basics)
|
||||
5. [Tabel aanmaken in Supabase](#5-tabel-aanmaken-in-supabase)
|
||||
6. [Foreign keys + relaties](#6-foreign-keys--relaties)
|
||||
7. [RLS — Row Level Security (intro)](#7-rls--row-level-security-intro)
|
||||
8. [SQL Editor — eerste queries](#8-sql-editor--eerste-queries)
|
||||
9. [Supabase client in Next.js](#9-supabase-client-in-nextjs)
|
||||
10. [Eerste SELECT vanuit Server Component](#10-eerste-select-vanuit-server-component)
|
||||
|
||||
---
|
||||
|
||||
## 1. Wat is Supabase
|
||||
|
||||
**Supabase** = open-source Backend-as-a-Service. Geef je een Postgres database + auth + storage + realtime + functions via één dashboard. Gratis tier voor leren + kleine projecten.
|
||||
|
||||
### Wat krijg je
|
||||
|
||||
- **Postgres database** — echte SQL, geen NoSQL
|
||||
- **Auth** — login, signup, magic link, social (Les 9-10)
|
||||
- **Storage** — files uploaden (later)
|
||||
- **Realtime** — subscribe op DB changes (later)
|
||||
- **Edge Functions** — serverless deno-runtime (later)
|
||||
- **Dashboard** — visuele tabel-editor, SQL editor, auth-management
|
||||
|
||||
### Open source
|
||||
|
||||
Volledige code op GitHub. Self-hostbaar als je wilt. Geen vendor lock-in.
|
||||
|
||||
---
|
||||
|
||||
## 2. Supabase vs alternatieven
|
||||
|
||||
| | Supabase | Firebase | Planetscale | Neon |
|
||||
|---|----------|----------|-------------|------|
|
||||
| Database | Postgres | NoSQL (Firestore) | MySQL | Postgres |
|
||||
| Auth | ✓ | ✓ | ✗ | ✗ |
|
||||
| Pricing | Free tier ruim | Pay-per-read | Free tier | Free tier |
|
||||
| Open source | ✓ | ✗ | ✗ | Onderdelen |
|
||||
|
||||
**Voor deze leerlijn: Supabase.** Postgres + auth + dashboard alles-in-één. Geen extra services nodig voor 90% van je app.
|
||||
|
||||
---
|
||||
|
||||
## 3. Account + project aanmaken
|
||||
|
||||
### Account
|
||||
|
||||
Ga naar supabase.com → Sign Up (mag met GitHub).
|
||||
|
||||
### Project
|
||||
|
||||
1. New project
|
||||
2. Org kiezen (default = je naam)
|
||||
3. **Naam:** `quickpoll`
|
||||
4. **Database password:** sla op (lange random string)
|
||||
5. **Region:** `Europe (Frankfurt)` voor NL gebruikers
|
||||
6. **Plan:** Free
|
||||
7. Wacht 1-2 min op provisioning
|
||||
|
||||
### Wat krijg je
|
||||
|
||||
- **Project URL:** `https://abc123.supabase.co`
|
||||
- **Anon key:** publieke API key (mag in client)
|
||||
- **Service role key:** admin key (NIET in client!)
|
||||
|
||||
Beide te vinden via Settings → API.
|
||||
|
||||
---
|
||||
|
||||
## 4. Postgres basics
|
||||
|
||||
### Wat is Postgres
|
||||
|
||||
Relationele SQL database. Sinds 1986, krachtige + betrouwbaar. Industrie-standaard.
|
||||
|
||||
### Tabellen + kolommen
|
||||
|
||||
```
|
||||
polls
|
||||
┌────┬──────────────────┬──────────────┐
|
||||
│ id │ title │ created_at │
|
||||
├────┼──────────────────┼──────────────┤
|
||||
│ 1 │ Beste taal? │ 2026-06-04 │
|
||||
│ 2 │ Beste IDE? │ 2026-06-04 │
|
||||
└────┴──────────────────┴──────────────┘
|
||||
```
|
||||
|
||||
### Veelgebruikte types
|
||||
|
||||
| Type | Wanneer |
|
||||
|------|---------|
|
||||
| `bigserial` | Auto-increment ID |
|
||||
| `uuid` | Random UUID (default `gen_random_uuid()`) |
|
||||
| `text` | Variabele tekst |
|
||||
| `integer` | Geheel getal |
|
||||
| `boolean` | true/false |
|
||||
| `timestamp` | Datum + tijd |
|
||||
| `jsonb` | JSON (queryable) |
|
||||
|
||||
### Constraints
|
||||
|
||||
- `primary key` — unieke identifier
|
||||
- `not null` — verplicht veld
|
||||
- `unique` — geen duplicaten
|
||||
- `references` — foreign key
|
||||
- `default` — automatische waarde bij niet meegegeven
|
||||
|
||||
---
|
||||
|
||||
## 5. Tabel aanmaken in Supabase
|
||||
|
||||
### Via Dashboard
|
||||
|
||||
1. Table Editor → New table
|
||||
2. Naam: `polls`
|
||||
3. Kolommen:
|
||||
- `id` — bigserial — primary key
|
||||
- `title` — text — not null
|
||||
- `created_at` — timestamp — default `now()`
|
||||
4. Save
|
||||
|
||||
### Via SQL Editor
|
||||
|
||||
```sql
|
||||
create table polls (
|
||||
id bigserial primary key,
|
||||
title text not null,
|
||||
created_at timestamp default now()
|
||||
);
|
||||
```
|
||||
|
||||
SQL is sneller + reproduceerbaar. Voor productie altijd via SQL (migrations).
|
||||
|
||||
---
|
||||
|
||||
## 6. Foreign keys + relaties
|
||||
|
||||
### Voorbeeld — polls + options
|
||||
|
||||
Een poll heeft meerdere opties. Twee tabellen, relatie via `poll_id`:
|
||||
|
||||
```sql
|
||||
create table options (
|
||||
id bigserial primary key,
|
||||
poll_id bigint not null references polls(id) on delete cascade,
|
||||
text text not null,
|
||||
votes integer default 0
|
||||
);
|
||||
```
|
||||
|
||||
`references polls(id)` = foreign key naar `polls.id`.
|
||||
`on delete cascade` = poll verwijderd → opties ook weg.
|
||||
|
||||
### One-to-many
|
||||
|
||||
`polls` → `options` (één poll, meerdere opties)
|
||||
|
||||
### Querying
|
||||
|
||||
```sql
|
||||
-- Alle polls met opties
|
||||
select p.title, o.text, o.votes
|
||||
from polls p
|
||||
join options o on o.poll_id = p.id;
|
||||
```
|
||||
|
||||
In Supabase JS:
|
||||
```typescript
|
||||
await supabase.from("polls").select("*, options(*)");
|
||||
```
|
||||
|
||||
Automatisch een join.
|
||||
|
||||
---
|
||||
|
||||
## 7. RLS — Row Level Security (intro)
|
||||
|
||||
**RLS** = Postgres-feature waarmee je per-row regels stelt over wie wat mag.
|
||||
|
||||
### Zonder RLS
|
||||
|
||||
Iedereen met je anon key kan ALLE data lezen + schrijven. Voor demo OK, voor productie disaster.
|
||||
|
||||
### Met RLS
|
||||
|
||||
Per tabel: enable RLS + maak policies.
|
||||
|
||||
```sql
|
||||
alter table polls enable row level security;
|
||||
|
||||
create policy "polls zijn publiek leesbaar"
|
||||
on polls for select using (true);
|
||||
|
||||
create policy "alleen ingelogde users mogen polls maken"
|
||||
on polls for insert with check (auth.uid() is not null);
|
||||
```
|
||||
|
||||
### Voor vandaag
|
||||
|
||||
In deze les: tabellen met RLS uit OF met open policies (`using (true)`). Dieper in Les 9-10 (auth + per-user RLS).
|
||||
|
||||
```sql
|
||||
-- Voor demo — alle access open
|
||||
alter table polls enable row level security;
|
||||
create policy "demo open" on polls for all to anon using (true) with check (true);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. SQL Editor — eerste queries
|
||||
|
||||
### Insert
|
||||
|
||||
```sql
|
||||
insert into polls (title) values ('Beste programmeertaal?')
|
||||
returning id;
|
||||
```
|
||||
|
||||
`returning id` = krijg de nieuwe id terug.
|
||||
|
||||
### Select
|
||||
|
||||
```sql
|
||||
-- Alle polls
|
||||
select * from polls;
|
||||
|
||||
-- Specifieke poll
|
||||
select * from polls where id = 1;
|
||||
|
||||
-- Sorted op nieuwste
|
||||
select * from polls order by created_at desc limit 10;
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
```sql
|
||||
update polls set title = 'Nieuwere titel' where id = 1;
|
||||
```
|
||||
|
||||
### Delete
|
||||
|
||||
```sql
|
||||
delete from polls where id = 1;
|
||||
```
|
||||
|
||||
### Aggregates
|
||||
|
||||
```sql
|
||||
select count(*) from polls;
|
||||
select count(*) as total, date_trunc('day', created_at) as day
|
||||
from polls group by day;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Supabase client in Next.js
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
pnpm add @supabase/supabase-js
|
||||
```
|
||||
|
||||
### `.env.local`
|
||||
|
||||
```
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://abc123.supabase.co
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
|
||||
```
|
||||
|
||||
`NEXT_PUBLIC_` prefix want anon key mag in client (RLS beschermt data).
|
||||
|
||||
### Client setup
|
||||
|
||||
```typescript
|
||||
// lib/supabase.ts
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
export const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
);
|
||||
```
|
||||
|
||||
In Les 9-10 vervangen we dit door SSR-safe variant (`@supabase/ssr`). Voor nu volstaat dit.
|
||||
|
||||
---
|
||||
|
||||
## 10. Eerste SELECT vanuit Server Component
|
||||
|
||||
```tsx
|
||||
// app/page.tsx
|
||||
import { supabase } from "@/lib/supabase";
|
||||
|
||||
export default async function Home() {
|
||||
const { data: polls, error } = await supabase
|
||||
.from("polls")
|
||||
.select("*")
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
if (error) return <p>Error: {error.message}</p>;
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{polls?.map((poll) => (
|
||||
<li key={poll.id}>
|
||||
<a href={`/poll/${poll.id}`}>{poll.title}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Wat hier gebeurt
|
||||
|
||||
- Server Component (geen `"use client"`)
|
||||
- `await supabase.from(...).select()` rechtstreeks in component
|
||||
- Server fetcht data, returnt HTML naar client
|
||||
- Geen extra API route, geen useEffect
|
||||
|
||||
In Les 8: we voegen INSERT toe (create polls) + de /create page.
|
||||
|
||||
---
|
||||
|
||||
## Bronnen
|
||||
|
||||
- **Supabase docs:** https://supabase.com/docs
|
||||
- **Supabase voor Next.js:** https://supabase.com/docs/guides/getting-started/quickstarts/nextjs
|
||||
- **Postgres tutorial:** https://www.postgresqltutorial.com/
|
||||
- **RLS guide:** https://supabase.com/docs/guides/database/postgres/row-level-security
|
||||
- **JS client docs:** https://supabase.com/docs/reference/javascript/select
|
||||
- **SQL crash course:** https://sqlbolt.com
|
||||
Reference in New Issue
Block a user