# Les 18 — Huiswerk ## Multi-user Tasks app met RLS + social login + AUTH.md **Vak:** AI-Assisted Development **Deadline:** Voor eindopdracht-inlevering (4 weken) **Inleveren:** GitHub repo + `AUTH.md` in root + Vercel productie URL --- ## Doel Bouw je auth-demo uit naar productie-niveau: tasks per user met RLS, GitHub social login, en deploy. Eindopdracht-ready. --- ## Onderdeel A — Tasks tabel + RLS (verplicht) ### A1 — Schema In Supabase SQL Editor: ```sql create table tasks ( id bigserial primary key, user_id uuid not null references auth.users(id) default auth.uid(), text text not null, done boolean default false, created_at timestamp default now() ); alter table tasks enable row level security; create policy "select own tasks" on tasks for select using (auth.uid() = user_id); create policy "insert own tasks" on tasks for insert with check (auth.uid() = user_id); create policy "update own tasks" on tasks for update using (auth.uid() = user_id); create policy "delete own tasks" on tasks for delete using (auth.uid() = user_id); ``` ### A2 — Tasks UI `app/page.tsx` — extend met tasks lijst + form: ```tsx import { createClient } from "@/utils/supabase/server"; import { redirect } from "next/navigation"; import { revalidatePath } from "next/cache"; async function addTask(formData: FormData) { "use server"; const supabase = await createClient(); await supabase.from("tasks").insert({ text: formData.get("text") as string }); revalidatePath("/"); } async function toggleTask(id: number, done: boolean) { "use server"; const supabase = await createClient(); await supabase.from("tasks").update({ done: !done }).eq("id", id); revalidatePath("/"); } async function deleteTask(id: number) { "use server"; const supabase = await createClient(); await supabase.from("tasks").delete().eq("id", id); revalidatePath("/"); } export default async function Home() { const supabase = await createClient(); const { data: { user } } = await supabase.auth.getUser(); if (!user) redirect("/login"); const { data: tasks } = await supabase .from("tasks") .select("*") .order("created_at", { ascending: false }); return (

