# 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

Error: {error.message}

; return ( ); } ``` ### 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