diff --git a/Les09-Cursor-Deep-Dive/Les09-Docenttekst.md b/Les09-Cursor-Deep-Dive/Les09-Docenttekst.md new file mode 100644 index 0000000..89a84c7 --- /dev/null +++ b/Les09-Cursor-Deep-Dive/Les09-Docenttekst.md @@ -0,0 +1,1545 @@ +# Les 9 — Cursor Deep Dive: Docenttekst + +**Docent:** Tim +**Duur:** 3 uur (180 min) — 09:00 tot 12:00 +**Cursus:** AI Developer — NOVI Hogeschool Utrecht +**Datum:** Lesweek 9 + +--- + +## Overzicht lesplanning + +| Tijd | Onderwerp | Vorm | +|------|-----------|------| +| 09:00–09:10 | Welkom + korte terugblik | Klassikaal | +| 09:10–09:35 | Theorie: Agent Harness, Rules, Plan Mode, Debug Mode, Code Review | Klassikaal | +| 09:35–09:55 | Setup: nieuw project + .cursor/rules (3 bestanden!) | Samen | +| 09:55–10:15 | Plan Mode: plan LinkVault, review, Build | Klassikaal | +| 10:15–10:30 | Pauze | — | +| 10:30–11:05 | Agent Mode: features bouwen (edit, filter) | Klassikaal | +| 11:05–11:25 | Debug Mode: Tim's bug vinden en fixen | Klassikaal | +| 11:25–11:45 | Code Review & Testing + Git push + Semantic commits | Klassikaal | +| 11:45–11:55 | (Optioneel) PR review met Cursor | Klassikaal | +| 11:55–12:00 | Afsluiting + huiswerk uitdelen | Klassikaal | + +--- + +## Voorkennis studenten + +- **Les 3 (Cursor Basics):** Chat (Ctrl+L), Inline Edit (Ctrl+K), Composer (Ctrl+I), Tab Completion, @ Mentions, .cursorrules, Skills/Docs +- **Tech stack:** Next.js, TypeScript, Tailwind CSS, Supabase +- **Cursor:** Studenten hebben Cursor geinstalleerd en het Student Plan actief (500 fast requests/maand) +- **Projectervaring:** Studenten hebben in eerdere lessen gewerkt met bestaande codebases; vandaag bouwen we from scratch + +## Wat we vandaag bouwen + +**LinkVault** — een bookmark manager applicatie: +- URLs opslaan met titel en tags (komma-gescheiden) +- Lijst van alle bookmarks bekijken in een card layout +- Filteren op tag (klikbare tag badges) +- Bookmarks bewerken (inline editing) +- Bookmarks verwijderen +- In-memory data (geen database) +- Next.js 16, TypeScript, Tailwind CSS + +## Benodigdheden + +- [ ] Cursor geinstalleerd met Student Plan actief +- [ ] Node.js 18+ geinstalleerd +- [ ] Git geconfigureerd +- [ ] GitHub account +- [ ] Internetverbinding +- [ ] Slides Les 9 open op docentlaptop + +--- + +# BLOK 1: Welkom + korte terugblik (09:00 – 09:10) + +## 1.1 Welkom en agenda (5 min) + +📊 **Slide 1 — Titelslide** + +> **Tim zegt:** +> "Goedemorgen allemaal! Fijn dat iedereen nu Cursor heeft met het Student Plan. Vandaag gaan we diep duiken in Cursor. In Les 3 hebben jullie de basis geleerd — Chat, Inline Edit, Composer. Maar Cursor kan veel meer dan dat. Vandaag leren jullie hoe je Cursor als een echte coding agent inzet." + +> **Tim zegt:** +> "We gaan een complete app bouwen from scratch: LinkVault, een bookmark manager. Maar het gaat niet om de app zelf — het gaat om HOE we die bouwen. Jullie leren vijf technieken: Rules, Plan Mode, Agent Mode, Debug Mode, en Code Review met semantic commits. Aan het eind van deze les denk je anders over hoe je met Cursor werkt." + +📊 **Slide 2 — Planning Vandaag** + +Loop kort de agenda door (verwijs naar de slides): +1. Theorie: hoe coding agents werken +2. Setup: nieuw project + rules +3. Plan Mode demo +4. Pauze +5. Samen bouwen met Agent Mode +6. Debug Mode +7. Code Review, Testing & Semantic Commits +8. (Optioneel) PR review +9. Afsluiting + huiswerk + +## 1.2 Korte terugblik Les 3 (5 min) + +> **Tim zegt:** +> "Even een snelle terugblik. In Les 3 hebben jullie geleerd over Chat met Ctrl+L, Inline Edit met Ctrl+K, en de Composer met Ctrl+I. Jullie hebben @ mentions gebruikt om context te geven aan de agent. En jullie hebben een .cursorrules bestand gemaakt. Klopt dat? Wie kan me vertellen wat @ mentions doen?" + +Laat een of twee studenten antwoorden. Kort houden. + +> **Tim zegt:** +> "Goed. Vandaag gaan we al die dingen combineren en uitbreiden. We vervangen .cursorrules door een veel krachtiger systeem: de .cursor/rules directory met meerdere regel-bestanden. En we leren nieuwe modes: Plan Mode en Debug Mode. Laten we beginnen." + +--- + +# BLOK 2: Theorie — Hoe werken Coding Agents? (09:10 – 09:35) + +> **Tim zegt:** +> "Voordat we gaan bouwen, wil ik dat jullie begrijpen WAT er onder de motorkap gebeurt als je met Cursor werkt. Dit is niet zomaar een chatbot in je editor. Dit is een coding agent. En er is een verschil." + +## 2.1 Het Harness — Hoe een Coding Agent werkt (5 min) + +📊 **Slide 3 — Hoe werkt een Coding Agent?** + +Teken op het whiteboard (of toon slide) drie blokken: + +``` ++------------------+ +| HET HARNESS | +| | +| 1. Instructions | <-- System prompt + jouw rules +| 2. Tools | <-- Bestanden bewerken, zoeken, terminal +| 3. Model | <-- Claude, GPT-4o, etc. ++------------------+ + | + v + Jouw prompt +``` + +> **Tim zegt:** +> "Een coding agent draait in een zogenaamd harness. Dat is het framework waarbinnen de agent werkt. Het bestaat uit drie onderdelen." + +> **Tim zegt:** +> "Nummer 1: Instructions. Dit is de system prompt die Cursor zelf meegeeft, plus jouw eigen rules. Die vertellen de agent HOE hij moet werken. Welke taal, welke frameworks, welke conventies. Dit is waar wij straks onze .cursor/rules bestanden voor maken." + +> **Tim zegt:** +> "Nummer 2: Tools. De agent kan bestanden lezen en bewerken, door je codebase zoeken, en commando's uitvoeren in de terminal. Dat is wat hem anders maakt dan ChatGPT — hij kan daadwerkelijk dingen DOEN in je project." + +> **Tim zegt:** +> "Nummer 3: Het model. Je kiest welk AI-model je gebruikt. Claude Sonnet, GPT-4o, of andere opties. Elk model heeft z'n sterke kanten. Voor vandaag laten we het standaardmodel staan." + +> **Tim zegt:** +> "Het mooie is: het harness regelt alles. Jij hoeft je alleen te focussen op goede prompts en goede rules. De rest doet Cursor voor je." + +## 2.2 Rules — De .cursor/rules directory (7 min) + +📊 **Slide 4 — Rules & Skills** + +> **Tim zegt:** +> "In Les 3 hebben jullie .cursorrules gezien. Dat was een enkel bestand in je project root. Maar Cursor heeft dat systeem flink uitgebreid. Nu heb je een hele rules directory met meerdere bestanden, elk voor een ander doel." + +Leg uit (toon slide): + +**Rules directory structuur:** +``` +.cursor/ + rules/ + project.mdc <-- Altijd actief (alwaysApply: true) + components.mdc <-- Actief bij component bestanden (globs) + styles.mdc <-- Actief bij styling bestanden (globs) + testing.mdc <-- Actief bij test bestanden (globs) + api.mdc <-- Actief bij API routes (globs) +``` + +> **Tim zegt:** +> "Elke rule is een .mdc bestand — dat staat voor Markdown Configuration. Het heeft een YAML frontmatter header bovenaan, net als bij een blog post. Die header vertelt Cursor WANNEER de rule actief moet zijn." + +Toon de YAML frontmatter structuur: + +``` +--- +description: Wat deze rule doet +globs: +alwaysApply: true +--- + +Hier komen je regels in Markdown. +``` + +> **Tim zegt:** +> "Er zijn drie soorten rules:" + +> **Tim zegt:** +> "1. **Always-on rules** — met `alwaysApply: true`. Die staan in elk gesprek aan. Bijvoorbeeld je project.mdc met algemene projectregels. Die wil je ALTIJD meegeven." + +> **Tim zegt:** +> "2. **Auto-attached rules** — met een `globs` patroon. Die worden automatisch geladen als je werkt in bestanden die matchen met dat patroon. Werk je in een .tsx component? Dan laadt Cursor automatisch je components.mdc. Werk je in een CSS-bestand? Dan laadt hij je styles.mdc. Cursor is slim genoeg om de juiste rules op het juiste moment te laden." + +> **Tim zegt:** +> "3. **Agent-requested rules** — de agent kan zelf rules opvragen als hij denkt dat ze relevant zijn op basis van de description. Maar die gebruiken we vandaag niet actief." + +> **Tim zegt:** +> "Belangrijk: houd je rules kort en specifiek. Schrijf NIET je hele coding handbook erin. Hoe meer overbodige rules je toevoegt, hoe meer je de agent in de war brengt. Kort, specifiek, met voorbeelden. We maken er straks drie aan, dan zie je precies hoe het werkt." + +**Skills kort aanstippen:** + +> **Tim zegt:** +> "Naast rules heb je ook Skills. Die zijn als workflow templates die de agent dynamisch kan laden. Skills zijn krachtig, maar voor vandaag focussen we op rules. Skills komen terug in latere lessen." + +## 2.3 Context Management (5 min) + +📊 **Slide 5 — Context Management** + +> **Tim zegt:** +> "Context is misschien wel het allerbelangrijkste concept. De agent weet alleen wat je hem vertelt. Hoe beter de context, hoe beter het resultaat. Denk er zo over: de agent is een briljante ontwikkelaar die net is begonnen op je project. Hij kent de taal en de frameworks, maar hij kent JOUW code niet. Jij moet hem vertellen waar hij moet kijken." + +Toon de @ mentions (verwijs naar Les 3 ter herinnering): + +| Mention | Wat het doet | Voorbeeld | +|---------|-------------|-----------| +| `@file` | Voegt een specifiek bestand toe als context | `@data.ts` | +| `@folder` | Voegt een hele map toe | `@src/components` | +| `@codebase` | Semantisch zoeken door je hele project | `@codebase hoe worden bookmarks opgeslagen?` | +| `@web` | Zoekt op het internet | `@web Next.js 16 server actions` | +| `@docs` | Zoekt in specifieke documentatie | `@docs Tailwind CSS` | +| `@git` | Referentie naar git diff/history | `@git bekijk mijn recente changes` | + +> **Tim zegt:** +> "Het verschil met Les 3: nu gaan we deze COMBINEREN. Je kunt zeggen: '@data.ts @components/BookmarkCard.tsx — voeg een edit knop toe aan elke bookmark.' Dan geef je de agent precies de bestanden die hij nodig heeft." + +> **Tim zegt:** +> "Pro-tip: start een nieuw gesprek voor elke nieuwe feature. Als de agent afdwaalt, begin opnieuw. Nieuwe feature? Nieuw gesprek. Agent doet raar? Nieuw gesprek. Context wordt rommelig na te veel heen-en-weer." + +**Sub-agents uitleggen:** + +> **Tim zegt:** +> "Cursor gebruikt ook sub-agents achter de schermen. Als je @codebase gebruikt, stuurt de agent een sub-agent op pad om door je code te zoeken. Die sub-agent zoekt, filtert, en geeft alleen het relevante terug aan de hoofd-agent. Dat is waarom @codebase zo goed werkt, zelfs in grote projecten." + +## 2.4 Plan Mode (5 min) + +📊 **Slide 6 — Plan Mode** + +> **Tim zegt:** +> "Dit is DE belangrijkste workflow die ik jullie vandaag wil leren. Plan Mode. Begin ALTIJD met een plan. Altijd." + +> **Tim zegt:** +> "Hoe werkt het? Je opent de chat met Ctrl+L, en dan druk je Shift+Tab om naar Plan Mode te schakelen. Of je klikt op de toggle onderaan het chatvenster. De agent gaat dan NIET meteen code schrijven. Hij doet eerst research, stelt verhelderende vragen, en maakt een stap-voor-stap plan in markdown." + +> **Tim zegt:** +> "En dat plan is BEWERKBAAR. Jij kunt stappen verwijderen, toevoegen, herschrijven. Vind je dat de agent te ambitieus is? Schrap die stappen. Wil je iets anders? Pas het aan. En pas als je tevreden bent, klik je op 'Build' en gaat de agent aan de slag." + +**Workflow visualiseren:** +``` +1. Ctrl+L -> Open chat +2. Shift+Tab -> Schakel naar Plan Mode +3. Typ je prompt -> Beschrijf wat je wilt bouwen +4. Agent plant -> Onderzoekt, stelt vragen, maakt plan +5. Jij reviewt -> Lees het plan, pas aan waar nodig +6. Klik "Build" -> Agent voert het plan uit +7. Review output -> Controleer de code +``` + +> **Tim zegt:** +> "Waarom is dit zo belangrijk? Omdat je VOORAF nadenkt over wat je wilt. Geen plan = de agent gaat z'n eigen gang = je bent daarna uren bezig met fixen. Een goed plan = gerichte output = minder iteraties = minder van je requests verspild." + +## 2.5 Agent Mode vs Ask Mode (2 min) + +📊 **Slide 7 — Agent Mode vs Ask Mode** + +> **Tim zegt:** +> "In Cursor heb je twee modes in de chat: Ask en Agent. Het verschil is simpel:" + +> **Tim zegt:** +> "**Ask Mode** is voor vragen. 'Hoe werkt useEffect?' of 'Leg deze code uit.' De agent leest, maar raakt niks aan." + +> **Tim zegt:** +> "**Agent Mode** is voor actie. De agent kan bestanden aanmaken, bewerken, verwijderen, en terminal commando's uitvoeren. Multi-file edits, refactoring, nieuwe features — dat doe je in Agent Mode." + +> **Tim zegt:** +> "Vuistregel: wil je iets WETEN? Ask Mode. Wil je iets DOEN? Agent Mode. Vandaag werken we vooral in Agent Mode en Plan Mode." + +## 2.6 Debug Mode (3 min) + +📊 **Slide 8 — Debug Mode** + +> **Tim zegt:** +> "Debug Mode is iets dat veel studenten missen. Als je een bug hebt, is je eerste instinct om de error te kopieren en in de chat te plakken. Dat werkt voor simpele bugs. Maar voor complexe bugs heb je een systematische aanpak nodig." + +> **Tim zegt:** +> "Het verschil zit in de methode. Bij een simpele bug plak je de error en de agent fixt het. Bij een complexe bug gebruik je Debug Mode: de agent genereert hypotheses over wat er mis kan zijn, voegt logging toe aan strategische plekken, vraagt jou om de bug te reproduceren, analyseert de logs, en stelt dan een gerichte fix voor op basis van bewijs. Niet gokken, maar bewijzen." + +Toon de stappen (slide of whiteboard): +``` +Simpele bug: Complexe bug (Debug Mode): +1. Copy error 1. Open Debug Mode +2. Plak in chat 2. Agent genereert hypotheses +3. Agent fixt 3. Agent voegt logging toe + 4. Jij reproduceert de bug + 5. Agent analyseert de logs + 6. Agent stelt een gerichte fix voor +``` + +> **Tim zegt:** +> "We gaan dit straks live doen. Ik ga BEWUST een bug in onze code plaatsen en dan laten zien hoe je die systematisch opspoort." + +## 2.7 Code Review & Semantic Commits (3 min) + +📊 **Slide 9 — Code Review & Testing** + +> **Tim zegt:** +> "Het laatste punt, en misschien het belangrijkste voor je professionele ontwikkeling. Voordat je iemand anders vraagt om je code te reviewen, doe je altijd eerst een self-review. Dat geldt ook voor AI-geschreven code." + +> **Tim zegt:** +> "Cursor heeft een 'Find Issues' functionaliteit. Die laat de agent je code doorlopen en mogelijke problemen signaleren. Daarnaast kun je de agent vragen om tests te schrijven. Tests zijn je vangnet — als je de agent later meer autonomie geeft, zorgen tests ervoor dat hij niks breekt." + +> **Tim zegt:** +> "En dan semantic commits. In plaats van een grote commit met 'app gebouwd', verdeel je je wijzigingen in logische groepen. 'Add bookmark data model', 'Add bookmark list component', 'Add tag filtering'. Maar — en dit is belangrijk — dat hoef je niet na elke stap te doen. In de praktijk bouw je vaak een tijdje door zonder te committen. Je bent gefocust op je feature, je wilt in de flow blijven." + +> **Tim zegt:** +> "Wat wij vandaag doen: we bouwen ALLES eerst. Plan Mode, Agent Mode, debug, tests — alles. Aan het eind hebben we een grote uncommitted diff. En DAN vragen we Cursor om die diff op te splitsen in nette semantic commits. Dat is een realistische workflow. Je leert twee dingen tegelijk: hoe je in de flow blijft tijdens het bouwen, en hoe je achteraf je werk netjes opdeelt." + +> **Tim zegt:** +> "Onthoud: dezelfde standaard voor AI-code als voor handgeschreven code. AI-code is geen excuus voor slechte code." + +### CHECKPOINT na Blok 2 + +> **Tim zegt:** +> "Snel samenvatten. De concepten: Het Harness, Rules met YAML frontmatter, Context met @ mentions, Plan Mode, Agent vs Ask, Debug Mode, Code Review met semantic commits. Zijn er vragen voordat we gaan bouwen?" + +Beantwoord vragen. Maximaal 2 minuten. Als er veel vragen zijn, parkeer ze: "Goed punt, dat zien we straks in de praktijk." + +--- + +# BLOK 3: Setup — Nieuw Project + .cursor/rules (09:35 – 09:55) + +> **Tim zegt:** +> "Oke, handen uit de mouwen. We gaan LinkVault opzetten. Iedereen doet mee. Open je terminal." + +## 3.1 Next.js project aanmaken (8 min) + +📊 **Slide 10 — Setup: Nieuw Project** + +**Stap 1: Create Next App** + +> **Tim zegt:** +> "Open je terminal en typ het volgende commando. We gebruiken Next.js 16, de nieuwste versie." + +```bash +npx create-next-app@latest linkvault +``` + +Wanneer de prompts komen, kies: +- TypeScript: **Yes** +- ESLint: **Yes** +- Tailwind CSS: **Yes** +- `src/` directory: **Yes** +- App Router: **Yes** +- Import alias: **@/** (default) + +> **Tim zegt:** +> "Wacht tot het klaar is. Dit kan even duren afhankelijk van je internetverbinding." + +**Stap 2: Git initialiseren (als dat niet automatisch is gebeurd)** + +```bash +cd linkvault +git init +git add . +git commit -m "chore: initial Next.js 16 project setup" +``` + +> **Tim zegt:** +> "We committen meteen de initieel gegenereerde code. Zo hebben we een schone baseline." + +**Stap 3: Project starten** + +```bash +npm run dev +``` + +> **Tim zegt:** +> "Open nu je browser en ga naar localhost:3000. Je zou de standaard Next.js welkomstpagina moeten zien." + +**Stap 4: Open in Cursor** + +> **Tim zegt:** +> "Open nu Cursor en open de linkvault map. File > Open Folder, of vanuit de terminal: `cursor .`" + +**Troubleshooting:** +- **"npx niet gevonden":** Node.js is niet geinstalleerd of niet in PATH. `node -v` om te checken. Minimaal v18. +- **"Port 3000 in gebruik":** `npm run dev -- -p 3001` of sluit het andere proces. +- **"Cursor opent niet vanuit terminal":** Open Cursor handmatig via File > Open Folder. + +## 3.2 Cursor Rules instellen — 3 bestanden (12 min) + +📊 **Slide 11 — Setup: .cursor/rules** + +> **Tim zegt:** +> "Nu gaan we onze rules instellen. We maken DRIE bestanden aan in een .cursor/rules directory. Elk bestand heeft een ander doel. Dit is het systeem dat de agent vertelt HOE hij moet werken." + +**Stap 1: Maak de directory** + +```bash +mkdir -p .cursor/rules +``` + +--- + +### Bestand 1: `.cursor/rules/project.mdc` — Algemene projectregels + +> **Tim zegt:** +> "Het eerste bestand is project.mdc. Dit zijn de algemene projectregels. Met `alwaysApply: true` is dit bestand ALTIJD actief, in elk gesprek met de agent. Hier zetten we de tech stack, taal, en basisconventies." + +Bestand: `.cursor/rules/project.mdc` + +```markdown +--- +description: Algemene projectregels voor LinkVault +globs: +alwaysApply: true +--- + +# LinkVault — Projectregels + +## Tech Stack +- Next.js 16 met App Router +- TypeScript in strict mode +- Tailwind CSS voor alle styling +- In-memory data opslag (GEEN database, GEEN Supabase, GEEN Prisma) + +## Taal & Conventies +- Code in het Engels (variabelen, functies, types) +- Comments in het Nederlands +- Commit messages in het Engels (conventional commits) + +## Architectuur +- Server Components als default, 'use client' alleen voor interactieve componenten +- Data logica in src/lib/ +- Componenten in src/components/ +- Types in src/types/ +- App routes in src/app/ + +## Regels +- Geen extra dependencies installeren zonder expliciete toestemming +- Gebruik altijd TypeScript interfaces voor props (geen inline types) +- Exporteer types vanuit een centraal types bestand +- Gebruik named exports, geen default exports (behalve voor page.tsx en layout.tsx) +- Error handling: altijd try-catch bij async operaties +``` + +> **Tim zegt:** +> "Let op de YAML frontmatter bovenaan — de drie streepjes, dan de velden, dan weer drie streepjes. `description` vertelt Cursor waar deze rule over gaat. `globs` laten we leeg want het is een always-on rule. `alwaysApply: true` zorgt ervoor dat deze regel ALTIJD wordt meegestuurd. Elke keer dat je met de agent praat, kent hij deze regels." + +> **Tim zegt:** +> "Merk op: we zeggen expliciet 'GEEN database, GEEN Supabase, GEEN Prisma'. Dat voorkomt dat de agent spontaan database libraries gaat installeren. En 'geen extra dependencies zonder toestemming' — dat is een belangrijke veiligheidsregel." + +--- + +### Bestand 2: `.cursor/rules/components.mdc` — Component regels + +> **Tim zegt:** +> "Het tweede bestand is components.mdc. Dit wordt automatisch geladen als je werkt in TSX-bestanden in de components map. Hier staan regels specifiek voor hoe we componenten schrijven." + +Bestand: `.cursor/rules/components.mdc` + +```markdown +--- +description: Regels voor React componenten in LinkVault +globs: "src/components/**/*.tsx" +alwaysApply: false +--- + +# Component Regels + +## Structuur +- Functionele componenten met arrow functions +- Props interface boven de component, naam: [ComponentNaam]Props +- Geen default exports — altijd named exports + +## Voorbeeld + +```tsx +interface BookmarkCardProps { + bookmark: Bookmark; + onDelete: (id: string) => void; + onEdit: (id: string, data: Partial) => void; +} + +export const BookmarkCard = ({ bookmark, onDelete, onEdit }: BookmarkCardProps) => { + return ( + // JSX hier + ); +}; +``` + +## Naamgeving +- Componentnaam in PascalCase: BookmarkCard, TagFilter, BookmarkForm +- Bestandsnaam gelijk aan componentnaam: BookmarkCard.tsx +- Een component per bestand + +## State Management +- useState voor lokale UI-state (edit mode, form values) +- Props doorgeven voor data, NIET direct importeren uit data.ts in componenten +- Event handlers als props: onDelete, onEdit, onFilter + +## Accessibility +- Altijd aria-labels op interactieve elementen +- Buttons moeten type="button" of type="submit" hebben +- Formulieren gebruiken form element met onSubmit +``` + +> **Tim zegt:** +> "Kijk naar de `globs` regel: `src/components/**/*.tsx`. Dat betekent: laad deze rule alleen als de agent werkt in een TSX-bestand in de components map. Werk je in data.ts? Dan krijgt de agent deze regels NIET te zien. Zo houd je de context schoon." + +> **Tim zegt:** +> "En kijk naar het voorbeeld in de regels. Een concreet voorbeeld is veel krachtiger dan een abstracte beschrijving. De agent ziet het patroon en volgt het." + +--- + +### Bestand 3: `.cursor/rules/styles.mdc` — Styling regels + +> **Tim zegt:** +> "Het derde bestand is styles.mdc. Dit geldt voor CSS-bestanden EN TSX-bestanden, want in beide werk je met styling." + +Bestand: `.cursor/rules/styles.mdc` + +```markdown +--- +description: Styling regels voor Tailwind CSS in LinkVault +globs: "**/*.css,**/*.tsx" +alwaysApply: false +--- + +# Styling Regels + +## Tailwind CSS +- Utility-first: gebruik Tailwind classes, GEEN inline styles (geen style={}) +- Geen custom CSS tenzij Tailwind het niet kan +- Gebruik Tailwind's responsive prefixes: sm:, md:, lg: +- Consistent spacing: gebruik Tailwind spacing scale (p-2, p-4, m-2, m-4) + +## Kleuren +- Primary: blue-600 (knoppen, links, accenten) +- Danger: red-500 (verwijder knoppen, waarschuwingen) +- Succes: green-500 (bevestigingen) +- Achtergrond: gray-50 voor pagina, white voor cards +- Tekst: gray-900 voor hoofdtekst, gray-500 voor secundair + +## Layout +- Cards: rounded-lg shadow-sm border border-gray-200 p-4 +- Knoppen: px-4 py-2 rounded-md font-medium +- Formulier inputs: w-full rounded-md border border-gray-300 p-2 +- Pagina container: max-w-4xl mx-auto p-6 + +## Hover & Interactie +- Knoppen: hover:opacity-80 transition-colors +- Cards: hover:shadow-md transition-shadow +- Tags/badges: cursor-pointer hover:opacity-80 +``` + +> **Tim zegt:** +> "Deze rule definieert ons kleurenschema en styling patronen. Zonder dit gaat de agent elke keer andere kleuren en spacing kiezen. Nu is het consistent." + +> **Tim zegt:** +> "Merk op dat de globs hier twee patronen heeft: CSS-bestanden en TSX-bestanden. In TSX schrijf je Tailwind classes, dus die moet ook matchen." + +--- + +### Verifieer de rules + +> **Tim zegt:** +> "Laten we even checken of alles goed staat. Open de .cursor/rules map in Cursor's file explorer. Je zou drie bestanden moeten zien." + +``` +.cursor/ + rules/ + project.mdc <-- alwaysApply: true + components.mdc <-- globs: src/components/**/*.tsx + styles.mdc <-- globs: **/*.css, **/*.tsx +``` + +> **Tim zegt:** +> "Heeft iedereen drie bestanden? Mooi. De agent kent nu onze projectregels, weet hoe we componenten schrijven, en kent ons kleurenschema. Dat is een enorm verschil met gewoon blind prompts typen." + +**Troubleshooting:** +- **".cursor map wordt niet getoond":** Dit is een hidden directory (begint met een punt). In Cursor's file explorer zou hij zichtbaar moeten zijn. Zo niet, maak hem via de terminal. +- **"Werkt .cursorrules nog?":** Ja, maar de nieuwe .cursor/rules/ directory is krachtiger en flexibeler. .cursorrules in de root werkt nog als fallback. +- **"Ik heb een typfout in de YAML frontmatter":** De drie streepjes `---` moeten exact kloppen. Geen spatie ervoor. Check ook dat `alwaysApply` met een hoofdletter A is geschreven bij Apply. + +### CHECKPOINT + +> **Tim zegt:** +> "Checkpoint: wie heeft het volgende werkend? Steek je hand op." +> +> "1. Next.js project draait op localhost:3000?" +> "2. Project geopend in Cursor?" +> "3. Drie .cursor/rules bestanden aangemaakt — project.mdc, components.mdc, styles.mdc?" + +**Doel:** Iedereen moet op dit punt zijn. Help studenten die achterlopen. Maximaal 2 minuten troubleshooting. + +> **Tim zegt:** +> "Top. We hebben een schoon project met drie rules bestanden. Nu gaan we Plan Mode gebruiken om LinkVault te plannen." + +--- + +# BLOK 4: Plan Mode — Plan LinkVault + Build (09:55 – 10:15) + +📊 **Slide 12 — Plan Mode Demo** + +> **Tim zegt:** +> "Dit is het moment dat het leuk wordt. We gaan Plan Mode gebruiken om LinkVault te plannen en de eerste versie te bouwen. Ik doe dit voor op mijn scherm, jullie kijken mee." + +## 4.1 Plan Mode openen (2 min) + +**Stap 1: Open de chat** + +> **Tim zegt:** +> "Druk Ctrl+L om de chat te openen. Dan druk je Shift+Tab om naar Plan Mode te schakelen. Je ziet dat er 'Plan' staat in plaats van 'Agent' of 'Ask'." + +Tim demonstreert dit live op zijn scherm. Zorg dat het scherm gedeeld is via de beamer. + +**Keyboard shortcut reminder:** +- `Ctrl+L` — Open chat panel +- `Shift+Tab` — Toggle tussen modes (Plan / Agent / Ask) + +## 4.2 De prompt typen (3 min) + +> **Tim zegt:** +> "Nu gaan we een prompt typen. Let op: ik geef CONTEXT en ik ben SPECIFIEK over wat ik wil. Geen vage 'maak een app'. Ik vertel precies welke features ik wil." + +Tim typt de volgende prompt in Plan Mode: + +``` +Ik wil een bookmark manager app bouwen genaamd LinkVault. + +Features: +- Bookmarks opslaan met URL, titel en tags (komma-gescheiden) +- Lijst van alle bookmarks tonen in een card layout +- Filteren op tag (klikbare tag badges bovenaan de pagina) +- Bookmarks bewerken (inline editing met opslaan/annuleren) +- Bookmarks verwijderen met een bevestiging +- In-memory data opslag in een apart data.ts bestand met sample data + +Technische eisen: +- Gebruik het bestaande Next.js 16 project met App Router +- TypeScript strict +- Tailwind CSS voor alle styling (volg de styling regels in .cursor/rules) +- Server Components waar mogelijk, 'use client' alleen waar nodig +- Responsive design + +Project structuur: +- src/types/bookmark.ts — TypeScript interfaces +- src/lib/data.ts — in-memory data store met CRUD functies +- src/components/BookmarkForm.tsx — formulier voor toevoegen +- src/components/BookmarkCard.tsx — individuele bookmark card +- src/components/BookmarkList.tsx — lijst van alle bookmarks +- src/components/TagFilter.tsx — tag filter badges +- src/app/page.tsx — hoofdpagina die alles combineert + +Voeg 3-4 sample bookmarks toe in data.ts zodat de app niet leeg start. + +Welke stappen stel je voor om dit te bouwen? +``` + +> **Tim zegt:** +> "Merk op wat ik doe: ik beschrijf de features, de technische eisen, EN ik geef de gewenste project structuur mee. Ik eindig met een vraag. Ik zeg niet 'bouw dit', ik zeg 'welke stappen stel je voor'. Dat is Plan Mode — de agent gaat nu nadenken, niet meteen bouwen." + +## 4.3 Agent plan reviewen (5 min) + +> **Tim zegt:** +> "Kijk, de agent komt terug met een plan. Hij heeft het opgedeeld in stappen. Laten we dit samen doorlezen." + +De agent zal typisch iets teruggeven als: +1. Type definities aanmaken (bookmark.ts) +2. Data model en in-memory store met CRUD functies (data.ts) +3. BookmarkForm component +4. BookmarkCard component met edit/delete +5. TagFilter component +6. BookmarkList component +7. Main page layout (page.tsx) +8. Sample data toevoegen + +> **Tim zegt:** +> "Dit is het moment om kritisch te zijn. Kijk naar elke stap:" + +> **Tim zegt:** +> "Is er iets te ambitieus? Soms stelt de agent dingen voor als 'zoekfunctionaliteit' of 'sorteer opties' die we niet gevraagd hebben. Die schrappen we." + +> **Tim zegt:** +> "Mist er iets? Kijk of alle bestanden die we willen erin staan." + +> **Tim zegt:** +> "Is de volgorde logisch? Types eerst, dan data model, dan componenten, dan de pagina — dat klopt." + +**Live editen van het plan:** + +Tim demonstreert: +- Verwijder eventuele extra features die de agent heeft toegevoegd (search, sorting, dark mode, etc.) +- Zorg dat de stappen overzichtelijk en realistisch zijn +- Voeg eventueel toe: "Zorg dat de homepage direct de bookmark list toont met een formulier erboven" + +> **Tim zegt:** +> "Dit is de kracht van Plan Mode. JIJ bent de architect. De agent is de aannemer. Jij bepaalt het plan, hij voert het uit." + +## 4.4 Build uitvoeren (5 min) + +> **Tim zegt:** +> "Ik ben tevreden met het plan. Nu klik ik op 'Build'. De agent gaat nu stap voor stap de code schrijven. Kijk mee wat er gebeurt." + +Tim klikt op "Build" en laat zien hoe de agent: +- Bestanden aanmaakt +- Code schrijft +- Tussen bestanden navigeert +- Terminal commando's uitvoert als dat nodig is + +> **Tim zegt:** +> "Zie je hoe de agent meerdere bestanden aanmaakt? Types, data store, componenten, de pagina. Hij volgt het plan dat we samen hebben gemaakt. En kijk — hij gebruikt TypeScript interfaces, Tailwind classes, named exports. Precies zoals onze rules voorschrijven." + +**Belangrijk: Accept/Reject per bestand** + +> **Tim zegt:** +> "Bij elk bestand dat de agent wil aanmaken of wijzigen, krijg je een Accept of Reject optie. LEES de code voordat je accepteert. Je hoeft het niet regel voor regel te lezen, maar scan op: klopt de structuur? Worden de juiste imports gebruikt? Ziet het er logisch uit?" + +## 4.5 Eerste test (5 min) + +> **Tim zegt:** +> "De agent is klaar. Laten we kijken of het werkt. Ga naar localhost:3000 in je browser. Mogelijk moet je de dev server opnieuw starten als die niet meer liep." + +**Verwacht resultaat:** Een pagina met een formulier om bookmarks toe te voegen, tag filter badges, en een lijst met 3-4 sample bookmarks. + +**Test scenario's:** +1. Bekijk de sample bookmarks — zijn ze zichtbaar? +2. Voeg een bookmark toe: URL = "https://nextjs.org", Titel = "Next.js Docs", Tags = "react, docs" +3. Klik op een tag badge — werkt het filteren? +4. Klik op "Bewerk" bij een bookmark — werkt inline editing? +5. Verwijder een bookmark + +> **Tim zegt:** +> "Werkt het? Waarschijnlijk grotendeels wel. Misschien zijn er kleine dingen die niet kloppen — dat is normaal. We gaan die zo meteen aanpakken met Agent Mode. We committen nog NIET. We bouwen eerst alles af." + +**Troubleshooting:** +- **App crashed:** Check de terminal in Cursor voor error messages. Vaak een TypeScript type error of missing import. Plak de error in de chat (Agent Mode) en laat het fixen. +- **Styling ziet er raar uit:** Vraag de agent om de styling te verbeteren: "De layout ziet er niet goed uit. Maak de cards netter en volg de styling regels uit .cursor/rules/styles.mdc." +- **Form werkt niet:** Waarschijnlijk een missing 'use client' directive. De agent vergeet dit soms bij interactieve componenten. +- **Tags worden niet getoond:** Check of de sample data in data.ts correct tags heeft als een string array. + +--- + +# PAUZE (10:15 – 10:30) + +> **Tim zegt:** +> "Pauze! 15 minuten. Als je app nog niet draait, gebruik de pauze om het werkend te krijgen. Ik ben beschikbaar voor vragen." + +**Tijdens de pauze:** +- Help studenten die vastzitten +- Check of iedereen een werkende LinkVault heeft met sample data +- Bereid Blok 5 voor: heb je eigen Cursor open met LinkVault? + +--- + +# BLOK 5: Agent Mode — Features bouwen (10:30 – 11:05) + +📊 **Slide 13 — Agent Mode: Features bouwen** + +> **Tim zegt:** +> "Welkom terug! Iedereen zou nu een basis-versie van LinkVault moeten hebben. Nu gaan we features toevoegen en verbeteren met Agent Mode. Ik doe het voor, jullie volgen mee op je eigen project." + +> **Tim zegt:** +> "Voordat we beginnen, onthoud dit: DENK EERST, PROMPT DAARNA. Een goede prompt met context levert betere output, wat minder iteraties betekent, wat minder requests kost. Jullie hebben 500 fast requests per maand. Gebruik ze slim." + +> **Tim zegt:** +> "En we committen tussendoor nog steeds NIET. We bouwen alles af, en aan het eind maken we nette commits. Daar komen we zo op terug." + +## 5.1 Oefening 1: Edit Bookmark Feature verbeteren (15 min) + +> **Tim zegt:** +> "Als het goed is heeft de agent al een edit feature gebouwd in Plan Mode. Maar misschien is die nog niet perfect. We gaan hem verbeteren met Agent Mode." + +**Stap 1: Nieuw gesprek openen** + +> **Tim zegt:** +> "Open een nieuw chat gesprek met Ctrl+L. Zorg dat je in Agent Mode zit — niet Plan Mode, niet Ask Mode. We willen dat de agent nu daadwerkelijk code schrijft." + +**Stap 2: Prompt met context** + +> **Tim zegt:** +> "Let op hoe ik context meegeef met @ mentions. Ik verwijs naar de specifieke bestanden die de agent nodig heeft." + +Tim typt de volgende prompt: + +``` +Verbeter de edit bookmark feature in LinkVault. + +Context: +- @src/lib/data.ts bevat de in-memory data store +- @src/components/BookmarkCard.tsx toont individuele bookmarks + +Wat ik wil verbeteren: +1. Als je op "Bewerk" klikt, worden ALLE velden bewerkbaar (URL, titel, tags) +2. De edit state moet duidelijk visueel anders zijn (lichte achtergrondkleur, border highlight) +3. "Opslaan" en "Annuleren" knoppen verschijnen, "Bewerk" en "Verwijder" verdwijnen +4. Na opslaan: toon een korte "Opgeslagen!" bevestiging die na 2 seconden verdwijnt +5. Escape toets = annuleren +6. Validatie: URL mag niet leeg zijn + +Zorg dat de updateBookmark functie in data.ts robuust is — check of de bookmark bestaat. +``` + +> **Tim zegt:** +> "Merk op: ik verwijs naar twee specifieke bestanden met @. Ik beschrijf precies wat ik wil. En ik geef aan welke bestanden aangepast moeten worden. Hoe specifieker je bent, hoe beter het resultaat." + +**Stap 3: Review wat Agent voorstelt** + +> **Tim zegt:** +> "De agent toont nu z'n wijzigingen. Laten we samen doorlopen wat hij doet." + +Bespreek met de klas: +- Welke bestanden worden aangepast? +- Klopt de updateBookmark functie? +- Is de UI-logica correct (state management voor edit mode)? +- Worden types correct gebruikt? + +**Stap 4: Accept en test** + +> **Tim zegt:** +> "Het ziet er goed uit. Ik accepteer de changes. Nu testen: ga naar je browser, klik op Bewerk bij een bookmark, wijzig de titel, en sla op. Werkt het? Test ook Escape om te annuleren." + +**Troubleshooting:** +- **Edit knop doet niks:** Waarschijnlijk missing onClick handler of state management probleem. Plak de relevante code in een nieuw gesprek. +- **Na opslaan verandert er niks:** De state wordt niet correct bijgewerkt. Check of de component re-rendert na de update. +- **TypeScript errors:** Vaak een type mismatch. Laat de agent de types fixen. + +## 5.2 Oefening 2: Tag-filtering verbeteren (15 min) + +> **Tim zegt:** +> "Nu gaan we de tag-filtering verbeteren. We gebruiken @codebase om het project te doorzoeken en te begrijpen hoe tags momenteel werken." + +**Stap 1: Nieuw gesprek, Agent Mode** + +Tim typt: + +``` +@codebase Hoe worden tags momenteel geimplementeerd in LinkVault? + +Ik wil de tag-filtering verbeteren: +1. Toon alle unieke tags als klikbare badges bovenaan de pagina +2. Meerdere tags tegelijk kunnen selecteren (AND-filter) +3. Geselecteerde tags visueel markeren (donkerder achtergrond, witte tekst) +4. Een "Reset filters" knop die alleen verschijnt als er filters actief zijn +5. Toon het aantal bookmarks per tag als badge count (bijv. "react (3)") + +Gebruik de kleuren uit onze styling regels: blue-600 voor geselecteerde tags, +gray-200 voor niet-geselecteerde tags. Maak ze ronder (rounded-full) met +een hover effect. +``` + +> **Tim zegt:** +> "Zie je dat ik begin met @codebase? Dat laat de agent eerst door het hele project zoeken om te begrijpen hoe tags nu werken. Dan weet hij precies waar hij moet aanpassen." + +**Stap 2: Review en itereren** + +Na accepteren, bekijk het resultaat in de browser. + +> **Tim zegt:** +> "Het werkt maar misschien ziet het er niet helemaal uit zoals ik wil. Je kunt altijd een follow-up prompt sturen. Of zelfs een screenshot in de chat plakken en zeggen: 'Maak dit mooier.' De agent kan screenshots analyseren en de styling aanpassen." + +**Stap 3: Test de filtering grondig** + +Test scenario's: +1. Klik op een tag — worden alleen matching bookmarks getoond? +2. Klik op een tweede tag — AND-filter werkt? (alleen bookmarks met BEIDE tags) +3. Klik op "Reset filters" — alle bookmarks weer zichtbaar? +4. Kloppen de badge counts? + +> **Tim zegt:** +> "Goed. Nu hebben we een werkende app met editing en verbeterde filtering. Onthoud: we committen nog steeds niet. We hebben nog een stap te gaan." + +## 5.3 Studenten doen het zelf (5 min) + +> **Tim zegt:** +> "Neem even 5 minuten om je eigen versie te verbeteren. Gebruik Agent Mode. Probeer de edit feature te verbeteren of de filtering aan te passen. Of voeg iets toe dat je mist. Ik loop rond voor vragen." + +Geef studenten 5 minuten. Loop rond en help waar nodig. + +**Veelvoorkomende problemen bij studenten:** +- Ze vergeten naar Agent Mode te schakelen → "Check links onderaan of je in Agent staat" +- De prompt is te vaag → "Wees specifieker. Welke bestanden? Wat precies?" +- Te veel in een prompt → "Splits het op. Een feature per gesprek." + +--- + +# BLOK 6: Debug Mode — Tim's bug vinden en fixen (11:05 – 11:25) + +📊 **Slide 14 — Debug Mode: Tim's Bug** + +> **Tim zegt:** +> "Nu gaan we het over bugs hebben. Ik ga nu BEWUST een bug in mijn code plaatsen. Dit is niet iets dat Cursor per ongeluk heeft gemaakt — ik doe dit expres om jullie Debug Mode te laten zien." + +## 6.1 Bug introduceren (5 min) + +> **Tim zegt:** +> "Kijk mee op mijn scherm. Ik open src/lib/data.ts — het bestand met onze data logica." + +Tim opent `src/lib/data.ts` en zoekt de filter functie. Die ziet er ongeveer zo uit: + +```typescript +export const getBookmarksByTag = (tag: string): Bookmark[] => { + return bookmarks.filter(b => b.tags.includes(tag)); +}; +``` + +> **Tim zegt:** +> "Ik ga nu een subtiele wijziging maken. Let op." + +Tim wijzigt de regel HANDMATIG (niet via Cursor) naar: + +```typescript +export const getBookmarksByTag = (tag: string): Bookmark[] => { + return bookmarks.filter(b => b.tags.includes(tag.toUpperCase())); +}; +``` + +> **Tim zegt:** +> "Zien jullie wat ik heb veranderd? Ik heb `.toUpperCase()` toegevoegd aan de tag parameter. Dat betekent: als ik filter op 'react', wordt dat omgezet naar 'REACT'. Maar onze tags in de data staan opgeslagen als 'react' in lowercase. 'REACT' !== 'react', dus de filter vindt niks." + +> **Tim zegt:** +> "Sla op. Ga naar de browser. Laten we kijken." + +Tim demonstreert de bug: +1. Open de app in de browser +2. Er staan bookmarks met tags als "react", "nextjs", "css" +3. Klik op de "react" tag filter +4. **Geen resultaten** — terwijl er wel bookmarks met die tag zijn + +> **Tim zegt:** +> "Kijk: ik filter op 'react' maar er komen geen resultaten. Er ZIJN bookmarks met de tag 'react'. Dit is een subtiele bug — de soort die je in de echte wereld ook tegenkomt. Een kleine wijziging die alles breekt." + +## 6.2 Debug Mode demonstratie (10 min) + +> **Tim zegt:** +> "Nu ga ik laten zien hoe je dit systematisch opspoort met Debug Mode. Niet gewoon 'filter werkt niet' in de chat gooien en hopen dat het goedkomt." + +**Stap 1: Open een nieuw gesprek** + +> **Tim zegt:** +> "Ctrl+L voor een nieuw gesprek. Ik gebruik Agent Mode maar met een debug-gerichte prompt. Ik beschrijf het probleem, de stappen om te reproduceren, en welke bestanden relevant zijn." + +Tim typt: + +``` +Bug: Als ik filter op een tag, krijg ik geen resultaten. Maar er zijn wel bookmarks met die tag. + +Stappen om te reproduceren: +1. De app heeft bookmarks met tags zoals "react", "nextjs" +2. Ik klik op de "react" tag badge om te filteren +3. Verwacht: bookmarks met tag "react" worden getoond +4. Werkelijk: geen resultaten, lege lijst + +Onderzoek dit systematisch: +1. Genereer hypotheses over wat het probleem kan zijn +2. Voeg console.log statements toe om de filter logica te debuggen +3. Laat mij de bug reproduceren zodat we de logs kunnen analyseren + +Relevante bestanden: @src/lib/data.ts @src/components/TagFilter.tsx +``` + +**Stap 2: Agent genereert hypotheses** + +> **Tim zegt:** +> "Kijk wat de agent nu doet. Hij plakt niet meteen een fix. Hij denkt na. Hij genereert hypotheses over wat het probleem zou kunnen zijn." + +De agent zal typisch hypotheses genereren als: +- Case sensitivity mismatch in de vergelijking +- Incorrecte filter operatie (toUpperCase, toLowerCase) +- Tag data niet correct opgeslagen +- State management probleem bij het doorgeven van de filter tag + +> **Tim zegt:** +> "Zie je? Meerdere hypotheses. De agent weet nog niet welke het is. Nu gaat hij onderzoeken." + +**Stap 3: Agent voegt logging toe** + +> **Tim zegt:** +> "De agent voegt nu console.log statements toe op strategische plekken om te zien wat er daadwerkelijk gebeurt." + +De agent voegt tijdelijke logging toe, bijv.: +```typescript +export const getBookmarksByTag = (tag: string): Bookmark[] => { + console.log('Ontvangen filter tag:', tag); + console.log('Na transformatie:', tag.toUpperCase()); + console.log('Beschikbare tags in bookmarks:', bookmarks.map(b => b.tags)); + const result = bookmarks.filter(b => b.tags.includes(tag.toUpperCase())); + console.log('Filter resultaat:', result.length, 'bookmarks'); + return result; +}; +``` + +**Stap 4: Reproduceren en logs analyseren** + +> **Tim zegt:** +> "Nu vraagt de agent mij om de bug te reproduceren. Ik ga naar de browser, open de DevTools console met F12, en voer dezelfde stappen uit." + +Tim reproduceert de bug en laat de console output zien: +``` +Ontvangen filter tag: react +Na transformatie: REACT +Beschikbare tags in bookmarks: [["react", "typescript"], ["nextjs", "react"], ["css", "tailwind"]] +Filter resultaat: 0 bookmarks +``` + +> **Tim zegt:** +> "Daar is het bewijs! De filter tag 'react' wordt omgezet naar 'REACT' met toUpperCase(). Maar de tags in de data staan als 'react' in lowercase. 'REACT' zit niet in ['react', 'typescript'], dus includes() geeft false. Nul resultaten." + +**Stap 5: Gerichte fix** + +> **Tim zegt:** +> "Nu stelt de agent een fix voor. Niet een generieke 'misschien werkt dit', maar een gerichte fix gebaseerd op het bewijs uit de logs." + +De agent stelt voor om de `.toUpperCase()` te verwijderen: +```typescript +export const getBookmarksByTag = (tag: string): Bookmark[] => { + return bookmarks.filter(b => b.tags.includes(tag)); +}; +``` + +Of een robuustere versie met case-insensitive vergelijking: +```typescript +export const getBookmarksByTag = (tag: string): Bookmark[] => { + return bookmarks.filter(b => + b.tags.some(t => t.toLowerCase() === tag.toLowerCase()) + ); +}; +``` + +> **Tim zegt:** +> "Accepteer de fix. De agent verwijdert ook de console.log statements — die waren alleen voor debugging. Test opnieuw. Klik op 'react'. Werkt het nu? Ja!" + +**Stap 6: Reflectie** + +> **Tim zegt:** +> "Vergelijk dit met wat er was gebeurd als ik gewoon 'filter werkt niet' in de chat had geplakt. De agent had waarschijnlijk de hele filter functie herschreven. Misschien had dat ook gewerkt, maar je weet dan niet WAAROM het niet werkte. En je leert niks." + +> **Tim zegt:** +> "Onthoud: als je de voorgestelde fix niet begrijpt, is het heel moeilijk om te valideren of de code correct is. Debug Mode helpt je om te BEGRIJPEN wat er mis is. Dat maakt je een betere developer, niet alleen een betere prompter." + +## 6.3 Studenten oefenen (5 min) + +> **Tim zegt:** +> "Probeer het zelf. Introduceer een bug in je eigen code — verander iets kleins in data.ts of een component. Gebruik dan een debug-gerichte prompt om het systematisch op te sporen." + +Suggesties voor bugs om te introduceren: +- Voeg `.toUpperCase()` toe aan de tag filter (zoals Tim deed) +- Verander `filter` naar `find` (retourneert een object i.p.v. een array) +- Verwijder de 'use client' directive van een interactief component +- Zet een verkeerde property naam in een interface (bijv. `titel` i.p.v. `title`) + +--- + +# BLOK 7: Code Review, Testing & Semantic Commits (11:25 – 11:45) + +> **Tim zegt:** +> "Onze app werkt, de bug is gefixt. Nu het laatste grote deel: kwaliteit en versiebeheer. We gaan onze code reviewen, tests schrijven, en dan — eindelijk — committen. Maar dan wel goed." + +## 7.1 Self-review met Cursor (5 min) + +📊 **Slide 15 — Code Review & Tests** + +> **Tim zegt:** +> "Eerst een self-review. We vragen de agent om onze code door te lopen op problemen." + +**Stap 1:** Open een nieuw chat gesprek (Ctrl+L), Agent Mode. + +Tim typt: + +``` +Review de code van mijn LinkVault project. Kijk naar: +- TypeScript type safety (zijn er any types? ontbrekende types?) +- Error handling (wat als een URL ongeldig is? wat als tags leeg zijn?) +- Accessibility (aria labels, keyboard navigatie) +- Consistentie met onze .cursor/rules + +@codebase + +Geef een lijst van issues gesorteerd op prioriteit (hoog/midden/laag). +``` + +> **Tim zegt:** +> "Merk op: ik geef specifiek aan WAAR de agent op moet letten. En ik verwijs naar @codebase zodat hij alles kan doorzoeken." + +**Stap 2:** Bespreek de bevindingen met de klas. + +> **Tim zegt:** +> "Kijk naar wat de agent vindt. Waarschijnlijk een paar dingen: missing error handling, misschien accessibility issues, mogelijk type safety problemen. Dit zijn echte verbeterpunten." + +> **Tim zegt:** +> "Fix de hoge-prioriteit issues nu. De rest kun je als TODO's noteren voor later." + +## 7.2 Tests schrijven (5 min) + +> **Tim zegt:** +> "Nu gaan we tests schrijven. Tests zijn je vangnet. Snel en kort — we testen de data logica." + +**Stap 1:** Nieuw gesprek, Agent Mode. + +Tim typt: + +``` +Schrijf unit tests voor de functies in @src/lib/data.ts. + +Test scenarios: +1. addBookmark — controleer dat een bookmark wordt toegevoegd aan de lijst +2. deleteBookmark — controleer dat een bookmark wordt verwijderd +3. updateBookmark — controleer dat velden worden bijgewerkt +4. getBookmarksByTag — controleer dat filtering correct werkt (ook case-insensitive) +5. Edge case: filteren op een tag die niet bestaat + +Gebruik Vitest. Installeer het als het nog niet in het project zit. +``` + +**Stap 2:** Tests uitvoeren + +```bash +npx vitest run +``` + +> **Tim zegt:** +> "Als alle tests slagen: mooi, onze code doet wat het moet doen. Als er tests falen: dat is ook waardevol. Laat de agent de failing tests analyseren en de code of test fixen." + +**Troubleshooting:** +- **"Vitest niet geinstalleerd":** De agent zou het moeten installeren. Zo niet: `npm install -D vitest` +- **Tests falen:** Gebruik dit als leermoment. "Kijk, de test verwacht X maar krijgt Y." +- **Import errors in tests:** Vaak een probleem met TypeScript path aliases. Laat de agent de vitest config aanpassen. + +## 7.3 Semantic commits met Cursor (8 min) + +📊 **Slide 16 — Git Push + PR** + +> **Tim zegt:** +> "Nu het deel waar alles samenkomt: semantic commits. We hebben de hele les gebouwd zonder te committen. We waren gefocust op leren, niet op versiebeheer. En dat is prima — in de praktijk bouw je ook vaak een tijdje door zonder te committen. Je zit in de flow." + +> **Tim zegt:** +> "Maar nu hebben we een grote uncommitted diff. Alles wat we hebben gebouwd — data model, componenten, filtering, edit feature, debug fix, tests — dat staat allemaal als unstaged changes. Nu gaan we Cursor vragen om dat netjes op te splitsen in logische commits." + +**Stap 1: Stage alles** + +```bash +git add . +``` + +> **Tim zegt:** +> "We stagen alles. Nu gaan we de agent vragen om onze staged changes te analyseren en op te splitsen." + +**Stap 2: Vraag Cursor om semantic commits** + +Tim typt in Agent Mode: + +``` +Bekijk mijn staged changes en maak semantische commits. Verdeel in logische groepen: +- Data model en types +- UI componenten (BookmarkForm, BookmarkCard, BookmarkList) +- Tag filtering feature +- Edit bookmark feature +- Bug fix (case sensitivity in filter) +- Tests + +Gebruik conventional commit format: +- feat: voor nieuwe features +- fix: voor bug fixes +- test: voor tests +- chore: voor configuratie + +Maak de commits in een logische volgorde — data model eerst, dan componenten, dan features. +``` + +> **Tim zegt:** +> "Kijk wat de agent doet. Hij analyseert de diff, groepeert de bestanden, en maakt aparte commits. Iets als:" + +Verwachte output: +1. `feat: add bookmark type definitions and interfaces` +2. `feat: add in-memory data store with CRUD operations` +3. `feat: add bookmark form, card, and list components` +4. `feat: add tag-based filtering with badge counts` +5. `feat: add inline edit bookmark functionality` +6. `fix: resolve case sensitivity bug in tag filtering` +7. `test: add unit tests for bookmark data operations` +8. `chore: add Cursor rules for project conventions` + +> **Tim zegt:** +> "Zie je het verschil met een enkele commit 'app gebouwd'? Elk commit vertelt een verhaal. Als iemand je history bekijkt, kan hij precies zien wat er wanneer is toegevoegd." + +> **Tim zegt:** +> "Misschien denk je: is het niet gek om achteraf losse commits te maken? Nee. In de praktijk bouw je vaak een feature in een flow en commit je pas achteraf. Wat telt is dat de EINDRESULTAAT — je commit history — logisch en leesbaar is. Dit is precies hoe veel professionele developers werken." + +**Stap 3: Verifieer** + +```bash +git log --oneline +``` + +> **Tim zegt:** +> "Mooi. Een schone commit history. Nu kunnen we pushen." + +**Stap 4: Push naar GitHub** + +```bash +git remote add origin https://github.com/[jouw-username]/linkvault.git +git branch -M main +git push -u origin main +``` + +> **Tim zegt:** +> "Als je nog geen GitHub repo hebt aangemaakt, doe dat nu snel via github.com of met `gh repo create linkvault --public`. De gh CLI is handig als je die hebt geinstalleerd." + +**Troubleshooting:** +- **"Cursor maakt niet de juiste commits":** Wees specifieker in je prompt. Geef exact aan welke bestanden bij welke commit horen. +- **"Git push faalt":** Check of je remote correct is ingesteld. `git remote -v` om te checken. +- **Merge conflicts:** Zou niet moeten voorkomen als je alleen op main werkt. Zo wel: `git status` om te zien wat er mis is. + +## 7.4 Kort: PR aanmaken (2 min) + +> **Tim zegt:** +> "In een echt project werk je op een feature branch en maak je een Pull Request aan. De korte versie:" + +```bash +git checkout -b feature/linkvault-mvp +git push -u origin feature/linkvault-mvp +``` + +> **Tim zegt:** +> "Dan maak je een PR aan op GitHub. Je kunt dat via de website doen, of met de gh CLI:" + +```bash +gh pr create --title "feat: LinkVault MVP" --body "Bookmark manager met add, edit, delete, en tag filtering" +``` + +> **Tim zegt:** +> "Die PR kun je dan laten reviewen — door een teamgenoot, of door Cursor zelf. Dat brengt ons bij het optionele blok." + +--- + +# BLOK 8 (Optioneel): PR review met Cursor (11:45 – 11:55) + +**LET OP: Dit is een optioneel blok. Tim beslist tijdens de les of er tijd voor is. Als je achterloopt, sla dit over en ga direct naar de afsluiting.** + +> **Tim zegt:** +> "We hebben nog een paar minuten. Ik wil jullie kort laten zien hoe je Cursor kunt gebruiken om een PR te reviewen. Dit is optioneel — in je huiswerk hoef je dit niet te doen." + +## 8.1 PR review via Cursor Chat + +> **Tim zegt:** +> "Er zijn een paar manieren om Cursor je PR te laten reviewen." + +**Optie 1: @git in de chat** + +> **Tim zegt:** +> "In de Cursor chat kun je `@git` gebruiken om je huidige diff of recente changes als context mee te geven. De agent ziet dan precies wat er is veranderd." + +Tim typt: + +``` +@git Review mijn recente changes. Let op: +- Bugs of logische fouten +- Type safety problemen +- Code kwaliteit en consistentie +- Security issues (bijv. XSS bij user input) + +Geef feedback per bestand. +``` + +**Optie 2: PR URL reviewen** + +> **Tim zegt:** +> "Als je al een PR hebt aangemaakt op GitHub, kun je de URL in de chat plakken." + +``` +Review deze PR: https://github.com/[username]/linkvault/pull/1 + +Let op bugs, type safety, en code kwaliteit. Geef concrete suggesties. +``` + +**Optie 3: gh CLI** + +> **Tim zegt:** +> "Cursor kan ook de `gh` CLI gebruiken om met GitHub te interacteren. Als de agent terminal-toegang heeft, kan hij de PR diff ophalen en analyseren." + +## 8.2 BugBot — Cursor's geautomatiseerde PR review + +> **Tim zegt:** +> "Tot slot, kort: Cursor heeft ook BugBot, een tool die automatisch PRs reviewt als je die activeert. Het scant je code op bugs, security issues, en best practice schendingen. Vergelijkbaar met wat we handmatig net deden, maar dan automatisch bij elke PR. Iets om in de gaten te houden voor je eindproject." + +--- + +# BLOK 9: Afsluiting + huiswerk uitdelen (11:55 – 12:00) + +## 9.1 Samenvatting: 5 Takeaways (3 min) + +📊 **Slide 17 — Samenvatting** + +> **Tim zegt:** +> "Laten we samenvatten wat we vandaag hebben geleerd. Vijf takeaways:" + +> **Tim zegt:** +> "**Takeaway 1 — Rules:** Maak meerdere .cursor/rules bestanden met YAML frontmatter. project.mdc voor always-on regels, en specifieke regels met globs voor componenten en styling. Kort, specifiek, met voorbeelden." + +> **Tim zegt:** +> "**Takeaway 2 — Plan Mode:** Begin ALTIJD met een plan. Shift+Tab, beschrijf wat je wilt, review het plan, edit het, en dan pas bouwen. Dit bespaart je uren." + +> **Tim zegt:** +> "**Takeaway 3 — Context:** Geef de agent de juiste context met @ mentions. @file voor specifieke bestanden, @codebase voor zoeken. Nieuw feature? Nieuw gesprek." + +> **Tim zegt:** +> "**Takeaway 4 — Debug Mode:** Voor complexe bugs: niet gokken, maar systematisch. Hypotheses, logging, reproduceren, analyseren, fixen. Begrijp de fix voordat je accepteert." + +> **Tim zegt:** +> "**Takeaway 5 — Code Review & Commits:** Dezelfde standaard voor AI-code als voor handgeschreven code. Tests schrijven, self-review doen, en semantic commits maken. Je commit history vertelt het verhaal van je project." + +## 9.2 Huiswerk uitdelen (2 min) + +📊 **Slide 18 — Huiswerk** + +> **Tim zegt:** +> "Dan het huiswerk. Deel het huiswerk document uit — dat is een apart bestand met de volledige opdracht." + +Deel het huiswerkbestand uit: **Les09-Huiswerk.md** + +> **Tim zegt:** +> "In het kort: jullie gaan zelf een app bouwen from scratch met alle vijf technieken die we vandaag hebben geleerd. Rules, Plan Mode, Agent Mode, Debug Mode, en Code Review met semantic commits. Alles staat in het document. Lees het goed door." + +> **Tim zegt:** +> "Een paar tips alvast:" +> +> "1. Begin met Plan Mode. Altijd. Plan je hele app voordat je een regel code schrijft." +> +> "2. Maak screenshots TERWIJL je werkt. Achteraf is het lastig om te reconstrueren." +> +> "3. Als je vastloopt: nieuw gesprek, betere prompt, meer context. Niet dezelfde fout herhalen." +> +> "4. Lees de code die de agent schrijft. Je leert er enorm veel van." + +## 9.3 Afsluiting (1 min) + +> **Tim zegt:** +> "Dat was het voor vandaag. Jullie weten nu hoe je Cursor als een echte coding agent gebruikt. Niet als een chatbot die je af en toe iets vraagt, maar als een partner die plant, bouwt, debugt en reviewt. Gebruik het zo, en je wordt een veel effectievere developer." + +> **Tim zegt:** +> "Vragen? Nee? Dan zie ik jullie volgende week. Succes met het huiswerk!" + +--- + +# APPENDIX A: Keyboard Shortcuts Referentie + +| Shortcut | Actie | +|----------|-------| +| `Ctrl+L` | Open chat panel | +| `Ctrl+K` | Inline edit (in een bestand) | +| `Ctrl+I` | Composer openen | +| `Shift+Tab` | Toggle modus (Plan / Agent / Ask) | +| `Tab` | Accept autocomplete suggestie | +| `Esc` | Sluit chat / annuleer | +| `Ctrl+Shift+P` | Command palette | +| `Ctrl+/` | Toggle chat zijbalk | +| `F12` | Browser DevTools (voor debugging) | + +# APPENDIX B: Handige Prompts Referentie + +**Plan Mode — nieuw project plannen:** +``` +Ik wil een [type app] bouwen. Features: [lijst features]. +Technische eisen: [framework, taal, styling]. +Project structuur: [gewenste mappen en bestanden]. +Welke stappen stel je voor? +``` + +**Agent Mode — feature toevoegen:** +``` +Voeg [feature] toe aan [project]. +Context: @[relevant bestand 1] @[relevant bestand 2] +Wat ik wil: [genummerde lijst van eisen] +``` + +**Debug Mode — bug systematisch aanpakken:** +``` +Bug: [beschrijving] +Stappen om te reproduceren: [genummerde stappen] +Verwacht: [wat zou moeten gebeuren] +Werkelijk: [wat er daadwerkelijk gebeurt] +Onderzoek dit systematisch: genereer hypotheses, voeg logging toe. +Relevante bestanden: @[bestand1] @[bestand2] +``` + +**Code Review:** +``` +Review de code van mijn project. Kijk naar: +- TypeScript type safety +- Error handling +- Accessibility +- Consistentie met .cursor/rules +@codebase +Geef een lijst van issues gesorteerd op prioriteit. +``` + +**Tests schrijven:** +``` +Schrijf unit tests voor @[bestand]. +Test scenarios: [lijst van wat je wilt testen] +Gebruik Vitest. +``` + +**Semantic commits:** +``` +Bekijk mijn staged changes en maak semantische commits. +Verdeel in logische groepen: [opsomming van groepen]. +Gebruik conventional commit format (feat:, fix:, test:, chore:). +``` + +# APPENDIX C: Troubleshooting Gids + +| Probleem | Oplossing | +|----------|-----------| +| Agent schrijft code in verkeerde taal/framework | Check je .cursor/rules/project.mdc — staan de juiste regels erin? | +| Agent gaat "off the rails" | Start een nieuw gesprek (Ctrl+L). Meer context, specifiekere prompt. | +| Te veel requests gebruikt | Gebruik Plan Mode om vooraf te plannen. Minder iteraties = minder requests. | +| Agent installeert ongewenste packages | Check of je rule "geen extra dependencies zonder toestemming" bevat. | +| Tailwind classes werken niet | Check of Tailwind correct is geconfigureerd. Restart de dev server. | +| 'use client' vergeten | Voeg aan je rules toe: "'use client' toevoegen aan componenten met useState, useEffect, onClick." | +| TypeScript errors na agent edit | Plak de error in een nieuw gesprek en laat de agent het fixen. | +| Agent maakt te veel bestanden | Wees specifieker in je prompt over welke bestanden je wilt aanpassen. | +| Hot reload werkt niet | Stop de dev server (Ctrl+C) en start opnieuw (npm run dev). | +| YAML frontmatter fout in .mdc | Check: drie streepjes `---` boven en onder, geen spaties ervoor. `alwaysApply` met hoofdletter A bij Apply. | +| Globs werken niet | Check of het pad klopt. Gebruik dubbele sterren voor recursief: `**/*.tsx`. Meerdere patronen scheiden met komma. | + +# APPENDIX D: Tijdmanagement + +| Tijd | Blok | Duur | Flexibiliteit | +|------|------|------|---------------| +| 09:00–09:10 | Welkom + terugblik | 10 min | Kan 2 min uitlopen | +| 09:10–09:35 | Theorie | 25 min | Houd het strak — niet langer dan 30 min | +| 09:35–09:55 | Setup + 3 rules bestanden | 20 min | Kan 5 min uitlopen voor troubleshooting | +| 09:55–10:15 | Plan Mode Demo + Build | 20 min | Kernblok — neem de tijd | +| 10:15–10:30 | Pauze | 15 min | Gebruik voor achterblijvers | +| 10:30–11:05 | Agent Mode oefeningen | 35 min | Kernblok — twee oefeningen + student tijd | +| 11:05–11:25 | Debug Mode | 20 min | Kernblok — niet inkorten | +| 11:25–11:45 | Code Review + Testing + Commits | 20 min | Kernblok — semantic commits is belangrijk | +| 11:45–11:55 | (Optioneel) PR review | 10 min | ALLEEN als er tijd is — Tim beslist | +| 11:55–12:00 | Afsluiting + huiswerk | 5 min | Huiswerk uitdelen is prioriteit | + +**Als je achterloopt:** Sla het optionele PR review blok over. Kort de student-oefentijd in bij Agent Mode. De kernblokken zijn: Setup met 3 rules, Plan Mode, Agent Mode (minimaal 1 oefening samen), Debug Mode, en Semantic Commits. + +**Als je voorloopt:** Doe het PR review blok. Laat studenten extra features bouwen. Ga dieper in op de code review. + +# APPENDIX E: .cursor/rules bestanden — complete referentie + +Hieronder staan de drie bestanden nogmaals voor snelle referentie. + +### project.mdc +```markdown +--- +description: Algemene projectregels voor LinkVault +globs: +alwaysApply: true +--- + +# LinkVault — Projectregels + +## Tech Stack +- Next.js 16 met App Router +- TypeScript in strict mode +- Tailwind CSS voor alle styling +- In-memory data opslag (GEEN database, GEEN Supabase, GEEN Prisma) + +## Taal & Conventies +- Code in het Engels (variabelen, functies, types) +- Comments in het Nederlands +- Commit messages in het Engels (conventional commits) + +## Architectuur +- Server Components als default, 'use client' alleen voor interactieve componenten +- Data logica in src/lib/ +- Componenten in src/components/ +- Types in src/types/ +- App routes in src/app/ + +## Regels +- Geen extra dependencies installeren zonder expliciete toestemming +- Gebruik altijd TypeScript interfaces voor props (geen inline types) +- Exporteer types vanuit een centraal types bestand +- Gebruik named exports, geen default exports (behalve voor page.tsx en layout.tsx) +- Error handling: altijd try-catch bij async operaties +``` + +### components.mdc +```markdown +--- +description: Regels voor React componenten in LinkVault +globs: "src/components/**/*.tsx" +alwaysApply: false +--- + +# Component Regels + +## Structuur +- Functionele componenten met arrow functions +- Props interface boven de component, naam: [ComponentNaam]Props +- Geen default exports — altijd named exports + +## Voorbeeld +interface BookmarkCardProps { + bookmark: Bookmark; + onDelete: (id: string) => void; + onEdit: (id: string, data: Partial) => void; +} + +export const BookmarkCard = ({ bookmark, onDelete, onEdit }: BookmarkCardProps) => { + return ( + // JSX hier + ); +}; + +## Naamgeving +- Componentnaam in PascalCase: BookmarkCard, TagFilter, BookmarkForm +- Bestandsnaam gelijk aan componentnaam: BookmarkCard.tsx +- Een component per bestand + +## State Management +- useState voor lokale UI-state (edit mode, form values) +- Props doorgeven voor data, NIET direct importeren uit data.ts in componenten +- Event handlers als props: onDelete, onEdit, onFilter + +## Accessibility +- Altijd aria-labels op interactieve elementen +- Buttons moeten type="button" of type="submit" hebben +- Formulieren gebruiken form element met onSubmit +``` + +### styles.mdc +```markdown +--- +description: Styling regels voor Tailwind CSS in LinkVault +globs: "**/*.css,**/*.tsx" +alwaysApply: false +--- + +# Styling Regels + +## Tailwind CSS +- Utility-first: gebruik Tailwind classes, GEEN inline styles (geen style={}) +- Geen custom CSS tenzij Tailwind het niet kan +- Gebruik Tailwind's responsive prefixes: sm:, md:, lg: +- Consistent spacing: gebruik Tailwind spacing scale (p-2, p-4, m-2, m-4) + +## Kleuren +- Primary: blue-600 (knoppen, links, accenten) +- Danger: red-500 (verwijder knoppen, waarschuwingen) +- Succes: green-500 (bevestigingen) +- Achtergrond: gray-50 voor pagina, white voor cards +- Tekst: gray-900 voor hoofdtekst, gray-500 voor secundair + +## Layout +- Cards: rounded-lg shadow-sm border border-gray-200 p-4 +- Knoppen: px-4 py-2 rounded-md font-medium +- Formulier inputs: w-full rounded-md border border-gray-300 p-2 +- Pagina container: max-w-4xl mx-auto p-6 + +## Hover & Interactie +- Knoppen: hover:opacity-80 transition-colors +- Cards: hover:shadow-md transition-shadow +- Tags/badges: cursor-pointer hover:opacity-80 rounded-full px-3 py-1 text-sm +``` diff --git a/Les09-Cursor-Deep-Dive/Les09-Huiswerk.md b/Les09-Cursor-Deep-Dive/Les09-Huiswerk.md new file mode 100644 index 0000000..0cd2d35 --- /dev/null +++ b/Les09-Cursor-Deep-Dive/Les09-Huiswerk.md @@ -0,0 +1,314 @@ +# Les 9 Huiswerk: Bouw je eigen app met de 5 Cursor-technieken + +**Vak:** AI-Assisted Development +**Opleiding:** NOVI Hogeschool Utrecht +**Deadline:** Voor de volgende les + +--- + +## Overzicht + +In de les heb je 5 Cursor-technieken geleerd en toegepast op LinkVault. Nu is het tijd om te laten zien dat je deze technieken zelfstandig kunt toepassen. Je gaat een **eigen app** bouwen van scratch -- geen LinkVault! + +--- + +## Kies je app + +Kies een van de volgende projecten (of bedenk er zelf een): + +| Optie | Omschrijving | +|-------|-------------| +| **Recepten app** | Recepten opslaan met ingredienten, bereidingswijze en tags | +| **Film tracker** | Films bijhouden met rating, genre en watchlist | +| **Notitie app** | Notities met categorieen en zoekfunctie | +| **Eigen idee** | Overleg dit eerst met Tim voordat je begint! | + +**Tech stack:** Next.js 16, TypeScript, Tailwind CSS (net als in de les). + +--- + +## Checklist: Wat moet je opleveren? + +Gebruik deze checklist om te controleren of je alles hebt gedaan. Elk punt is **verplicht** (tenzij anders aangegeven). + +- [ ] **1. Cursor Rules** -- `.cursor/rules/` map aangemaakt met minimaal 2 rule bestanden (met YAML frontmatter!) +- [ ] **2. Plan Mode** -- Plan Mode gebruikt om je app te plannen (maak een screenshot van je plan) +- [ ] **3. Agent Mode** -- Agent Mode gebruikt om minimaal 2 features te bouwen +- [ ] **4. Debug Mode** -- Debug Mode gebruikt voor minstens 1 bug (maak een screenshot van je debug sessie) +- [ ] **5. Tests** -- Tests geschreven met de agent (minimaal 3 unit tests) +- [ ] **6. Code Review** -- "Find Issues" gedraaid en eventuele issues gefixt +- [ ] **7. Semantic Commits** -- Semantic commits gemaakt (feat:, fix:, docs:, etc.) +- [ ] **8. GitHub** -- Alles gepusht naar een GitHub repository +- [ ] **9. (Bonus)** -- Pull Request aangemaakt en door Cursor laten reviewen + +--- + +## Wat lever je in? + +1. **GitHub repository link** -- Zorg dat de repo public is (of nodig Tim uit als collaborator) +2. **Korte reflectie (200 woorden)** -- Beantwoord deze vragen: + - Welke Cursor-technieken werkten het beste voor jou? + - Waar liep je vast? + - Wat doe je de volgende keer anders? +3. **Screenshots** van: + - Je Plan Mode plan + - Een Debug Mode sessie + - Je test resultaten (terminal output) + +--- + +## Tips + +- Begin met Plan Mode! Laat Cursor eerst een plan maken voordat je gaat bouwen. +- Commit vroeg en vaak. Gebruik semantic commits vanaf het begin. +- Loop je vast? Gebruik Debug Mode -- beschrijf de fout en laat Cursor helpen. +- Houd je prompt requests in de gaten. Je hebt 500 fast requests per maand op het Student Plan. + +--- + +## Appendix A: Keyboard Shortcuts Reference + +Alle belangrijke Cursor sneltoetsen op een rij: + +| Actie | Windows / Linux | macOS | +|-------|----------------|-------| +| Chat openen | `Ctrl+L` | `Cmd+L` | +| Plan Mode toggle | `Shift+Tab` | `Shift+Tab` | +| Inline Edit | `Ctrl+K` | `Cmd+K` | +| Composer | `Ctrl+I` | `Cmd+I` | +| Autocomplete accepteren | `Tab` | `Tab` | +| Terminal openen | `` Ctrl+` `` | `` Ctrl+` `` | +| Command Palette | `Ctrl+Shift+P` | `Cmd+Shift+P` | + +--- + +## Appendix B: .cursor/rules Templates + +Maak een `.cursor/rules/` map in je project root en voeg daar `.mdc` bestanden toe. Hieronder staan templates die je kunt kopieren en aanpassen voor je eigen project. + +### project.mdc (algemene projectregels) + +```markdown +--- +description: Algemene projectregels en conventies +alwaysApply: true +--- + +# Project Regels + +## Tech Stack +- Next.js 16 met App Router +- TypeScript (strict mode) +- Tailwind CSS voor styling + +## Conventies +- Gebruik functionele componenten met TypeScript interfaces +- Bestandsnamen in kebab-case +- Componenten in PascalCase +- Gebruik `async/await` in plaats van `.then()` chains + +## Mappenstructuur +- `src/app/` -- App Router pagina's en layouts +- `src/components/` -- Herbruikbare componenten +- `src/lib/` -- Utility functies en types +- `src/types/` -- TypeScript type definities +``` + +### components.mdc (componentregels) + +```markdown +--- +description: Regels voor React componenten +globs: + - "src/components/**/*.tsx" + - "src/app/**/*.tsx" +--- + +# Component Regels + +## Structuur +- Elke component heeft een eigen map met index.tsx +- Props worden gedefinieerd als TypeScript interface boven de component +- Gebruik `"use client"` alleen wanneer nodig (interactieve componenten) + +## Styling +- Gebruik Tailwind utility classes +- Geen inline styles +- Gebruik `cn()` helper voor conditionele classes + +## Toegankelijkheid +- Alle images hebben een alt attribuut +- Interactieve elementen hebben aria-labels +- Gebruik semantische HTML elementen +``` + +### styles.mdc (styling regels) + +```markdown +--- +description: Regels voor styling en Tailwind gebruik +globs: + - "src/**/*.css" + - "src/**/*.tsx" +--- + +# Styling Regels + +## Tailwind CSS +- Gebruik de standaard Tailwind kleurenpalet +- Definieer custom kleuren in `tailwind.config.ts` +- Gebruik `dark:` variant voor dark mode support +- Responsive design: mobile-first (`sm:`, `md:`, `lg:`) + +## CSS Bestanden +- Gebruik `globals.css` alleen voor CSS variabelen en base styles +- Geen component-specifieke CSS bestanden -- gebruik Tailwind classes +``` + +--- + +## Appendix C: Prompt Templates + +Goede prompts maken het verschil. Hieronder staan templates die je kunt gebruiken voor elke techniek. + +### 1. Plan Mode prompt + +``` +Ik wil een [app naam] bouwen met Next.js 16, TypeScript en Tailwind CSS. + +De app moet het volgende kunnen: +- [Feature 1] +- [Feature 2] +- [Feature 3] + +Maak een gedetailleerd plan met: +1. Mappenstructuur +2. Benodigde componenten +3. Data model / types +4. Stappen om te bouwen (in volgorde) + +Gebruik de App Router en server components waar mogelijk. +``` + +### 2. Agent Mode feature prompt + +``` +Bouw de [feature naam] feature voor mijn app. + +Wat het moet doen: +- [Beschrijving van de feature] +- [Verwacht gedrag] +- [Edge cases] + +Gebruik bestaande types uit src/types/ en componenten uit src/components/. +Volg de regels in .cursor/rules/. +``` + +### 3. Debug Mode prompt + +``` +Ik krijg de volgende fout: + +[Plak hier de foutmelding of beschrijf het onverwachte gedrag] + +Wat ik verwacht: [beschrijf het verwachte gedrag] +Wat er gebeurt: [beschrijf wat er daadwerkelijk gebeurt] + +Het relevante bestand is [bestandsnaam]. Kun je de bug vinden en fixen? +``` + +### 4. Test writing prompt + +``` +Schrijf unit tests voor [component/functie naam]. + +Test minimaal: +- Het happy path (normaal gebruik) +- Edge cases (lege input, lange strings, etc.) +- Error handling + +Gebruik de bestaande test setup in het project. +``` + +### 5. Semantic commits prompt + +``` +Maak een semantic commit message voor de huidige wijzigingen. + +Gebruik dit formaat: +- feat: voor nieuwe features +- fix: voor bugfixes +- docs: voor documentatie +- style: voor opmaak (geen code wijzigingen) +- refactor: voor code refactoring +- test: voor tests +- chore: voor overige taken + +Houd de message kort en beschrijvend in het Engels. +``` + +### 6. Code review prompt + +``` +Review de code in [bestandsnaam of map]. + +Let op: +- TypeScript best practices +- Performance issues +- Security problemen +- Toegankelijkheid +- Code duplicatie + +Geef concrete suggesties voor verbeteringen. +``` + +--- + +## Appendix D: Troubleshooting + +### Plan Mode verschijnt niet + +| Probleem | Oplossing | +|----------|----------| +| Plan Mode optie niet zichtbaar | Zorg dat je Cursor versie up-to-date is (Help > Check for Updates) | +| Toggle doet niets | Probeer `Shift+Tab` in het chat venster, niet in de editor | +| Plan wordt niet gegenereerd | Zorg dat je prompt duidelijk genoeg is -- geef context over wat je wilt bouwen | + +### Agent Mode voert niets uit + +| Probleem | Oplossing | +|----------|----------| +| Agent maakt geen bestanden aan | Controleer of Agent Mode actief is (niet Ask Mode) in de chat dropdown | +| Agent stopt halverwege | Druk op "Continue" of geef een follow-up prompt | +| Agent maakt fouten | Wees specifieker in je prompt, verwijs naar bestaande bestanden | + +### .cursor/rules worden niet opgepikt + +| Probleem | Oplossing | +|----------|----------| +| Rules hebben geen effect | Controleer dat de map `.cursor/rules/` heet (niet `.cursor/rule/`) | +| YAML frontmatter fout | Controleer de `---` blokken bovenaan elk `.mdc` bestand | +| Globs matchen niet | Check je glob patronen -- `src/**/*.tsx` matcht alles onder src/ | +| Bestanden staan verkeerd | De `.cursor/` map moet in je project root staan | + +### Tests draaien niet + +| Probleem | Oplossing | +|----------|----------| +| `npm test` geeft fout | Controleer of Vitest of Jest is geinstalleerd: `npm install -D vitest` | +| Tests worden niet gevonden | Bestandsnaam moet eindigen op `.test.ts` of `.test.tsx` | +| Import errors in tests | Controleer je `tsconfig.json` paths en test configuratie | +| Module not found | Voer `npm install` uit om dependencies te installeren | + +### Git / GitHub problemen + +| Probleem | Oplossing | +|----------|----------| +| `git push` geeft permission denied | Controleer of je SSH key of personal access token is ingesteld | +| Repo niet gevonden op GitHub | Maak eerst een repo aan op github.com en volg de instructies | +| Merge conflicts | Gebruik `git status` om conflicten te zien, los ze op in Cursor | +| Vergeten te committen | `git add .` en daarna `git commit -m "feat: beschrijving"` | + +--- + +Veel succes en plezier met bouwen! Kom je er niet uit, stel je vraag in het les-kanaal. diff --git a/Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md b/Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md new file mode 100644 index 0000000..0bb4488 --- /dev/null +++ b/Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md @@ -0,0 +1,943 @@ +# Les 9 -- Slide-overzicht +## Cursor Deep Dive: Van Agent Harness tot Code Review (18 slides) + +**Cursus:** AI Developer -- NOVI Hogeschool Utrecht +**Duur:** 3 uur (180 minuten) | 09:00 - 12:00 +**Project:** LinkVault -- een bookmark manager (in-memory, geen database) + +> **Voorkennis studenten:** Cursor basics uit Les 3 (Chat, Inline Edit, Composer, Tab, @ Mentions, .cursorrules, Skills/Docs). Next.js 16, TypeScript, Tailwind uit eerdere lessen. Studenten hebben Cursor al geinstalleerd met een actief abonnement. + +--- + +## Timing-overzicht + +| Tijd | Duur | Onderwerp | Slide(s) | Vorm | +|------|------|-----------|----------|------| +| 09:00 - 09:10 | 10 min | Welkom + terugblik | 1 - 2 | Klassikaal | +| 09:10 - 09:35 | 25 min | Theorie: Agent Harness, Rules, Plan Mode, Debug Mode, Code Review | 3 - 9 | Klassikaal | +| 09:35 - 09:55 | 20 min | Setup: nieuw project + 3 .cursor/rules bestanden | 10 - 11 | Samen | +| 09:55 - 10:15 | 20 min | Plan Mode: plan LinkVault, review, Build | 12 | Klassikaal | +| 10:15 - 10:30 | 15 min | Pauze | -- | -- | +| 10:30 - 11:05 | 35 min | Agent Mode: features bouwen | 13 | Klassikaal | +| 11:05 - 11:25 | 20 min | Debug Mode: Tim's bug vinden en fixen | 14 | Klassikaal | +| 11:25 - 11:45 | 20 min | Code Review & Testing + Semantic commits + Git push | 15 - 16 | Klassikaal | +| 11:45 - 11:55 | 10 min | (Optioneel) PR review met Cursor | 16 | Klassikaal | +| 11:55 - 12:00 | 5 min | Afsluiting + huiswerk | 17 - 18 | Klassikaal | + +--- + +## Slide-indeling + +--- + +### Slide 1: Titelslide +**Timing:** 09:00 - 09:05 (5 min) + +**Titel:** Les 9 -- Cursor Deep Dive +**Ondertitel:** Van Agent Harness tot Code Review -- LinkVault bouwen + +``` ++========================================================+ +| | +| LES 9: CURSOR DEEP DIVE | +| | +| Van Agent Harness tot Code Review | +| LinkVault bouwen met 5 Agent-technieken | +| | +| Tim -- NOVI Hogeschool Utrecht | +| | ++========================================================+ +``` + +**Spreektekst:** +- Welkom bij les 9. Vandaag gaan we diep in Cursor. +- We bouwen een complete app: LinkVault, een bookmark manager. +- Jullie hebben Cursor al draaien met een abonnement -- we gaan er direct mee aan de slag. + +--- + +### Slide 2: Planning Vandaag +**Timing:** 09:05 - 09:10 (5 min) + +``` ++========================================================+ +| PLANNING VANDAAG | +| | +| 09:00 Welkom + terugblik | +| 09:10 Theorie: hoe werkt een coding agent? | +| 09:35 Setup: project + rules | +| 09:55 Plan Mode: LinkVault plannen | +| 10:15 -- PAUZE -- | +| 10:30 Agent Mode: features bouwen | +| 11:05 Debug Mode: bug opsporen | +| 11:25 Code Review + commits + push | +| 11:45 (Optioneel) PR review | +| 11:55 Afsluiting + huiswerk | ++========================================================+ + + LEERDOELEN: + +----------------------------------------------------+ + | 1. Agent Harness begrijpen (rules + tools + model) | + | 2. .cursor/rules met YAML frontmatter schrijven | + | 3. Plan Mode workflow beheersen | + | 4. Debug Mode systematisch toepassen | + | 5. Code Review + semantic commits + push | + +----------------------------------------------------+ +``` + +**Spreektekst:** +- Dit is het programma. We bouwen alles stap voor stap in Cursor. +- Aan het eind hebben jullie een werkende LinkVault-app met nette commits op GitHub. +- De PR review is optioneel -- alleen als we tijd over hebben. + +--- + +### Slide 3: Hoe werkt een Coding Agent? +**Timing:** 09:10 - 09:15 (5 min) + +``` ++========================================================+ +| HOE WERKT EEN CODING AGENT? | +| | +| Een coding agent is een LLM met een "harness": | +| een systeem dat het model aanstuurt. | +| | +| +--------------------------------------------------+ | +| | AGENT HARNESS | | +| | | | +| | +------------+ +----------+ +--------+ | | +| | |INSTRUCTIONS| | TOOLS | | MODEL | | | +| | | | | | | | | | +| | | .cursor/ | | file edit| | Claude | | | +| | | rules/ | | search | | GPT-4o | | | +| | | prompts | | terminal | | etc. | | | +| | +-----+------+ +----+-----+ +---+----+ | | +| | | | | | | +| | +-------+-------+------+-------+ | | +| | | | | | +| | [ AGENT LOOP ] | | +| | think -> act -> observe -> repeat | | +| +--------------------------------------------------+ | ++========================================================+ +``` + +**Kernpunten:** +- **Instructions:** regels die je meegeeft (system prompt + rules bestanden) +- **Tools:** wat de agent KAN doen (bestanden lezen/schrijven, terminal, zoeken) +- **Model:** het LLM dat beslissingen neemt (Claude, GPT-4o, etc.) +- De agent draait in een **loop**: denken, actie, observeren, herhalen +- Cursor IS zo'n harness. Jij geeft de instructions, Cursor levert tools + model. + +**Spreektekst:** +- Een coding agent is meer dan een chatbot. Het is een LLM dat in een harness draait — een systeem met drie onderdelen. +- Instructions: dat zijn de regels die je meegeeft. Jouw rules-bestanden plus de system prompt van Cursor zelf. +- Tools: de agent kan bestanden lezen, bewerken, door je code zoeken, en commando's uitvoeren in de terminal. Dat is het verschil met ChatGPT — hij kan daadwerkelijk dingen doen in je project. +- Model: het AI-model dat de beslissingen neemt. Claude, GPT-4o, et cetera. +- De agent werkt in een loop: denken, actie uitvoeren, het resultaat bekijken, en herhalen. Net zoals jij als developer zou doen. +- Cursor IS zo'n harness. Jij levert de instructions via rules-bestanden, Cursor levert de tools en het model. + +--- + +### Slide 4: Rules & Skills +**Timing:** 09:15 - 09:20 (5 min) + +``` ++========================================================+ +| RULES & SKILLS | +| | +| .cursor/rules/ directory -- drie types: | +| | +| +--------------------------------------------------+ | +| | TYPE | HOE? | VOORBEELD | | +| |-----------------|----------------|----------------| | +| | Always-on | alwaysApply: | project.mdc | | +| | | true | (tech stack, | | +| | | | conventies) | | +| |-----------------|----------------|----------------| | +| | Auto-attached | globs: | components.mdc | | +| | | "src/**/*.tsx" | (component | | +| | | | regels) | | +| |-----------------|----------------|----------------| | +| | Agent-requested | description: | api-design.mdc | | +| | | "use when..." | (wordt opge- | | +| | | | vraagd) | | +| +--------------------------------------------------+ | +| | +| VUISTREGEL: Houd rules MINIMAAL en SPECIFIEK. | +| Te veel regels = ruis = slechtere output. | +| | +| SKILLS = dynamische rules (bv. @docs, @web). | +| Cursor kan zelf beslissen welke skills te gebruiken. | ++========================================================+ +``` + +**Kernpunten:** +- Elke `.mdc` file heeft YAML frontmatter bovenaan +- **alwaysApply: true** = altijd meegestuurd naar het model +- **globs** = alleen meegestuurd als je werkt in bestanden die matchen +- **description** = agent kan het zelf ophalen als het relevant lijkt +- Minder is meer. 3-5 regels per bestand. Geen roman schrijven. + +**Spreektekst:** +- In Les 3 hadden jullie een enkel .cursorrules bestand. Dat werkt nog steeds, maar Cursor heeft nu een veel krachtiger systeem: de .cursor/rules directory. +- Elk bestand is een .mdc file — Markdown Configuration — met YAML frontmatter bovenaan. +- Er zijn drie types. Always-on rules met alwaysApply: true — die staan altijd aan. Gebruik dit voor je project.mdc met tech stack en conventies. +- Auto-attached rules met een globs patroon. Werk je in een TSX-bestand? Dan laadt Cursor automatisch je components.mdc. Slim en efficiënt. +- En agent-requested rules: de agent kan zelf rules opvragen als hij denkt dat ze relevant zijn. Dat gebruiken we vandaag niet actief. +- Vuistregel: houd je rules kort en specifiek. Teveel regels is ruis, en ruis levert slechtere output. +- Skills zijn dynamische rules die Cursor automatisch kan laden. Die laten we even voor wat het is vandaag. + +--- + +### Slide 5: Context Management +**Timing:** 09:20 - 09:25 (5 min) + +``` ++========================================================+ +| CONTEXT MANAGEMENT | +| | +| Het model heeft BEPERKT werkgeheugen (context window). | +| Elk gesprek begint "leeg". Nieuwe feature = NIEUWE CHAT.| +| | +| CONTEXT TOEVOEGEN: | +| +--------------------------------------------------+ | +| | @file | specifiek bestand meegeven | | +| | @folder | hele map als context | | +| | @codebase | Cursor doorzoekt je project | | +| | @web | zoekt het internet | | +| | @docs | doorzoekt documentatie | | +| +--------------------------------------------------+ | +| | +| TIPS: | +| +--------------------------------------------------+ | +| | - Combineer: @file layout.tsx + @docs Next.js | | +| | - Nieuwe feature? Start ALTIJD een nieuwe chat | | +| | - Lang gesprek? Context raakt vervuild | | +| | - Geef RELEVANTE context, niet ALLES | | +| +--------------------------------------------------+ | ++========================================================+ +``` + +**Kernpunten:** +- Context window = werkgeheugen van het model. Alles wat je toevoegt kost ruimte. +- Nieuwe feature = nieuwe chat. Dit is de belangrijkste tip van vandaag. +- @codebase laat Cursor zoeken, maar wees specifiek in je vraag. +- Combineer @ mentions voor maximale relevantie. + +**Spreektekst:** +- Context is misschien het allerbelangrijkste concept. De agent weet alleen wat je hem vertelt. +- Denk aan de agent als een briljante developer die net op je project begint. Hij kent de taal en frameworks, maar JOUW code kent hij niet. Jij moet hem vertellen waar hij moet kijken. +- Met @ mentions voeg je context toe: @file voor een specifiek bestand, @folder voor een hele map, @codebase om Cursor je project te laten doorzoeken. +- Je kunt ze combineren: '@data.ts @BookmarkCard.tsx — voeg een edit knop toe'. Dan heeft de agent precies de bestanden die hij nodig heeft. +- De allerbelangrijkste tip: nieuwe feature, nieuwe chat. Na teveel heen-en-weer raakt de context vervuild en gaat de agent afdwalen. + +--- + +### Slide 6: Plan Mode +**Timing:** 09:25 - 09:30 (5 min) + +``` ++========================================================+ +| PLAN MODE (Shift+Tab) | +| | +| Start ELKE feature met een plan! | +| | +| WORKFLOW: | +| +--------------------------------------------------+ | +| | | | +| | 1. RESEARCH Vraag Cursor om te onderzoeken | | +| | | (bestaande code, docs, structuur) | | +| | v | | +| | 2. VRAGEN Stel vragen, krijg opties | | +| | | | | +| | v | | +| | 3. PLAN Cursor schrijft plan in markdown | | +| | | | | +| | v | | +| | 4. EDIT JIJ reviewt en past het plan aan | | +| | | | | +| | v | | +| | 5. BUILD Tab terug naar Agent Mode | | +| | en voer het plan uit | | +| | | | +| +--------------------------------------------------+ | +| | +| WAAROM? Voorkomt dat de agent meteen gaat bouwen | +| zonder na te denken. Jij houdt de controle. | ++========================================================+ +``` + +**Kernpunten:** +- Shift+Tab schakelt naar Plan Mode +- De agent denkt NA maar voert NIET uit -- geen file edits +- Jij reviewt het plan voordat er code geschreven wordt +- Na goedkeuring: Tab terug naar Agent Mode om het plan uit te voeren +- Dit is hoe professionals met agents werken + +**Spreektekst:** +- Dit is DE belangrijkste workflow van vandaag. Plan Mode. Begin ALTIJD met een plan. +- Hoe werkt het? Open de chat met Ctrl+L, druk Shift+Tab om naar Plan Mode te schakelen. De agent gaat dan NIET meteen code schrijven — hij doet eerst research en maakt een stap-voor-stap plan. +- Dat plan is bewerkbaar. Jij kunt stappen schrappen, toevoegen, herschrijven. Agent te ambitieus? Schrap die stappen. +- Pas als je tevreden bent, schakel je terug naar Agent Mode en laat je het plan uitvoeren. +- Waarom zo belangrijk? Geen plan betekent dat de agent z'n eigen gang gaat. Dan ben je uren bezig met fixen. Een goed plan levert gerichte output en minder iteraties. Dat spaart je requests. + +--- + +### Slide 7: Agent Mode vs Ask Mode +**Timing:** 09:30 - 09:33 (3 min) + +``` ++========================================================+ +| AGENT MODE vs ASK MODE | +| | +| +------------------------+ +----------------------+ | +| | AGENT MODE | | ASK MODE | | +| | (Tab) | | (Tab Tab) | | +| | | | | | +| | - VOERT UIT | | - ANTWOORDT ALLEEN | | +| | - Edit bestanden | | - Geen file edits | | +| | - Draait terminal | | - Geen terminal | | +| | - Maakt nieuwe files | | - Alleen uitleg | | +| | | | | | +| | Gebruik voor: | | Gebruik voor: | | +| | - Features bouwen | | - Code begrijpen | | +| | - Refactoring | | - Concepten leren | | +| | - Bug fixen | | - Architectuur- | | +| | - Tests schrijven | | beslissingen | | +| +------------------------+ +----------------------+ | +| | +| VUISTREGEL: | +| "Moet er code veranderen?" -> Agent Mode | +| "Wil ik iets begrijpen?" -> Ask Mode | ++========================================================+ +``` + +**Kernpunten:** +- Agent Mode is de standaard -- hier bouw je mee +- Ask Mode is voor vragen stellen zonder dat er iets verandert +- Wisselen met Tab (Agent) of dubbel Tab (Ask) +- Plan Mode (Shift+Tab) is een derde optie: denken zonder uitvoeren + +**Spreektekst:** +- In Cursor heb je twee modes in de chat: Agent en Ask. Het verschil is simpel. +- Ask Mode is voor vragen. 'Hoe werkt useEffect?' of 'Leg deze code uit.' De agent leest, maar raakt niks aan. +- Agent Mode is voor actie. De agent kan bestanden aanmaken, bewerken, verwijderen, en terminal commando's uitvoeren. Multi-file edits, refactoring, nieuwe features — dat doe je in Agent Mode. +- Vuistregel: moet er code veranderen? Agent Mode. Wil je iets begrijpen? Ask Mode. +- Vandaag werken we vooral in Agent Mode en Plan Mode. + +--- + +### Slide 8: Debug Mode +**Timing:** 09:33 - 09:36 (3 min) + +``` ++========================================================+ +| DEBUG MODE | +| | +| NIET: error kopieer-plakken en hopen op het beste. | +| WEL: systematisch debuggen met de agent. | +| | +| WORKFLOW: | +| +--------------------------------------------------+ | +| | | | +| | 1. HYPOTHESES "Wat kan dit veroorzaken?" | | +| | | | | +| | v | | +| | 2. LOGGING Voeg console.log / breakpoints | | +| | | toe op strategische plekken | | +| | v | | +| | 3. REPRODUCE Reproduceer de bug | | +| | | | | +| | v | | +| | 4. ANALYZE Bekijk output, beperk scope | | +| | | | | +| | v | | +| | 5. TARGETED FIX Pas alleen aan wat nodig is | | +| | | | +| +--------------------------------------------------+ | +| | +| TIP: Geef Cursor de CONTEXT. Welk bestand? | +| Welke functie? Wat verwacht je? Wat gebeurt er? | ++========================================================+ +``` + +**Kernpunten:** +- Debug Mode is een mindset, niet een knop +- Stuur de agent met hypotheses, niet met "fix this" +- Voeg logging toe VOORDAT je gaat fixen +- Gerichte fix > shotgun approach + +**Spreektekst:** +- Debug Mode is een aanpak, niet een knop. Het verschil: bij een simpele bug plak je de error in de chat en de agent fixt het. Dat werkt voor de makkelijke gevallen. +- Maar bij complexe bugs heb je een systematische aanpak nodig. De agent genereert hypotheses over wat er mis kan zijn, voegt logging toe op strategische plekken, vraagt jou om de bug te reproduceren, analyseert de logs, en stelt dan een gerichte fix voor. +- Niet gokken, maar bewijzen. Dat is het verschil. +- We gaan dit straks live doen. Ik ga bewust een bug in onze code plaatsen en dan laten zien hoe je die systematisch opspoort. + +--- + +### Slide 9: Code Review & Testing +**Timing:** 09:36 - 09:40 (4 min -- afronden theorie) + +``` ++========================================================+ +| CODE REVIEW & TESTING | +| | +| 1. FIND ISSUES (Cursor's built-in feature) | +| Cursor scant je code op problemen | +| | +| 2. TESTS SCHRIJVEN | +| Vraag Agent Mode om tests te genereren | +| Prompt: "Schrijf unit tests voor [bestand]" | +| | +| 3. SEMANTIC COMMITS | +| +--------------------------------------------------+ | +| | WORKFLOW: Bouw ALLES eerst. Aan het eind: | | +| | | | +| | feat: nieuwe feature | | +| | fix: bugfix | | +| | refactor: code verbetering | | +| | test: tests toevoegen | | +| | docs: documentatie | | +| | chore: overig (config, deps) | | +| | | | +| | -> Bouw alles in 1 sessie | | +| | -> Aan het einde: splits in logische commits | | +| | -> Dan pas push naar GitHub | | +| +--------------------------------------------------+ | +| | +| 4. PR REVIEW (optioneel, als tijd het toelaat) | +| Cursor kan een PR reviewen als code reviewer | ++========================================================+ +``` + +**Kernpunten:** +- Find Issues = Cursor's self-review feature +- Tests schrijven met Agent Mode (niet handmatig) +- Semantic commits: NIET na elke wijziging committen +- Realistisch: bouw alles, splits achteraf in nette commits +- PR review is optioneel vandaag + +**Spreektekst:** +- Het laatste theorieblok, en misschien het belangrijkste voor je professionele ontwikkeling. +- Voordat je iemand anders vraagt om je code te reviewen, doe je altijd eerst een self-review. Dat geldt ook voor AI-geschreven code. Cursor heeft een Find Issues feature die je code scant op problemen. +- Daarnaast kun je de agent vragen om tests te schrijven. Tests zijn je vangnet. +- En dan semantic commits. In plaats van een grote commit met 'app gebouwd', verdeel je je wijzigingen in logische groepen met prefixes als feat:, fix:, test:. +- Maar — en dit is belangrijk — je hoeft niet na elke stap te committen. Vandaag bouwen we alles eerst af, en aan het eind splitsen we de diff op in nette commits. Dat is een realistische workflow. +- Dezelfde standaard voor AI-code als voor handgeschreven code. + +--- + +> **CHECKPOINT THEORIE** +> Vraag aan de klas: "Noem de drie onderdelen van een Agent Harness." +> Verwacht antwoord: Instructions, Tools, Model. + +--- + +### Slide 10: Setup -- Nieuw Project +**Timing:** 09:40 - 09:50 (10 min -- samen doen) + +``` ++========================================================+ +| SETUP: NIEUW PROJECT | +| | +| STAP 1: Maak een nieuw Next.js 16 project | +| | +| $ npx create-next-app@latest linkvault | +| | +| TypeScript? Yes | +| ESLint? Yes | +| Tailwind CSS? Yes | +| src/ directory? Yes | +| App Router? Yes | +| Import alias? @/* (default) | +| | +| STAP 2: Open in Cursor | +| | +| $ cd linkvault | +| $ cursor . | +| | +| STAP 3: Maak de rules directory | +| | +| $ mkdir -p .cursor/rules | +| | ++========================================================+ +``` + +**Spreektekst:** +- We maken een nieuw project. Next.js 16, de nieuwste versie. +- Iedereen doet dit samen. Als je vast zit, steek je hand op. +- Na het project openen we het in Cursor. + +> **CHECKPOINT SETUP PROJECT** +> Iedereen moet `linkvault` open hebben in Cursor voordat we verder gaan. + +--- + +### Slide 11: Setup -- .cursor/rules +**Timing:** 09:50 - 09:55 (5 min -- samen doen) + +``` ++========================================================+ +| SETUP: .cursor/rules (3 bestanden) | +| | +| .cursor/ | +| rules/ | +| project.mdc <- altijd actief | +| components.mdc <- bij .tsx bestanden | +| styles.mdc <- bij .css en .tsx bestanden | ++========================================================+ + + BESTAND 1: .cursor/rules/project.mdc + +------------------------------------------------------+ + | --- | + | description: General project rules for LinkVault | + | alwaysApply: true | + | --- | + | | + | # LinkVault Project Rules | + | | + | - Tech stack: Next.js 16, TypeScript, Tailwind CSS | + | - Use App Router (src/app/) | + | - All components in src/components/ | + | - Use English for code, Dutch for UI text | + | - Prefer server components unless interactivity | + | is needed | + +------------------------------------------------------+ + + BESTAND 2: .cursor/rules/components.mdc + +------------------------------------------------------+ + | --- | + | description: Rules for TSX component files | + | globs: "src/components/**/*.tsx" | + | --- | + | | + | # Component Rules | + | | + | - Functional components only (no class components) | + | - Define Props interface above the component | + | - Use PascalCase for component names | + | - Export as named export, not default | + | - Keep components under 80 lines | + +------------------------------------------------------+ + + BESTAND 3: .cursor/rules/styles.mdc + +------------------------------------------------------+ + | --- | + | description: Tailwind and styling rules | + | globs: "**/*.css,**/*.tsx" | + | --- | + | | + | # Styling Rules | + | | + | - Tailwind utility-first: use className, not | + | inline styles | + | - No custom CSS unless absolutely necessary | + | - Color scheme: slate-50 bg, blue-600 primary, | + | slate-800 text | + | - Responsive: mobile-first with sm:/md:/lg: | + | - Dark mode: use dark: variant where applicable | + +------------------------------------------------------+ +``` + +**Spreektekst:** +- Maak deze drie bestanden aan in `.cursor/rules/`. +- Let op de YAML frontmatter bovenaan (tussen de `---`). +- `project.mdc` is altijd actief door `alwaysApply: true`. +- `components.mdc` wordt automatisch geladen als je in `.tsx` bestanden werkt. +- `styles.mdc` geldt voor zowel `.css` als `.tsx` bestanden. +- Houd regels kort en concreet. Geen lange verhalen. + +> **CHECKPOINT RULES** +> Iedereen opent `.cursor/rules/` en laat zien: 3 bestanden met YAML frontmatter. + +--- + +### Slide 12: Plan Mode Demo +**Timing:** 09:55 - 10:15 (20 min) + +``` ++========================================================+ +| PLAN MODE: LINKVAULT PLANNEN | +| | +| STAP 1: Open een NIEUWE chat in Cursor | +| STAP 2: Druk Shift+Tab (Plan Mode) | +| STAP 3: Gebruik deze prompt: | +| | +| +--------------------------------------------------+ | +| | "Plan een bookmark manager app genaamd LinkVault. | | +| | Features: | | +| | - Bookmarks toevoegen (URL + titel + tags) | | +| | - Bookmarks weergeven in een lijst | | +| | - Filteren op tags | | +| | - Bookmarks verwijderen | | +| | - In-memory opslag (geen database) | | +| | Maak een gedetailleerd implementatieplan." | | +| +--------------------------------------------------+ | +| | +| WAT TE VERWACHTEN: | +| - Cursor maakt een markdown plan | +| - Bestandsstructuur, componenten, types | +| - GEEN code -- alleen het plan | +| | +| HOE TE REVIEWEN: | +| - Klopt de bestandsstructuur? | +| - Zijn alle features meegenomen? | +| - Past het bij onze rules? | +| - Pas het plan AAN als iets niet klopt | +| | +| NA REVIEW: Tab terug -> Agent Mode -> "Voer het | +| plan uit" | ++========================================================+ +``` + +**Spreektekst:** +- We doen dit samen. Ik laat het voor zien, jullie volgen mee. +- Let op hoe Cursor nadenkt ZONDER code te schrijven. +- Dit is het moment om het plan aan te passen. Straks is het te laat. +- Na review schakelen we naar Agent Mode om het plan uit te laten voeren. +- Cursor bouwt dan de basis: types, componenten, pagina. + +> **CHECKPOINT PLAN MODE** +> Iedereen heeft een plan gereviewed en de basis van LinkVault draait lokaal. +> Test: `npm run dev` -> open `localhost:3000` -> je ziet de app. + +--- + +### Slide 13: Agent Mode -- Features bouwen +**Timing:** 10:30 - 11:05 (35 min, na pauze) + +``` ++========================================================+ +| AGENT MODE: FEATURES BOUWEN | +| | +| We bouwen nu extra features met Agent Mode. | +| Start ELKE feature met een NIEUWE CHAT. | +| | +| FEATURE 1: Edit Bookmark | +| +--------------------------------------------------+ | +| | "Voeg een edit-functie toe aan bookmarks. | | +| | Een gebruiker moet de titel, URL en tags van | | +| | een bestaande bookmark kunnen wijzigen. | | +| | Gebruik een modal of inline edit." | | +| +--------------------------------------------------+ | +| | +| FEATURE 2: Tag Filtering | +| +--------------------------------------------------+ | +| | "Voeg tag filtering toe. Toon alle unieke tags | | +| | als klikbare chips boven de lijst. Als een tag | | +| | geselecteerd is, toon alleen bookmarks met die | | +| | tag. Toon ook een 'Alles' optie." | | +| +--------------------------------------------------+ | +| | +| ITEREREN: | +| - Niet tevreden? Geef feedback in DEZELFDE chat | +| - "Maak de chips kleiner" | +| - "Voeg een hover effect toe" | +| - "De filter werkt niet als er spaties in tags staan" | +| | +| NIEUWE FEATURE = NIEUWE CHAT (context management!) | ++========================================================+ +``` + +**Spreektekst:** +- Na de pauze gaan we bouwen. +- Elke feature in een nieuwe chat -- dit is belangrijk voor context management. +- Ik laat Feature 1 voor zien, dan doen jullie Feature 2 zelf. +- Itereer in dezelfde chat als je kleine aanpassingen wilt. +- Niet tevreden met het resultaat? Geef specifieke feedback. + +--- + +### Slide 14: Debug Mode -- Tim's Bug +**Timing:** 11:05 - 11:25 (20 min) + +``` ++========================================================+ +| DEBUG MODE: TIM'S BUG | +| | +| Tim heeft HANDMATIG een bug geintroduceerd in de | +| filter-logica. | +| | +| DE BUG: In het filter-component is | +| tag | +| veranderd naar | +| tag.toUpperCase() | +| in de vergelijking. | +| | +| EFFECT: Tags worden opgeslagen als "react" maar | +| gefilterd als "REACT" -> geen match -> filter "werkt | +| niet". | +| | +| +--------------------------------------------------+ | +| | STAP 1: Reproduceer | | +| | Voeg bookmark toe met tag "react" | | +| | Klik op filter "react" | | +| | -> Geen resultaten! | | +| | | | +| | STAP 2: Debug prompt | | +| | "De tag filter werkt niet. Als ik klik op | | +| | de tag 'react' worden geen bookmarks | | +| | getoond, terwijl er bookmarks zijn met die | | +| | tag. Onderzoek de filter-logica." | | +| | | | +| | STAP 3: Volg Cursor's analyse | | +| | - Cursor onderzoekt het filter-component | | +| | - Vindt de toUpperCase() mismatch | | +| | - Stelt een fix voor | | +| | | | +| | STAP 4: Review de fix | | +| | Klopt de fix? Accept of pas aan. | | +| +--------------------------------------------------+ | ++========================================================+ +``` + +**Spreektekst (voor Tim):** +- Voordat jullie gaan debuggen, introduceer ik even een bug. +- Ik verander in het filter-component `tag` naar `tag.toUpperCase()`. +- Dit is een realistische bug: case-sensitivity in vergelijkingen. +- Jullie taak: gebruik Debug Mode om de bug te vinden en te fixen. +- Geef Cursor goede context: wat werkt niet, wat verwacht je, wat gebeurt er? + +> **CHECKPOINT DEBUG** +> Iedereen heeft de bug gevonden en gefixt. De filter werkt weer. + +--- + +### Slide 15: Code Review & Tests +**Timing:** 11:25 - 11:40 (15 min) + +``` ++========================================================+ +| CODE REVIEW & TESTS | +| | +| STAP 1: Find Issues | +| +--------------------------------------------------+ | +| | Gebruik Cursor's "Find Issues" feature | | +| | Cursor scant je code en rapporteert problemen | | +| | -> Fix wat je vindt | | +| +--------------------------------------------------+ | +| | +| STAP 2: Tests schrijven (nieuwe chat!) | +| +--------------------------------------------------+ | +| | "Schrijf unit tests voor de bookmark filter | | +| | logica. Test dat: | | +| | - Filteren op een bestaande tag werkt | | +| | - 'Alles' toont alle bookmarks | | +| | - Case-insensitive filtering werkt" | | +| +--------------------------------------------------+ | +| | +| STAP 3: Semantic Commits | +| +--------------------------------------------------+ | +| | Nu pas committen! Splits je werk in logische | | +| | commits met semantic prefixes: | | +| | | | +| | $ git add src/types/ | | +| | $ git commit -m "feat: add bookmark types | | +| | and interfaces" | | +| | | | +| | $ git add src/components/BookmarkForm.tsx | | +| | $ git commit -m "feat: add bookmark creation | | +| | form with tag support" | | +| | | | +| | $ git add src/components/TagFilter.tsx | | +| | $ git commit -m "feat: add tag filtering | | +| | with chip-based UI" | | +| | | | +| | $ git add src/components/__tests__/ | | +| | $ git commit -m "test: add unit tests for | | +| | tag filter logic" | | +| | | | +| | $ git add src/components/TagFilter.tsx | | +| | $ git commit -m "fix: resolve case-sensitivity | | +| | bug in tag filtering" | | +| +--------------------------------------------------+ | ++========================================================+ +``` + +**Spreektekst:** +- Nu gaan we ons werk opschonen. +- Eerst: Find Issues -- laat Cursor je code scannen. +- Dan: tests schrijven voor de filter-logica. +- Tot slot: alles committen. NIET alles in een commit! +- We splitsen in logische, semantische commits. +- Dit is hoe het in de echte wereld werkt: je bouwt eerst, dan maak je de history netjes. + +--- + +### Slide 16: Git Push + PR +**Timing:** 11:40 - 11:55 (15 min, waarvan 10 min optioneel) + +``` ++========================================================+ +| GIT PUSH + PR | +| | +| STAP 1: Push naar GitHub | +| +--------------------------------------------------+ | +| | $ git remote add origin | | +| | https://github.com/[jouw-username]/linkvault | | +| | $ git push -u origin main | | +| +--------------------------------------------------+ | +| | +| STAP 2: Maak een PR (als je op een branch werkt) | +| +--------------------------------------------------+ | +| | $ git checkout -b feature/linkvault-v1 | | +| | $ git push -u origin feature/linkvault-v1 | | +| | -> Open GitHub -> Create Pull Request | | +| +--------------------------------------------------+ | +| | +| ============= OPTIONEEL (als tijd het toelaat) ====== | +| | +| STAP 3: PR Review met Cursor | +| +--------------------------------------------------+ | +| | Cursor kan PRs reviewen als code reviewer. | | +| | Open de PR URL in Cursor en vraag: | | +| | "Review deze PR. Focus op code kwaliteit, | | +| | mogelijke bugs, en best practices." | | +| | | | +| | Dit is OPTIONEEL. Alleen doen als er tijd is. | | +| +--------------------------------------------------+ | +| | ++========================================================+ +``` + +**Spreektekst:** +- Push je werk naar GitHub. Maak een repo aan als je die nog niet hebt. +- Als we tijd over hebben, laat ik zien hoe Cursor een PR kan reviewen. +- Dit is optioneel -- het belangrijkste is dat je code gepusht is. + +--- + +### Slide 17: Samenvatting +**Timing:** 11:55 - 11:58 (3 min) + +``` ++========================================================+ +| SAMENVATTING: 5 KEY TAKEAWAYS | +| | +| +--------------------------------------------------+ | +| | | | +| | 1. AGENT HARNESS | | +| | Instructions + Tools + Model = Agent | | +| | Jij controleert de instructions (rules) | | +| | | | +| | 2. RULES MINIMAAL HOUDEN | | +| | 3 bestanden, YAML frontmatter, korte regels | | +| | Te veel regels = slechtere output | | +| | | | +| | 3. PLAN VOOR JE BOUWT | | +| | Shift+Tab -> Plan Mode -> review -> build | | +| | Elke feature begint met een plan | | +| | | | +| | 4. CONTEXT MANAGEMENT | | +| | Nieuwe feature = nieuwe chat | | +| | Geef relevante @ mentions mee | | +| | | | +| | 5. SYSTEMATISCH DEBUGGEN | | +| | Hypothese -> logging -> reproduce -> | | +| | analyze -> targeted fix | | +| | | | +| +--------------------------------------------------+ | ++========================================================+ +``` + +**Spreektekst:** +- Dit zijn de vijf dingen die ik wil dat jullie onthouden. +- Het gaat niet om welk model je gebruikt, maar hoe je de agent aanstuurt. +- Goede rules, goede plannen, goede context = goede output. + +--- + +### Slide 18: Huiswerk +**Timing:** 11:58 - 12:00 (2 min) + +``` ++========================================================+ +| HUISWERK | +| | +| Zie: Les09-Huiswerk.md | +| | +| +--------------------------------------------------+ | +| | De opdracht staat volledig beschreven in | | +| | Les09-Huiswerk.md. | | +| | | | +| | Kort samengevat: | | +| | - Breid LinkVault uit met eigen features | | +| | - Gebruik Plan Mode + Agent Mode + Debug Mode | | +| | - Maak nette semantic commits | | +| | - Push naar GitHub | | +| | | | +| | Deadline en inleverinstructies staan in het | | +| | huiswerkbestand. | | +| +--------------------------------------------------+ | +| | +| VRAGEN? Stel ze nu of via Teams. | +| | +| Volgende les: we gaan verder met AI-assisted | +| development workflows. | +| | ++========================================================+ +``` + +**Spreektekst:** +- Het huiswerk staat in `Les09-Huiswerk.md`. Lees dat bestand goed door. +- Jullie gaan LinkVault uitbreiden met eigen features. +- Gebruik alles wat je vandaag geleerd hebt: Plan Mode, Agent Mode, Debug Mode. +- Vragen? Nu stellen of via Teams. + +--- + +## Troubleshooting + +### Veelvoorkomende problemen tijdens de les + +| Probleem | Oorzaak | Oplossing | +|----------|---------|-----------| +| `npx create-next-app` faalt | Node.js niet geinstalleerd of verouderd | `node -v` checken, minimaal v18. Installeer via nodejs.org | +| Cursor herkent .mdc bestanden niet | Verkeerde directory structuur | Check: `.cursor/rules/project.mdc` (niet `.cursor/project.mdc`) | +| Plan Mode doet niets | Verkeerde modus | Check linksboven in chat: moet "Plan" zeggen, niet "Agent" | +| Agent Mode maakt geen bestanden | Permissions of path probleem | Check dat je in de juiste directory bent (`pwd` in terminal) | +| Filter bug is al gefixt door Cursor | Cursor heeft het vanzelf opgelost | Tim moet de bug opnieuw introduceren NA de build stap | +| `npm run dev` geeft errors | Ontbrekende dependencies | `npm install` opnieuw draaien | +| Git push faalt | Geen remote of geen rechten | `git remote -v` checken, GitHub repo aanmaken | +| Semantic commits zijn verwarrend | Studenten weten niet wat waar hoort | Laat de voorbeelden van slide 15 zien, doe het samen | +| Context window vol | Te lang in dezelfde chat gebleven | Nieuwe chat starten, relevante bestanden opnieuw @-mentionen | +| Cursor genereert andere code dan verwacht | Model-variatie is normaal | Dit is OK -- focus op het PROCES, niet op identieke output | + +### Tim's Bug -- exacte stappen + +1. Wacht tot ALLE features gebouwd zijn (na slide 13) +2. Open het tag filter component (waarschijnlijk `src/components/TagFilter.tsx` of vergelijkbaar) +3. Zoek de filter-logica waar tags vergeleken worden +4. Verander `tag` naar `tag.toUpperCase()` in de vergelijking (bijv. in een `.filter()` of `.includes()` call) +5. Sla op, NIET committen +6. Laat studenten de bug vinden met Debug Mode + +--- + +## Timing-samenvatting (verificatie) + +| Blok | Start | Eind | Duur | Inhoud | +|------|-------|------|------|--------| +| 1 | 09:00 | 09:10 | 10 min | Welkom + terugblik (slides 1-2) | +| 2 | 09:10 | 09:35 | 25 min | Theorie (slides 3-9) | +| 3 | 09:35 | 09:55 | 20 min | Setup project + rules (slides 10-11) | +| 4 | 09:55 | 10:15 | 20 min | Plan Mode demo (slide 12) | +| -- | 10:15 | 10:30 | 15 min | PAUZE | +| 5 | 10:30 | 11:05 | 35 min | Agent Mode features (slide 13) | +| 6 | 11:05 | 11:25 | 20 min | Debug Mode (slide 14) | +| 7 | 11:25 | 11:45 | 20 min | Code Review + commits (slides 15-16) | +| 8 | 11:45 | 11:55 | 10 min | (Optioneel) PR review (slide 16) | +| 9 | 11:55 | 12:00 | 5 min | Afsluiting + huiswerk (slides 17-18) | +| **Totaal** | **09:00** | **12:00** | **180 min** | | + +--- + +## Checklist voor Tim (voor de les) + +- [ ] Next.js 16 beschikbaar (`npx create-next-app@latest` geeft v16) +- [ ] Cursor werkt op docentlaptop +- [ ] Drie `.mdc` bestanden voorbereid (kopieer van slide 11) +- [ ] Git/GitHub werkt +- [ ] Weet waar de bug geintroduceerd moet worden (filter component) +- [ ] `Les09-Huiswerk.md` is klaar en beschikbaar voor studenten +- [ ] Backup plan als Cursor offline is: theorie doornemen + pair programming diff --git a/Les09-Cursor-Deep-Dive/Les09-Slides.key b/Les09-Cursor-Deep-Dive/Les09-Slides.key new file mode 100755 index 0000000..6bcc240 Binary files /dev/null and b/Les09-Cursor-Deep-Dive/Les09-Slides.key differ diff --git a/Les09-Cursor-Deep-Dive/Les09-Slides.pptx b/Les09-Cursor-Deep-Dive/Les09-Slides.pptx new file mode 100644 index 0000000..d06b26d Binary files /dev/null and b/Les09-Cursor-Deep-Dive/Les09-Slides.pptx differ diff --git a/Samenvattingen/Les07-Samenvatting.md b/Samenvattingen/Les07-Samenvatting.md index ce0a859..a68f5ba 100644 --- a/Samenvattingen/Les07-Samenvatting.md +++ b/Samenvattingen/Les07-Samenvatting.md @@ -1,372 +1,105 @@ -# Les 7: Database Principles +# Les 7: Van In-Memory naar Supabase (Introductie) --- ## Hoofdstuk -**Deel 2: Technical Foundations** (Les 4-8) +**Deel 2: Technical Foundations** (Les 4-9) ## Beschrijving -Leer de basisprincipes van relationele databases voordat we Supabase gaan gebruiken. Begrijp tabellen, relaties, keys en normalisatie - essentiële kennis voor elke developer. +Eerste kennismaking met Supabase. Studenten maken hun QuickPoll uit Les 6 af, leren wat een relationele database is via de Supabase GUI (geen SQL nodig), en koppelen voor het eerst een echte database aan hun Next.js app. + +> **Reflectie na geven:** Te veel materiaal voor één les. Studenten kwamen niet door Deel 3 heen. Daarom is Les 8 toegevoegd waarin de Supabase-koppeling rustig opnieuw wordt doorlopen, plus een /create pagina. --- -## Te Behandelen +## Lesopbouw -### Wat is een Relationele Database? +### Deel 1 — Poll afmaken (30 min, klassikaal) +Onaffe stukken uit Les 6 wegwerken: +- `votePoll()` functie in `data.ts` +- POST route die echt verwerkt (geen `console.log` meer) +- **Server Component + VoteForm split** — kernmoment van de les +- GET route + visuele percentage bars in `PollItem` -**Een database is:** Een georganiseerde verzameling van data. +### Deel 2 — Supabase Introductie, No Code (45 min) +Voor de meeste studenten hun eerste database ervaring. +- Wat is Supabase? Open-source Firebase alternatief op Postgres +- Project aanmaken (via GitHub login) +- `polls` tabel aanmaken via Table Editor (id, question, created_at) +- `options` tabel aanmaken met foreign key naar polls (CASCADE) +- RLS policies uitleggen en SELECT policies aanzetten +- Testdata invoeren via de GUI +- SQL Editor: eerste `SELECT`, `WHERE` en `JOIN` query -**Relationeel betekent:** Data is opgeslagen in tabellen die aan elkaar gerelateerd zijn. +### Pauze (15 min) -**Vergelijk het met Excel:** -- Database = Excel workbook -- Tabel = Excel sheet -- Kolom = Excel kolom (field) -- Rij = Excel rij (record) +### Deel 3 — Supabase koppelen aan Next.js (60 min) +- `npm install @supabase/supabase-js` +- `.env.local` met `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY` +- `lib/supabase.ts` client +- Types updaten (`Poll`, `Option`) +- `data.ts` herschrijven met Supabase queries (`select`, `eq`, `single`) +- Homepage async maken +- `PollItem`, `VoteForm`, detailpagina aanpassen +- Testen op localhost — data overleeft restart + +### Vragen + Huiswerk (15 min) +**Huiswerk:** /create pagina bouwen (formulier → INSERT in Supabase) — voor de meeste studenten te zwaar gebleken, daarom in Les 8 herhaald. --- -### Tabellen, Kolommen en Rijen - -**Voorbeeld: Users tabel** - -| id | name | email | created_at | -|----|------|-------|------------| -| 1 | Tim | tim@email.com | 2024-01-15 | -| 2 | Anna | anna@email.com | 2024-01-16 | -| 3 | Jan | jan@email.com | 2024-01-17 | - -**Terminologie:** -- **Tabel:** users -- **Kolommen:** id, name, email, created_at -- **Rijen:** 3 records (Tim, Anna, Jan) -- **Cell:** Eén specifieke waarde (bijv. "tim@email.com") - ---- - -### Data Types - -Elke kolom heeft een type: - -| Type | Beschrijving | Voorbeeld | -|------|--------------|-----------| -| `text` / `varchar` | Tekst | "Tim", "Hello world" | -| `integer` / `int` | Hele getallen | 1, 42, -5 | -| `decimal` / `numeric` | Decimalen | 19.99, 3.14 | -| `boolean` | True/False | true, false | -| `timestamp` | Datum + tijd | 2024-01-15 14:30:00 | -| `uuid` | Unieke identifier | a1b2c3d4-e5f6-... | - -**Kies het juiste type:** -- Prijs? → `decimal` (niet `integer`, want centen) -- Is actief? → `boolean` -- Naam? → `text` -- Aantal? → `integer` - ---- - -### Primary Keys - -**Wat:** Een kolom die elke rij UNIEK identificeert. - -**Regels:** -- Moet uniek zijn per rij -- Mag nooit NULL zijn -- Verandert nooit - -**Voorbeeld:** -``` -users ------- -id (PRIMARY KEY) | name | email -1 | Tim | tim@email.com -2 | Anna | anna@email.com -``` - -**Waarom niet `email` als primary key?** -- Emails kunnen veranderen -- `id` is stabiel en snel - ---- - -### Foreign Keys - -**Wat:** Een kolom die verwijst naar de primary key van een andere tabel. - -**Voorbeeld: Posts tabel** -``` -posts ------- -id | title | user_id (FOREIGN KEY → users.id) -1 | "Mijn blog" | 1 -2 | "Hello world" | 1 -3 | "Tips" | 2 -``` - -**Wat zegt dit?** -- Post 1 en 2 zijn van user 1 (Tim) -- Post 3 is van user 2 (Anna) - ---- - -### Relatie Types - -**One-to-Many (1:N)** - Meest voorkomend! -``` -Eén user → meerdere posts -Eén category → meerdere products -``` - -**One-to-One (1:1)** - Zeldzaam -``` -Eén user → één profile -``` - -**Many-to-Many (N:N)** - Via tussentabel -``` -Posts ↔ Tags (een post heeft meerdere tags, een tag heeft meerdere posts) -``` - ---- - -### One-to-Many Voorbeeld - -``` -users posts ------- ------ -id | name id | title | user_id -1 | Tim ←────────── 1 | "Blog 1" | 1 -2 | Anna ←────┬───── 2 | "Blog 2" | 1 - └───── 3 | "Tips" | 2 -``` - -**Lees:** Tim heeft 2 posts, Anna heeft 1 post. - ---- - -### Many-to-Many met Tussentabel - -``` -posts post_tags tags ------- --------- ------ -id | title post_id | tag_id id | name -1 | "React tips" 1 | 1 1 | "react" -2 | "CSS guide" 1 | 2 2 | "frontend" - 2 | 2 3 | "css" - 2 | 3 -``` - -**Lees:** -- Post 1 heeft tags: react, frontend -- Post 2 heeft tags: frontend, css - ---- - -### Normalisatie Basics - -**Probleem: Data duplicatie** -``` -orders (SLECHT) ------- -id | customer_name | customer_email | product_name | price -1 | Tim | tim@email.com | Laptop | 999 -2 | Tim | tim@email.com | Phone | 699 -3 | Anna | anna@email.com | Laptop | 999 -``` - -**Problemen:** -- Tim's email staat 2x (als hij verandert: 2 plekken updaten) -- "Laptop" en prijs staan 2x - ---- - -### Genormaliseerde Versie - -``` -users products orders ------- -------- ------ -id | name | email id | name | price id | user_id | product_id -1 | Tim | tim@... 1 | Laptop | 999 1 | 1 | 1 -2 | Anna | anna@... 2 | Phone | 699 2 | 1 | 2 - 3 | 2 | 1 -``` - -**Voordelen:** -- Elk gegeven staat 1x -- Update op 1 plek -- Minder opslagruimte - ---- - -### NULL Values - -**NULL = "geen waarde" (niet 0, niet "")** - -``` -users ------- -id | name | phone -1 | Tim | 0612345678 -2 | Anna | NULL ← Geen telefoon bekend -``` - -**Wanneer NULL toestaan?** -- Optionele velden (phone, description) -- Niet bij verplichte velden (name, email) - ---- - -### Defaults - -**Automatische waarde als je niks opgeeft:** - -``` -todos ------- -id | title | completed | created_at - | | DEFAULT: false | DEFAULT: now() -``` - -Bij `INSERT INTO todos (title) VALUES ('Test')`: -``` -id | title | completed | created_at -1 | Test | false | 2024-01-15 10:30:00 -``` - ---- - -### Database Schema Tekenen - -**Tools:** draw.io, Excalidraw, pen en papier - -**Conventie:** -``` -┌──────────────┐ ┌──────────────┐ -│ users │ │ posts │ -├──────────────┤ ├──────────────┤ -│ id (PK) │───┐ │ id (PK) │ -│ name │ │ │ title │ -│ email │ └────→│ user_id (FK) │ -│ created_at │ │ content │ -└──────────────┘ │ created_at │ - └──────────────┘ -``` - -PK = Primary Key -FK = Foreign Key -Pijl = Relatie richting +## Kernconcepten +- Server Component vs Client Component patroon +- Database-as-a-service (Supabase = Postgres + Auth + REST + Realtime) +- Tabellen, kolommen, primary keys, foreign keys, CASCADE +- Row Level Security (RLS) basics +- Environment variables in Next.js (`NEXT_PUBLIC_` prefix) +- Supabase JavaScript client: `from`, `select`, `eq`, `single` --- ## Tools -- Pen en papier / Excalidraw / draw.io -- Supabase Table Editor (vooruitblik) +- Next.js 15 +- Supabase (Table Editor, SQL Editor) +- Cursor / VS Code +- TypeScript +- `@supabase/supabase-js` --- -## Lesopdracht (2 uur) +## Lesopdracht +Volg de docent klassikaal mee door Deel 1 → 3. Aan het eind draait je QuickPoll app met data uit Supabase. -### Database Design Oefening - -**Deel 1: Blog Database Ontwerpen (45 min)** - -Ontwerp een database voor een blog met: -- Users (kunnen posts schrijven) -- Posts (hebben een auteur) -- Comments (op posts, door users) - -Voor elke tabel: -1. Teken de tabel met kolommen -2. Bepaal data types -3. Markeer Primary Keys -4. Markeer Foreign Keys -5. Teken de relaties - -**Deel 2: Normalisatie Oefening (30 min)** - -Gegeven deze "slechte" tabel: - -``` -library -------- -book_title | author_name | author_email | borrower_name | borrowed_date -"1984" | "Orwell" | orwell@... | "Tim" | 2024-01-15 -"1984" | "Orwell" | orwell@... | "Anna" | 2024-01-10 -"Dune" | "Herbert" | herbert@... | "Tim" | 2024-01-12 -``` - -Normaliseer naar aparte tabellen: -1. Welke entiteiten zie je? -2. Maak aparte tabellen -3. Voeg relaties toe - -**Deel 3: Eindproject Schema (45 min)** - -Ontwerp het database schema voor jouw eindproject: -1. Welke entiteiten heb je nodig? -2. Teken elke tabel met kolommen -3. Bepaal relaties -4. Documenteer je keuzes - -### Deliverable -- Blog database schema (tekening) -- Genormaliseerde library database -- Eindproject database schema +## Huiswerk +- /create pagina afmaken (formulier dat een nieuwe poll insert) +- Validatie toevoegen +- Eventueel: extra SQL queries proberen --- -## Huiswerk (2 uur) - -### Verdieping en Voorbereiding - -**Deel 1: Eindproject Schema Uitwerken (1 uur)** - -Werk je database schema volledig uit: - -1. **Per tabel:** - - Naam - - Alle kolommen met data types - - Primary key - - Foreign keys - - Defaults - - Nullable fields - -2. **Documenteer:** - - Waarom deze structuur? - - Welke relaties? - - Eventuele alternatieve overwegingen - -**Deel 2: Supabase Account (30 min)** - -Bereid je voor op volgende les: -1. Maak account op [supabase.com](https://supabase.com) -2. Verken de interface -3. Bekijk de Table Editor - -**Deel 3: Reflectie (30 min)** - -Beantwoord deze vragen (kort): -1. Wat is het verschil tussen primary en foreign key? -2. Waarom normaliseren we data? -3. Wanneer gebruik je one-to-many vs many-to-many? -4. Welke tabellen heeft jouw eindproject nodig? - -### Deliverable -- Volledig uitgewerkt database schema voor eindproject -- Supabase account aangemaakt -- Reflectie vragen beantwoord +## Lesmateriaal +- `Les07-Slide-Overzicht.md` +- `Les07-Docenttekst.md` +- `Les07-Live-Coding-Guide.md` +- `Les07-Lesopdracht.pdf` +- `Les07-Slides.pptx` --- ## Leerdoelen Na deze les kan de student: -- Uitleggen wat een relationele database is -- Tabellen, kolommen en rijen beschrijven -- De juiste data types kiezen -- Primary keys en hun doel uitleggen -- Foreign keys en relaties begrijpen -- One-to-many en many-to-many relaties herkennen -- Het probleem van data duplicatie identificeren -- Een database normaliseren -- NULL values en defaults begrijpen -- Een database schema ontwerpen en tekenen +- Uitleggen wat Supabase is en wanneer je het inzet +- Een Supabase project aanmaken via de GUI +- Tabellen met relaties (foreign keys) aanmaken in de Table Editor +- RLS policies opzetten voor publieke read access +- De Supabase JavaScript client installeren en configureren +- Environment variables gebruiken voor API keys +- Data ophalen met `select`, `eq` en relaties (`options(*)`) +- Het Server Component + Client Component patroon toepassen + +--- + +## Lessons Learned (voor v2) +- 3 hoofddelen in 1 les is te ambitieus voor het tempo van deze klas +- /create pagina als huiswerk werkt niet — studenten hebben begeleiding nodig bij hun eerste INSERT +- Splits Supabase introductie en concrete code-koppeling over twee lessen → **Les 8 voegt dit toe** diff --git a/Samenvattingen/Les08-Samenvatting.md b/Samenvattingen/Les08-Samenvatting.md index 3d07eba..bb193ae 100644 --- a/Samenvattingen/Les08-Samenvatting.md +++ b/Samenvattingen/Les08-Samenvatting.md @@ -1,305 +1,116 @@ -# Les 8: Supabase: Auth & CRUD +# Les 8: Van In-Memory naar Supabase (Self-Paced + /create) --- ## Hoofdstuk -**Deel 2: Technical Foundations** (Les 4-8) +**Deel 2: Technical Foundations** (Les 4-9) ## Beschrijving -Supabase Authentication en CRUD operaties. Implementeer email/password auth, JWT tokens, Row Level Security (RLS) policies, realtime subscriptions en volledige CRUD functionaliteit in je full-stack app. +Vervolg op Les 7. Studenten kregen vorige les niet alles af, dus loopt de docent de Supabase-koppeling rustig opnieuw door — nu in een **self-paced PDF** met copy-paste blokken en TODO-blokken. Daarna bouwen studenten zelfstandig de **/create pagina** (hun eerste INSERT). + +**Aanpak:** Deel 1-3 doet de docent klassikaal door de PDF heen. Deel 4 (de /create pagina) doen studenten zelfstandig met de docent als coach. --- -## Te Behandelen +## Lesopbouw (3 uur) -### Wat is Supabase? - -**Supabase = Database + Auth in één** -- PostgreSQL database (gratis tier: 500MB) -- Ingebouwde authenticatie -- Real-time subscriptions -- File storage -- Auto-generated API - -**Waarom Supabase voor beginners:** -- Geen eigen server nodig -- Visuele Table Editor (geen SQL kennis nodig) -- Simpele JavaScript SDK -- Gratis tier is ruim voldoende +| Tijd | Onderwerp | Vorm | +|------|-----------|------| +| 09:00–09:15 | Welkom + Intro + PDF uitdelen | Klassikaal | +| 09:15–09:45 | **PDF Deel 1** — Setup (npm, .env, supabase.ts, types, vote_option SQL) | Klassikaal | +| 09:45–10:00 | **PDF Deel 2** — Queries (`getPolls`, `getPollById`, `votePoll`) | Klassikaal | +| 10:00–10:15 | **PDF Deel 3** — Componenten (page, PollItem, VoteForm, [id]) | Klassikaal | +| 10:15–10:30 | Pauze | — | +| 10:30–10:45 | Uitleg INSERT theorie + RLS policy + start Deel 4 | Klassikaal | +| 10:45–11:30 | **PDF Deel 4** — /create pagina bouwen | **Zelfstandig** | +| 11:30–12:00 | Vragen + Huiswerk + Vooruitblik Auth | Klassikaal | --- -### Supabase Project Aanmaken +## Lesopdracht (PDF) +Studenten krijgen één PDF met vier delen. Grijze blokken zijn copy-paste, gele TODO-blokken vullen ze zelf in. -**Stap 1:** Ga naar [supabase.com](https://supabase.com) en maak account +### Deel 1 — Setup (klassikaal) +1. `npm install @supabase/supabase-js` +2. `.env.local` met SUPABASE URL + ANON KEY +3. `lib/supabase.ts` client +4. `types/index.ts` updaten (`Poll`, `Option`) +5. **vote_option SQL functie** aanmaken in Supabase SQL Editor (voorkomt PGRST202 error) -**Stap 2:** Klik "New Project" -- Naam: `todo-app` -- Database Password: (bewaar deze!) -- Region: `West EU (Frankfurt)` (dichtst bij NL) +### Deel 2 — Queries (klassikaal, TODO's invullen) +- `getPolls()` — `select("*, options(*)")` +- `getPollById(id)` — `eq("id", id).single()` +- `votePoll(optionId)` — `rpc("vote_option", { option_id })` -**Stap 3:** Wacht ~2 minuten tot project klaar is +### Deel 3 — Componenten (klassikaal, copy-paste) +- `app/page.tsx` (async Server Component) +- `components/PollItem.tsx` (Client, percentage bars) +- `components/VoteForm.tsx` (Client) +- `app/poll/[id]/page.tsx` (Server Component, **Next.js 15 `params` is een Promise**) -**Stap 4:** Ga naar Settings → API en kopieer: -- `Project URL` -- `anon public` key +### Deel 4 — /create pagina (zelfstandig) +1. RLS INSERT policy voor `polls` en `options` +2. INSERT theorie (poll inserten → id terugkrijgen → options met `poll_id`) +3. `app/create/page.tsx` — volledig formulier in PDF, alleen `handleSubmit` TODO invullen --- -### Je Database Schema Implementeren - -In Les 7 heb je een database schema ontworpen. Nu gaan we dat implementeren! - -**In Supabase Dashboard → Table Editor:** - -1. Klik "New Table" -2. Gebruik je schema uit Les 7 -3. Voeg kolommen toe met de juiste types -4. Definieer Primary Keys en Foreign Keys - -**Voorbeeld: todos tabel** - -| Name | Type | Default | Primary | -|------|------|---------|---------| -| id | int8 | - | ✓ (auto) | -| title | text | - | | -| completed | bool | false | | -| created_at | timestamptz | now() | | - ---- - -### Environment Variables - -**Wat zijn environment variables?** -- Configuratie die NIET in je code hoort -- API keys, database URLs, secrets -- Verschillend per omgeving (lokaal vs productie) - -**Maak `.env.local` in je project root:** -```bash -# .env.local - NOOIT committen naar Git! -NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co -NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx -``` - -**Maak ook `.env.example` (WEL committen):** -```bash -# .env.example - template voor anderen -NEXT_PUBLIC_SUPABASE_URL=your-supabase-url -NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key -``` - ---- - -### Supabase SDK Installeren - -```bash -npm install @supabase/supabase-js -``` - -**Maak `src/lib/supabase.ts`:** -```typescript -import { createClient } from '@supabase/supabase-js' - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! -const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! - -export const supabase = createClient(supabaseUrl, supabaseAnonKey) -``` - ---- - -### CRUD Operaties - -**C - Create (toevoegen):** -```typescript -const { data, error } = await supabase - .from('todos') - .insert({ title: 'Nieuwe taak' }) -``` - -**R - Read (ophalen):** -```typescript -const { data, error } = await supabase - .from('todos') - .select('*') - .order('created_at', { ascending: false }) -``` - -**U - Update (wijzigen):** -```typescript -const { data, error } = await supabase - .from('todos') - .update({ completed: true }) - .eq('id', todoId) -``` - -**D - Delete (verwijderen):** -```typescript -const { error } = await supabase - .from('todos') - .delete() - .eq('id', todoId) -``` - ---- - -### Authenticatie met Auth UI - -**Installeer auth packages:** -```bash -npm install @supabase/auth-ui-react @supabase/auth-ui-shared -``` - -**Login component:** -```tsx -import { Auth } from '@supabase/auth-ui-react' -import { ThemeSupa } from '@supabase/auth-ui-shared' -import { supabase } from '@/lib/supabase' - -export function LoginForm() { - return ( - - ) -} -``` - -**Huidige user checken:** -```typescript -const { data: { user } } = await supabase.auth.getUser() - -if (user) { - // User is ingelogd - console.log('Logged in as:', user.email) -} else { - // Redirect naar login -} -``` - ---- - -### Deployment naar Vercel - -**Stap 1: Push naar GitHub** -```bash -git add . -git commit -m "Add Supabase integration" -git push -``` - -**Stap 2: Deploy op Vercel** -1. Ga naar [vercel.com](https://vercel.com) -2. "Add New Project" -3. Import je GitHub repo -4. **BELANGRIJK:** Voeg Environment Variables toe! - - `NEXT_PUBLIC_SUPABASE_URL` - - `NEXT_PUBLIC_SUPABASE_ANON_KEY` -5. Klik "Deploy" - -**Stap 3: Supabase Redirect URLs** -1. Ga naar Supabase → Authentication → URL Configuration -2. Voeg toe bij "Redirect URLs": - - `https://jouw-app.vercel.app/**` +## Belangrijke leermomenten +- **Self-paced PDF werkt beter dan live coding** voor deze klas — studenten kunnen op eigen tempo +- **Next.js 15 breaking change:** `params` is nu een `Promise<{ id: string }>`. Je moet `const { id } = await params` +- **Supabase RPC functies:** `vote_option` aanmaken in SQL Editor — anders PGRST202 error +- **RLS policies:** Zonder INSERT policy faalt elke `.insert()` met "row-level security violation" +- **Server vs Client Components:** Server haalt data (`async` + `await`), Client doet interactie (`'use client'` + `useState`) --- ## Tools -- Supabase -- Next.js -- OpenCode/WebStorm -- Vercel -- Git +- Next.js 15 +- Supabase (SQL Editor, Table Editor, RLS) +- `@supabase/supabase-js` +- TypeScript +- Cursor / VS Code --- -## Lesopdracht (2 uur) +## Huiswerk +**Verplicht:** +- /create pagina afmaken (als niet klaar) +- Validatie toevoegen (vraag niet leeg, minimaal 2 opties) -### Bouw een Todo App met Supabase - -**Groepsdiscussie (15 min):** -Bespreek klassikaal de database schemas uit Les 7 - wie heeft welke structuur gekozen en waarom? - -**Deel 1: Supabase Setup (30 min)** - -1. Maak Supabase account en project -2. Maak je tabellen via Table Editor (gebaseerd op Les 7 schema) -3. Kopieer credentials -4. Installeer `@supabase/supabase-js` -5. Maak `src/lib/supabase.ts` -6. Configureer `.env.local` - -Test: `npm run dev` werkt zonder errors - -**Deel 2: CRUD Interface (1 uur)** - -Bouw UI voor todos: -1. Lijst van todos tonen -2. Form om nieuwe todo toe te voegen -3. Checkbox om todo af te vinken -4. Delete button per todo - -Gebruik AI hulp voor de components! - -**Deel 3: Authenticatie (30 min)** - -1. Installeer auth packages -2. Maak login pagina met Auth UI -3. Toon alleen app voor ingelogde users -4. Test: login met magic link - -### Deliverable -- Werkende Todo app lokaal -- GitHub repository met code -- Screenshot van werkende app +**Extra:** +- Delete functionaliteit +- SQL queries direct testen in Supabase +- Realtime subscriptions uitproberen +- Styling polish --- -## Huiswerk (2 uur) - -### Deploy naar Productie + Uitbreiden - -**Deel 1: Deployment (30 min)** - -1. Push naar GitHub -2. Deploy naar Vercel -3. Configureer env vars in Vercel -4. Voeg Vercel URL toe aan Supabase Redirect URLs -5. Test: app werkt op productie URL! - -**Deel 2: Features Uitbreiden (1 uur)** - -Voeg toe: -1. Filter buttons: Alle / Actief / Voltooid -2. Sorteer op datum (nieuwste eerst) -3. Loading state tijdens data ophalen -4. Error state bij problemen -5. Empty state: "Geen todos gevonden" - -**Deel 3: Polish (30 min)** - -1. Styling verbeteren met Tailwind -2. Responsive design (mobile friendly) -3. Kleine animaties (fade in/out) - -### Deliverable -- Deployed app op Vercel (werkende URL!) -- Alle features werken in productie -- Screenshot van productie app +## Lesmateriaal +- `Les08-Slide-Overzicht.md` +- `Les08-Docenttekst.md` +- `Les08-Lesopdracht.pdf` (de self-paced handleiding) +- `Les08-Slides.pptx` --- ## Leerdoelen Na deze les kan de student: -- Een Supabase project aanmaken en configureren -- Database schema implementeren via Table Editor -- Environment variables correct beheren -- De Supabase client installeren en configureren -- CRUD operaties uitvoeren met de Supabase SDK -- Authenticatie implementeren met Auth UI -- Deployen naar Vercel met environment variables -- Database principles uit Les 7 toepassen in de praktijk +- De Supabase JavaScript client installeren en configureren +- Environment variables gebruiken voor API keys +- Data ophalen via Supabase queries (`select` met relaties, `eq`, `single`) +- Een PostgreSQL function aanroepen via `.rpc()` +- Het verschil uitleggen tussen Server en Client Components in Next.js 15 +- Een formulier bouwen dat data INSERT in Supabase +- RLS policies schrijven voor publieke read en insert +- Veelvoorkomende Supabase errors herkennen en oplossen (PGRST202, RLS violation) + +--- + +## Voorbereiding docent +- [ ] QuickPoll project werkt lokaal op localhost:3000 +- [ ] Supabase project met `polls` + `options` tabellen +- [ ] `vote_option` RPC functie aangemaakt +- [ ] SELECT RLS policies staan aan +- [ ] Lesopdracht PDF gedeeld met studenten (digitaal) +- [ ] Whiteboard voor de vier query-patronen diff --git a/Samenvattingen/Les09-Samenvatting.md b/Samenvattingen/Les09-Samenvatting.md index d613fe1..62a6d73 100644 --- a/Samenvattingen/Les09-Samenvatting.md +++ b/Samenvattingen/Les09-Samenvatting.md @@ -1,126 +1,96 @@ -# Les 9: Full-Stack Mini Project +# Les 9: Cursor Deep Dive (Student Plan) --- ## Hoofdstuk -**Deel 3: Integration & AI Tooling** (Les 9-12) +**Deel 2: Technical Foundations** (Les 4-9) ## Beschrijving -Combineer alles wat je geleerd hebt (TypeScript, Next.js, Supabase) in een kleine werkende applicatie. Dit is je eerste "echte" full-stack project en voorbereiding op het werken met AI tools. +Studenten hebben Cursor met het Student Plan. Tijd voor een deep dive in de 5 professionele workflows: **Rules & Skills, Plan Mode, Agent Mode, Debug Mode, en Code Review & Testing**. We bouwen een nieuwe app from scratch: **LinkVault** (bookmark manager, in-memory, Next.js 16 + TypeScript + Tailwind). --- -## Te Behandelen +## Lesopbouw (3 uur) -### Groepsdiscussie (15 min) -Bespreek klassikaal de Supabase ervaringen uit Les 8 - welke uitdagingen kwamen jullie tegen bij authenticatie en RLS? - -### Doel van deze les - -Je hebt nu alle bouwstenen: -- TypeScript (Les 4) -- Next.js met App Router (Les 5-6) -- Supabase database & auth (Les 7-8) - -Vandaag combineren we dit in een **werkende mini-app**. Geen nieuwe concepten - alleen integratie en toepassing. +| Tijd | Onderwerp | Vorm | +|------|-----------|------| +| 09:00–09:10 | Welkom + terugblik | Klassikaal | +| 09:10–09:35 | Theorie: Agent Harness, Rules, Plan/Debug/Review Mode | Klassikaal | +| 09:35–09:55 | Setup: nieuw project + 3 `.cursor/rules` bestanden | Samen | +| 09:55–10:15 | Plan Mode: plan LinkVault → review → Build | Klassikaal | +| 10:15–10:30 | Pauze | — | +| 10:30–11:05 | Agent Mode: features bouwen | Klassikaal | +| 11:05–11:25 | Debug Mode: deterministische bug vinden en fixen | Klassikaal | +| 11:25–11:45 | Code Review & Testing + semantic commits + git push | Klassikaal | +| 11:45–11:55 | (Optioneel) PR review met Cursor | Klassikaal | +| 11:55–12:00 | Afsluiting + huiswerk | Klassikaal | --- -### Mini Project: Personal Bookmarks +## De 5 Kernvaardigheden -Een simpele bookmark manager waar je links kunt opslaan. +### 1. Rules & Skills +- `.cursor/rules/` directory met `.mdc` bestanden (YAML frontmatter) +- 3 bestanden: `project.mdc` (alwaysApply), `components.mdc` (globs: tsx), `styles.mdc` (globs: css/tsx) +- Houd rules kort, specifiek, en wijs naar voorbeelden -**Features:** -- Login met Supabase Auth -- Bookmarks toevoegen (URL + titel) -- Bookmarks bekijken en verwijderen +### 2. Plan Mode +- `Shift+Tab` → agent researcht, stelt vragen, maakt interactief plan +- Plan bewerken in markdown → "Build" klikken +- Start elke feature met een plan -**Tech stack:** -- Next.js 14 met App Router -- TypeScript -- Tailwind CSS -- Supabase (auth + database) -- React Query +### 3. Agent Mode +- Agent = uitvoeren (files, terminal, multi-file). Ask = alleen vragen. +- Goede context geven: `@file`, `@folder`, `@codebase`, `@docs` +- Itereren met screenshots en feedback ---- +### 4. Debug Mode +- Voor complexe bugs: hypotheses → logging → reproduceren → analyseren → fix +- Tim introduceert bug handmatig (deterministic) → studenten debuggen -### Stap-voor-stap - -#### Database Schema - -**Tabel: bookmarks** -| Kolom | Type | -|-------|------| -| id | uuid (PK) | -| user_id | uuid (FK naar auth.users) | -| url | text | -| title | text | -| created_at | timestamptz | - -**RLS:** Users kunnen alleen eigen bookmarks zien, toevoegen en verwijderen. - -#### Wat je bouwt - -1. **Login pagina** - Supabase Auth -2. **Dashboard** - Lijst van bookmarks -3. **Add form** - URL + titel invoeren -4. **Delete** - Bookmark verwijderen +### 5. Code Review & Testing +- "Find Issues" voor self-review +- Tests schrijven met Agent Mode +- Semantic commits: achteraf changes opdelen in logische groepen +- (Optioneel) PR review met Cursor --- ## Tools -- VS Code -- Supabase Dashboard -- Browser DevTools +- Cursor (Student Plan) +- Next.js 16 +- TypeScript +- Tailwind CSS --- -## Lesopdracht (2.5 uur) - -### Bouw de Bookmark Manager - -**Checkpoints:** - -| Tijd | Wat klaar moet zijn | -|------|---------------------| -| 30 min | Project setup + database schema | -| 60 min | Auth werkt (login/logout) | -| 90 min | Bookmarks toevoegen en bekijken | -| 120 min | Delete werkt | -| 150 min | Styling en testen | - -**Minimale eisen:** -- [ ] Login/logout werkt -- [ ] Bookmarks toevoegen werkt -- [ ] Bookmarks worden getoond -- [ ] Delete werkt - -### Deliverable -- Werkende lokale applicatie -- Screenshot van je app met data - ---- - -## Huiswerk (1 uur) - -### Reflectie - -Schrijf korte reflectie (200 woorden): -- Wat ging goed bij het integreren? -- Waar liep je vast? -- Wat zou je volgende keer anders doen? - -Maak een lijst van 3 verbeterpunten voor je code. - -### Deliverable -- Reflectie (200 woorden) -- 3 verbeterpunten +## Lesmateriaal +- `Les09-Slide-Overzicht.md` +- `Les09-Docenttekst.md` +- `Les09-Huiswerk.md` --- ## Leerdoelen Na deze les kan de student: -- Een complete full-stack applicatie bouwen met Next.js, TypeScript en Supabase -- CRUD operaties implementeren met React Query -- Authenticatie integreren in een applicatie -- Zelfstandig integratieproblemen oplossen +- Uitleggen hoe een coding agent werkt (harness: instructions + tools + model) +- `.cursor/rules` opzetten met meerdere bestanden (alwaysApply, globs) +- Plan Mode gebruiken om een feature te plannen +- Agent Mode inzetten voor multi-file feature development +- Debug Mode gebruiken voor systematisch debuggen +- Code review doen met "Find Issues" en tests schrijven +- Semantic commits maken en een PR aanmaken +- Een app from scratch bouwen met alle 5 technieken + +--- + +## Voorbereiding docent +- [ ] `npx create-next-app@latest` getest +- [ ] 3 `.cursor/rules` bestanden voorbereid +- [ ] Plan Mode demo doorgelopen +- [ ] Bug voor Debug Mode voorbereid (tag.toUpperCase() in filter) +- [ ] GitHub repo klaar voor push demo + +--- + +*Laatste update: april 2026* diff --git a/readme.md b/readme.md index f75686d..9d7bc8a 100644 --- a/readme.md +++ b/readme.md @@ -42,9 +42,9 @@ Dit format betrekent meer interactie, sneller feedback en meer mogelijkheden voo | 04 | [TypeScript Fundamentals](Samenvattingen/Les04-Samenvatting.md) | 2 | ✅ Gegeven | | 05 | [Next.js — Het React Framework (Part 1)](Samenvattingen/Les05-Samenvatting.md) | 2 | ✅ Gegeven (v1) | | 06 | [Next.js — QuickPoll Vervolg (Part 2)](Samenvattingen/Les06-Samenvatting.md) | 2 | 📋 Gepland | -| 07 | [Database Principles & Supabase Setup](Samenvattingen/Les07-Samenvatting.md) | 2 | 📋 Samenvatting | -| 08 | [Supabase: Auth & CRUD](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Samenvatting | -| 09 | [Full-Stack Mini Project](Samenvattingen/Les09-Samenvatting.md) | 3 | 📋 Samenvatting | +| 07 | [Van In-Memory naar Supabase (Introductie)](Samenvattingen/Les07-Samenvatting.md) | 2 | ✅ Gegeven | +| 08 | [Van In-Memory naar Supabase (Self-Paced + /create)](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Gepland | +| 09 | [Cursor Deep Dive (Student Plan)](Samenvattingen/Les09-Samenvatting.md) | 2 | 📋 Gepland | | 10 | [Styling: Tailwind CSS & shadcn/ui](Samenvattingen/Les10-Samenvatting.md) | 3 | 📋 Samenvatting | | 11 | [Van Idee naar Prototype](Samenvattingen/Les11-Samenvatting.md) | 3 | 📋 Samenvatting | | 12 | [Project Setup & AI Config (.cursorrules, claude.md)](Samenvattingen/Les12-Samenvatting.md) | 3 | 📋 Samenvatting | @@ -62,7 +62,7 @@ Dit format betrekent meer interactie, sneller feedback en meer mogelijkheden voo | Deel | Lessen | Tools | Kosten | |------|--------|-------|--------| | Deel 1: AI Foundations | 1-3 | ChatGPT, v0.dev, OpenCode, **Cursor** | Gratis (Cursor Student Plan) | -| Deel 2: Technical Foundations | 4-8 | TypeScript, Next.js, Supabase | Gratis | +| Deel 2: Technical Foundations | 4-9 | TypeScript, Next.js, Supabase, Supabase Auth | Gratis | | Deel 3: Full-Stack Development | 9-12 | Next.js, Supabase, Tailwind, **shadcn/ui**, Cursor | Gratis | | Deel 4: Advanced AI & Deployment | 13-18 | Cursor, Vercel AI SDK, Vercel | Gratis (Cursor Student Plan) | @@ -225,9 +225,11 @@ Kennismaking met AI, LLMs en de basis van AI-assisted development met Cursor. # Deel 2: Technical Foundations -**5 lessen · 10 EC** +**6 lessen · 10 EC** -Stevige technische basis: TypeScript, Next.js, databases en Supabase. +Stevige technische basis: TypeScript, Next.js, Supabase database en Cursor deep dive. + +> **Curriculum-shift:** Deel 2 telt nu 6 lessen i.p.v. 5. Tijdens het geven van Les 7 bleek dat studenten meer tijd nodig hadden voor het Supabase-traject. Daarom is Les 8 (Self-paced redo + /create) toegevoegd. Les 9 is een Cursor Deep Dive nu studenten de Student Plan hebben. **Supabase Auth schuift naar Les 10. Les 10-18 schuiven hierdoor één plek op en moeten nog opnieuw gepland worden.** --- @@ -304,83 +306,127 @@ Stevige technische basis: TypeScript, Next.js, databases en Supabase. --- -### Les 7: Database Principles & Supabase Setup +### Les 7: Van In-Memory naar Supabase (Introductie) -**Tools:** Diagramming tool (draw.io/Excalidraw), Supabase, Cursor +**Tools:** Next.js 15, Supabase (Table Editor, SQL Editor), `@supabase/supabase-js`, Cursor, TypeScript -**Docent vertelt:** -- Wat is een relationele database? Tabellen, rijen, kolommen -- Primary Keys, Foreign Keys en relaties -- Relatie types: one-to-one, one-to-many, many-to-many -- Normalisatie basics -- Wat is Supabase? (database + auth in één) -- Supabase project setup -- Table Editor: tabellen maken zonder SQL -- Environment variables configuratie +**Docent vertelt (~75 min, klassikaal):** +- Recap Les 6: QuickPoll met in-memory data — wat mist nog? +- Server Component + Client Component patroon (kernmoment) +- Wat is Supabase? Open-source Firebase alternatief op Postgres +- Tabellen, primary keys, foreign keys, CASCADE +- RLS policies basics +- SQL: SELECT, WHERE, JOIN +- Environment variables in Next.js (`NEXT_PUBLIC_` prefix) +- Supabase JavaScript client (`from`, `select`, `eq`, `single`) -**Studenten doen:** -- Database schema tekenen voor eigen project -- Supabase account en project aanmaken -- Tabellen maken via UI (op basis van eigen schema) -- `.env.local` configureren -- Supabase client instellen +**Samen bouwen (~120 min, klassikaal):** +- **Deel 1:** Poll afmaken — `votePoll()`, POST route, Server/Client split, percentage bars +- **Deel 2:** Supabase no-code — project, polls + options tabellen met foreign key, RLS, testdata, SQL Editor +- **Deel 3:** Supabase koppelen — `npm install`, `.env.local`, `lib/supabase.ts`, types, `data.ts` herschrijven, components aanpassen, testen -**Lesopdracht:** -1. Teken database schema voor jouw eindproject -2. Maak Supabase project -3. Implementeer je tabellen in Table Editor -4. Configureer `.env.local` -5. Test connectie met Supabase client +**Lesopdracht:** Volg klassikaal mee. Aan het eind draait je QuickPoll app met data uit Supabase. -**Huiswerk:** Refine je database schema, voeg meer relaties toe, dokumenteer decisions, bereid Les 8 vor. +**Huiswerk:** /create pagina bouwen (formulier → INSERT). *Bleek voor de meeste studenten te zwaar — daarom wordt dit in Les 8 herhaald.* + +**Lesmateriaal:** +- [Slide-Overzicht](Les07-Supabase/Les07-Slide-Overzicht.md) +- [Docenttekst](Les07-Supabase/Les07-Docenttekst.md) +- [Live Coding Guide](Les07-Supabase/Les07-Live-Coding-Guide.md) +- [Lesopdracht (PDF)](Les07-Supabase/Les07-Lesopdracht.pdf) +- [Slides (PPTX)](Les07-Supabase/Les07-Slides.pptx) [→ Ga naar Les 7 Samenvatting](Samenvattingen/Les07-Samenvatting.md) --- -### Les 8: Supabase: Auth & CRUD +### Les 8: Van In-Memory naar Supabase (Self-Paced + /create) -**Tools:** Supabase, Next.js, Cursor, React Query +**Tools:** Next.js 15, Supabase (SQL Editor, RLS), `@supabase/supabase-js`, Cursor, TypeScript -**Docent vertelt:** -- Supabase Authentication: email/password, OAuth basics -- User sessions en JWT tokens -- Row Level Security (RLS) policies -- CRUD operaties in Supabase -- Realtime subscriptions introduceer -- Error handling en validation -- Best practices: secrets, security +**Achtergrond:** Studenten kregen vorige les niet door Deel 3 heen. Deze les loopt de docent de Supabase-koppeling rustig opnieuw door — nu via een **self-paced PDF** met copy-paste blokken en TODO-blokken. Daarna bouwen studenten zelfstandig de **/create pagina** (hun eerste INSERT). -**Studenten doen:** -- **Groepsdiscussie:** Database schemas van vorige les - aanpassingen nodig? -- Auth setup met email/password -- User sessions implementeren -- RLS policies schrijven -- CRUD app bouwen (Todo, Notes, Bookmarks) -- Realtime features testen +**Aanpak:** Deel 1-3 klassikaal door de PDF. Deel 4 (/create pagina) zelfstandig met docent als coach. -**Lesopdracht:** -1. Setup Supabase Auth (email/password) -2. Maak login/signup forms -3. Implementeer user sessions -4. Schrijf RLS policies voor je tabellen -5. Bouw complete CRUD app met auth +**Tijdsindeling:** +- 09:00–09:15 Welkom + PDF uitdelen +- 09:15–09:45 **PDF Deel 1** — Setup (npm, .env, supabase.ts, types, `vote_option` SQL functie) +- 09:45–10:00 **PDF Deel 2** — Queries (`getPolls`, `getPollById`, `votePoll` met TODO's) +- 10:00–10:15 **PDF Deel 3** — Componenten (page, PollItem, VoteForm, [id]) +- 10:15–10:30 Pauze +- 10:30–10:45 Uitleg INSERT theorie + RLS policy +- 10:45–11:30 **ZELFSTANDIG: PDF Deel 4** — /create pagina +- 11:30–12:00 Vragen + Huiswerk + Vooruitblik Auth -**Huiswerk:** Add OAuth provider (Google/GitHub), implementeer logout en password reset, deploy naar Vercel met env secrets. +**Belangrijke leermomenten:** +- Self-paced PDF werkt beter dan live coding voor deze klas +- Next.js 15: `params` is nu een `Promise<{ id: string }>` → `const { id } = await params` +- Supabase RPC: `vote_option` PostgreSQL function aanmaken (anders PGRST202 error) +- RLS INSERT policy nodig vóór `.insert()` (anders "row-level security violation") + +**Lesopdracht:** PDF met 4 delen — grijze blokken zijn copy-paste, gele TODO-blokken vullen studenten zelf in. + +**Huiswerk:** /create pagina afmaken, validatie toevoegen (vraag niet leeg, min 2 opties). Extra: delete functie, SQL queries, realtime, styling. + +**Lesmateriaal:** +- [Slide-Overzicht](Les08-Van-InMemory-naar-Supabase/Les08-Slide-Overzicht.md) +- [Docenttekst](Les08-Van-InMemory-naar-Supabase/Les08-Docenttekst.md) +- [Lesopdracht (PDF)](Les08-Van-InMemory-naar-Supabase/Les08-Lesopdracht.pdf) — self-paced handleiding +- [Slides (PPTX)](Les08-Van-InMemory-naar-Supabase/Les08-Slides.pptx) [→ Ga naar Les 8 Samenvatting](Samenvattingen/Les08-Samenvatting.md) --- -# Deel 3: Full-Stack Development +### Les 9: Cursor Deep Dive (Student Plan) -**4 lessen · 7 EC** +**Tools:** Cursor (Student Plan), Next.js 16, TypeScript, Tailwind CSS -Integratie van alle geleerde technieken, styling en voorbereiding op eindproject. +**Context:** Studenten hebben Cursor met het Student Plan (500 fast requests/maand). Tijd voor een deep dive in 5 professionele workflows die elke developer nodig heeft bij het werken met coding agents. + +**We bouwen een nieuwe app from scratch: LinkVault** — een bookmark manager. In-memory data, geen Supabase. + +**Docent vertelt (~25 min):** +- Hoe werkt een coding agent? Het Harness concept (instructions + tools + model) +- Rules & Skills: `.cursor/rules/` met 3 `.mdc` bestanden (project, components, styles) +- Context management: nieuw feature = nieuwe chat, @file/@codebase/@docs combineren +- Plan Mode: Shift+Tab → plan → review → edit → Build +- Agent Mode vs Ask Mode: wanneer welke? +- Debug Mode: hypotheses → logging → reproduceren → analyseren → fix +- Code Review & Testing: "Find Issues", tests schrijven, semantic commits + +**Samen bouwen (~120 min, klassikaal):** +1. Setup: `npx create-next-app@latest` + 3 `.cursor/rules` bestanden +2. Plan Mode: plan LinkVault → review → Build +3. Agent Mode: features bouwen (edit bookmark, tag filtering) +4. Debug Mode: deterministische bug (handmatig geïntroduceerd) vinden en fixen +5. Code Review: "Find Issues" + unit tests + semantic commits + git push +6. (Optioneel) PR review met Cursor + +**Lesopdracht:** Bouw LinkVault mee met alle 5 technieken. + +**Huiswerk:** Bouw je eigen app from scratch (recepten, films, notities, of eigen idee) met dezelfde 5 technieken. Reflectie schrijven (200 woorden). Zie `Les09-Huiswerk.md`. + +**Lesmateriaal:** +- [Slide-Overzicht](Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md) +- [Docenttekst](Les09-Cursor-Deep-Dive/Les09-Docenttekst.md) +- [Huiswerk](Les09-Cursor-Deep-Dive/Les09-Huiswerk.md) + +[→ Ga naar Les 9 Samenvatting](Samenvattingen/Les09-Samenvatting.md) --- -### Les 9: Full-Stack Mini Project +# Deel 3: Full-Stack Development + +**4 lessen · 7 EC** *(nog te herplannen — Les 10-12 schuiven naar Les 11-13)* + +Integratie van alle geleerde technieken, styling en voorbereiding op eindproject. + +> **Let op:** De onderstaande lessen 9-12 zijn nog op de oude nummering. Na de Les 7/8/9 herschikking schuift dit blok één plek op (Les 10 = Mini Project, Les 11 = Styling, etc.). Bestanden zijn nog niet hernoemd. + +--- + +### Les 9 (oud → wordt Les 10): Full-Stack Mini Project **Tools:** Cursor, Supabase, Browser DevTools