Tasks van {user.email}

); } ``` ### Eisen - [ ] `tasks` tabel met RLS aan - [ ] 4 policies: select / insert / update / delete - [ ] UI: add, toggle, delete tasks werkt - [ ] In incognito met ander account: andere tasks zichtbaar (geen vermenging) --- ## Onderdeel B — Social login (GitHub) (verplicht) ### B1 — GitHub OAuth App 1. github.com → Settings → Developer settings → OAuth Apps → New 2. Application name: jouw app 3. Homepage URL: `http://localhost:3000` (dev) of `https://yourapp.vercel.app` (prod) 4. Callback URL: `https://your-project.supabase.co/auth/v1/callback` 5. Save, generate Client Secret ### B2 — Configure in Supabase 1. Dashboard → Auth → Providers → GitHub 2. Enable + plak Client ID + Secret ### B3 — Button toevoegen In `app/login/page.tsx`: ```tsx async function signInWithGitHub() { const supabase = createClient(); await supabase.auth.signInWithOAuth({ provider: "github", options: { redirectTo: `${location.origin}/auth/callback` }, }); } // In render: ``` ### Eisen - [ ] GitHub OAuth App aangemaakt - [ ] Supabase configured - [ ] Klik op GitHub button → redirect → ingelogd - [ ] Tasks werken met GitHub-account --- ## Onderdeel C — Deploy naar Vercel (verplicht) Combineert Les 14/15: 1. Push naar GitHub 2. Vercel: import repo 3. Add env vars: `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY` 4. Deploy 5. Update Supabase Auth → URL Configuration: - **Site URL:** `https://yourapp.vercel.app` - **Redirect URLs:** `https://yourapp.vercel.app/**`, `http://localhost:3000/**` 6. Update GitHub OAuth App callback URL to productie ### Eisen - [ ] App live op Vercel - [ ] Magic link werkt op productie URL - [ ] GitHub login werkt op productie URL - [ ] Tasks per user werken op productie --- ## Onderdeel D — `AUTH.md` documentatie (verplicht) In repo-root. ### Sectie 1 — Auth methoden Welke auth methoden ondersteund: - Magic link (default) - GitHub OAuth - (eventuele extra's) ### Sectie 2 — RLS policies Lijst je policies + waarom: ```markdown **Table: tasks** - `select own tasks` — users zien alleen eigen tasks - `insert own tasks` — voorkomt inserten op andermans naam - `update own tasks` — alleen eigen toggle - `delete own tasks` — alleen eigen delete ``` ### Sectie 3 — Test van multi-user isolation Bewijs dat RLS werkt: - Screenshot van Account A's tasks - Screenshot van Account B's tasks (incognito) - Bewijs: account A's tasks staan NIET in account B's lijst ### Sectie 4 — Deployment checklist Wat je moest aanpassen voor productie: - Site URL in Supabase - Redirect URLs in Supabase - GitHub OAuth callback URL - Env vars in Vercel ### Sectie 5 — Eindopdracht-architectuur (~250 woorden) Concrete plan voor je eigen eindopdracht: - App naam + doel - User-flows (signup, login, kernfeature) - Welke tabellen + RLS policies - AI feature(s) en hoe ze user-context gebruiken - Externe APIs (uit Les 17) - Tijd-plan (4-6 weken) ### Vorm - Max 800 woorden - Screenshots zijn waardevol - Concrete plan, geen vaagheid --- ## Bonus (optioneel) ### Bonus 1 — Email + password naast magic link Voeg klassieke signup/login toe. Combine met magic link. ### Bonus 2 — Profile pagina `/profile` — user kan naam, avatar URL, etc. instellen. Aparte `profiles` tabel met RLS. ### Bonus 3 — Team feature Multi-user binnen team. Aparte tabel `teams`, junction `team_members`. RLS policies die team-leden toelaten elkaars data te zien. ### Bonus 4 — AI integration met user context Voeg een AI chat toe waar de user-tasks deel zijn van de context. AI weet wat jouw tasks zijn (door RLS), kan helpen prioriteren. --- ## Inleveren 1. **GitHub repo URL** in Brightspace 2. **Vercel productie URL** in Brightspace 3. **`AUTH.md`** in repo-root 4. **Test-account credentials** voor docent (email of GitHub) 5. **2-3 screenshots** van multi-user test --- ## Beoordeling | Criterium | Punten | |-----------|--------| | A — Tasks + RLS werkt (4 policies) | 3 | | B — GitHub OAuth werkt | 2 | | C — Deployed op Vercel + auth werkt op prod | 2 | | D — AUTH.md compleet (5 secties) | 2 | | Multi-user isolation bewezen | 1 | | **Totaal** | **10** | Voldoende = 6+. Bonus telt mee. --- ## Tijd-indicatie | Onderdeel | Tijd | |-----------|------| | A — Tasks + RLS | 50 min | | B — GitHub OAuth | 25 min | | C — Deploy | 20 min | | D — AUTH.md | 35 min | | **Totaal** | **~2 uur 10 min** | --- ## Veelvoorkomende valkuilen | Probleem | Oplossing | |----------|-----------| | Tasks van andere users zichtbaar | RLS niet aan, of policy `using (true)` | | Insert faalt met "row violates" | RLS check faalt — check `with check (auth.uid() = user_id)` + default | | OAuth redirect 404 | Site URL niet bijgewerkt voor productie | | Magic link werkt lokaal niet prod | Site URL in Supabase staat nog op localhost | | Cookies werken niet | Middleware draait niet — check matcher en path | | `auth.uid()` returnt null | User niet ingelogd — check session in Server Component | --- ## Tips - **Test isolation in incognito** — alleen daar ben je écht "another user" - **RLS error messages** kunnen vaag zijn — log policy + auth.uid() in Postgres function voor debug - **Productie env vars** — vergeet niet je Vercel env vars te zetten - **Eindopdracht-koppeling:** dit huiswerk is je startpunt — bouw eindopdracht hier op - **Veel succes met de eindopdracht!** --- ## Voor je begint aan de eindopdracht Als afsluiting: 1. Plan je eindopdracht concreet (Sectie 5 van AUTH.md is de basis) 2. Start een nieuwe repo van scratch óf bouw verder op deze 3. Push klein en vaak — niet één big commit aan eind 4. Vraag hulp tijdig — Slack, mail, office hours 5. Plan tijd in van min 8-10 uur/week voor 4-6 weken **Bedankt voor jullie inzet deze 18 lessen. Veel succes met de eindopdracht!**