Files
novi-lessons/Les07-Supabase/Les07-Lesopdracht.md
2026-06-07 10:44:05 +02:00

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 + options tabellen
  • 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 votes toe (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.