4.7 KiB
4.7 KiB
Les 7 — Lesopdracht
Supabase Setup + eerste queries
Duur: ~120 minuten klassikaal
Doel
Aan het einde: Supabase project gekoppeld aan QuickPoll. Polls tabel aangemaakt, en homepage leest uit echte database in plaats van in-memory.
Stap 1 — Supabase project klaar
Account + project moeten klaar zijn (uit Les 6 huiswerk). Anders nu doen.
Check je gegevens (Settings → API):
- Project URL:
https://abc123.supabase.co - Anon key:
eyJ...
Stap 2 — Tabellen via SQL Editor
Supabase Dashboard → SQL Editor → New query:
-- Polls tabel
create table polls (
id bigserial primary key,
title text not null,
created_at timestamp default now()
);
-- Options tabel (relatie naar polls)
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,
created_at timestamp default now()
);
-- RLS open voor demo
alter table polls enable row level security;
alter table options enable row level security;
create policy "polls demo open" on polls
for all to anon using (true) with check (true);
create policy "options demo open" on options
for all to anon using (true) with check (true);
Run → check Table Editor: beide tabellen verschijnen.
Stap 3 — Test data inserten
In SQL Editor:
insert into polls (title) values
('Beste programmeertaal?'),
('Beste IDE?');
insert into options (poll_id, text) values
(1, 'TypeScript'), (1, 'Python'), (1, 'Go'),
(2, 'Cursor'), (2, 'VS Code'), (2, 'Vim');
Check Table Editor → 2 polls, 6 opties.
Stap 4 — Supabase in Next.js
cd quickpoll
pnpm add @supabase/supabase-js
.env.local:
NEXT_PUBLIC_SUPABASE_URL=https://abc123.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
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!,
);
Stap 5 — Homepage van Supabase
Refactor app/page.tsx:
import { supabase } from "@/lib/supabase";
import Link from "next/link";
export default async function Home() {
const { data: polls, error } = await supabase
.from("polls")
.select("*")
.order("created_at", { ascending: false });
if (error) return <p className="p-8 text-red-600">Error: {error.message}</p>;
return (
<main className="max-w-2xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-6">QuickPoll</h1>
<ul className="space-y-2">
{polls?.map(p => (
<li key={p.id}>
<Link href={`/poll/${p.id}`} className="text-blue-600 hover:underline">
{p.title}
</Link>
</li>
))}
</ul>
</main>
);
}
Restart pnpm dev (env-changes vereisen restart). Open localhost:3000 → polls zichtbaar uit Supabase.
Stap 6 — Detail-pagina
// app/poll/[id]/page.tsx
import { supabase } from "@/lib/supabase";
import { notFound } from "next/navigation";
export default async function PollPage({
params,
}: { params: Promise<{ id: string }> }) {
const { id } = await params;
const { data: poll } = await supabase
.from("polls")
.select("*, options(*)")
.eq("id", Number(id))
.single();
if (!poll) notFound();
return (
<main className="max-w-md mx-auto p-8">
<h1 className="text-2xl font-bold mb-4">{poll.title}</h1>
<ul className="space-y-2">
{poll.options.map(o => (
<li key={o.id} className="p-3 border rounded flex justify-between">
<span>{o.text}</span>
<span className="text-gray-500">{o.votes}</span>
</li>
))}
</ul>
</main>
);
}
Voting bouwen we in Les 8.
Eisen
- Supabase project actief met
polls+optionstabellen - RLS aan met open policies
- Minstens 2 polls in DB
- Homepage leest van Supabase
- Detail-pagina toont opties van Supabase
- Geen errors in console
Bonus
- Voeg een 3e tabel
votestoe (voor user-tracking later) - Type-generation:
pnpm dlx supabase gen types typescript --linked > types/database.ts - Loading-skeleton voor detail-pagina
Veelvoorkomende problemen
| Probleem | Oplossing |
|---|---|
| "Invalid API key" | Anon key klopt niet — check .env.local, restart dev |
| Polls niet zichtbaar | RLS policy ontbreekt — check beide tabellen |
.env.local niet geladen |
Restart pnpm dev na env-changes |
| Foreign key violation | Insert opties na polls (poll_id moet bestaan) |
Klaar?
Volgende les: schrijven naar DB (INSERT, UPDATE) — create-pagina + voting werkend.