Files
novi-lessons/Les09-Cursor-Deep-Dive/Les09-Docenttekst.md
2026-04-22 07:05:35 +02:00

61 KiB
Raw Permalink Blame History

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:0009:10 Welkom + korte terugblik Klassikaal
09:1009:35 Theorie: Agent Harness, Rules, Plan Mode, Debug Mode, Code Review Klassikaal
09:3509:55 Setup: nieuw project + .cursor/rules (3 bestanden!) Samen
09:5510:15 Plan Mode: plan LinkVault, review, Build Klassikaal
10:1510:30 Pauze
10:3011:05 Agent Mode: features bouwen (edit, filter) Klassikaal
11:0511:25 Debug Mode: Tim's bug vinden en fixen Klassikaal
11:2511:45 Code Review & Testing + Git push + Semantic commits Klassikaal
11:4511:55 (Optioneel) PR review met Cursor Klassikaal
11:5512: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."

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)

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

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

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

---
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

---
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<Bookmark>) => 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:

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:

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.:

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:

export const getBookmarksByTag = (tag: string): Bookmark[] => {
  return bookmarks.filter(b => b.tags.includes(tag));
};

Of een robuustere versie met case-insensitive vergelijking:

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

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

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

git log --oneline

Tim zegt: "Mooi. Een schone commit history. Nu kunnen we pushen."

Stap 4: Push naar GitHub

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:"

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:"

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:0009:10 Welkom + terugblik 10 min Kan 2 min uitlopen
09:1009:35 Theorie 25 min Houd het strak — niet langer dan 30 min
09:3509:55 Setup + 3 rules bestanden 20 min Kan 5 min uitlopen voor troubleshooting
09:5510:15 Plan Mode Demo + Build 20 min Kernblok — neem de tijd
10:1510:30 Pauze 15 min Gebruik voor achterblijvers
10:3011:05 Agent Mode oefeningen 35 min Kernblok — twee oefeningen + student tijd
11:0511:25 Debug Mode 20 min Kernblok — niet inkorten
11:2511:45 Code Review + Testing + Commits 20 min Kernblok — semantic commits is belangrijk
11:4511:55 (Optioneel) PR review 10 min ALLEEN als er tijd is — Tim beslist
11:5512: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

---
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

---
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<Bookmark>) => 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

---
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