fix: les 9
This commit is contained in:
1545
Les09-Cursor-Deep-Dive/Les09-Docenttekst.md
Normal file
1545
Les09-Cursor-Deep-Dive/Les09-Docenttekst.md
Normal file
File diff suppressed because it is too large
Load Diff
314
Les09-Cursor-Deep-Dive/Les09-Huiswerk.md
Normal file
314
Les09-Cursor-Deep-Dive/Les09-Huiswerk.md
Normal file
@@ -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.
|
||||||
943
Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md
Normal file
943
Les09-Cursor-Deep-Dive/Les09-Slide-Overzicht.md
Normal file
@@ -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
|
||||||
BIN
Les09-Cursor-Deep-Dive/Les09-Slides.key
Executable file
BIN
Les09-Cursor-Deep-Dive/Les09-Slides.key
Executable file
Binary file not shown.
BIN
Les09-Cursor-Deep-Dive/Les09-Slides.pptx
Normal file
BIN
Les09-Cursor-Deep-Dive/Les09-Slides.pptx
Normal file
Binary file not shown.
@@ -1,372 +1,105 @@
|
|||||||
# Les 7: Database Principles
|
# Les 7: Van In-Memory naar Supabase (Introductie)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Deel 2: Technical Foundations** (Les 4-8)
|
**Deel 2: Technical Foundations** (Les 4-9)
|
||||||
|
|
||||||
## Beschrijving
|
## 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:**
|
### Deel 3 — Supabase koppelen aan Next.js (60 min)
|
||||||
- Database = Excel workbook
|
- `npm install @supabase/supabase-js`
|
||||||
- Tabel = Excel sheet
|
- `.env.local` met `NEXT_PUBLIC_SUPABASE_URL` + `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||||
- Kolom = Excel kolom (field)
|
- `lib/supabase.ts` client
|
||||||
- Rij = Excel rij (record)
|
- 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
|
## Kernconcepten
|
||||||
|
- Server Component vs Client Component patroon
|
||||||
**Voorbeeld: Users tabel**
|
- Database-as-a-service (Supabase = Postgres + Auth + REST + Realtime)
|
||||||
|
- Tabellen, kolommen, primary keys, foreign keys, CASCADE
|
||||||
| id | name | email | created_at |
|
- Row Level Security (RLS) basics
|
||||||
|----|------|-------|------------|
|
- Environment variables in Next.js (`NEXT_PUBLIC_` prefix)
|
||||||
| 1 | Tim | tim@email.com | 2024-01-15 |
|
- Supabase JavaScript client: `from`, `select`, `eq`, `single`
|
||||||
| 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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Pen en papier / Excalidraw / draw.io
|
- Next.js 15
|
||||||
- Supabase Table Editor (vooruitblik)
|
- 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
|
## Huiswerk
|
||||||
|
- /create pagina afmaken (formulier dat een nieuwe poll insert)
|
||||||
**Deel 1: Blog Database Ontwerpen (45 min)**
|
- Validatie toevoegen
|
||||||
|
- Eventueel: extra SQL queries proberen
|
||||||
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 (2 uur)
|
## Lesmateriaal
|
||||||
|
- `Les07-Slide-Overzicht.md`
|
||||||
### Verdieping en Voorbereiding
|
- `Les07-Docenttekst.md`
|
||||||
|
- `Les07-Live-Coding-Guide.md`
|
||||||
**Deel 1: Eindproject Schema Uitwerken (1 uur)**
|
- `Les07-Lesopdracht.pdf`
|
||||||
|
- `Les07-Slides.pptx`
|
||||||
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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Uitleggen wat een relationele database is
|
- Uitleggen wat Supabase is en wanneer je het inzet
|
||||||
- Tabellen, kolommen en rijen beschrijven
|
- Een Supabase project aanmaken via de GUI
|
||||||
- De juiste data types kiezen
|
- Tabellen met relaties (foreign keys) aanmaken in de Table Editor
|
||||||
- Primary keys en hun doel uitleggen
|
- RLS policies opzetten voor publieke read access
|
||||||
- Foreign keys en relaties begrijpen
|
- De Supabase JavaScript client installeren en configureren
|
||||||
- One-to-many en many-to-many relaties herkennen
|
- Environment variables gebruiken voor API keys
|
||||||
- Het probleem van data duplicatie identificeren
|
- Data ophalen met `select`, `eq` en relaties (`options(*)`)
|
||||||
- Een database normaliseren
|
- Het Server Component + Client Component patroon toepassen
|
||||||
- NULL values en defaults begrijpen
|
|
||||||
- Een database schema ontwerpen en tekenen
|
---
|
||||||
|
|
||||||
|
## 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**
|
||||||
|
|||||||
@@ -1,305 +1,116 @@
|
|||||||
# Les 8: Supabase: Auth & CRUD
|
# Les 8: Van In-Memory naar Supabase (Self-Paced + /create)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Deel 2: Technical Foundations** (Les 4-8)
|
**Deel 2: Technical Foundations** (Les 4-9)
|
||||||
|
|
||||||
## Beschrijving
|
## 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?
|
| Tijd | Onderwerp | Vorm |
|
||||||
|
|------|-----------|------|
|
||||||
**Supabase = Database + Auth in één**
|
| 09:00–09:15 | Welkom + Intro + PDF uitdelen | Klassikaal |
|
||||||
- PostgreSQL database (gratis tier: 500MB)
|
| 09:15–09:45 | **PDF Deel 1** — Setup (npm, .env, supabase.ts, types, vote_option SQL) | Klassikaal |
|
||||||
- Ingebouwde authenticatie
|
| 09:45–10:00 | **PDF Deel 2** — Queries (`getPolls`, `getPollById`, `votePoll`) | Klassikaal |
|
||||||
- Real-time subscriptions
|
| 10:00–10:15 | **PDF Deel 3** — Componenten (page, PollItem, VoteForm, [id]) | Klassikaal |
|
||||||
- File storage
|
| 10:15–10:30 | Pauze | — |
|
||||||
- Auto-generated API
|
| 10:30–10:45 | Uitleg INSERT theorie + RLS policy + start Deel 4 | Klassikaal |
|
||||||
|
| 10:45–11:30 | **PDF Deel 4** — /create pagina bouwen | **Zelfstandig** |
|
||||||
**Waarom Supabase voor beginners:**
|
| 11:30–12:00 | Vragen + Huiswerk + Vooruitblik Auth | Klassikaal |
|
||||||
- Geen eigen server nodig
|
|
||||||
- Visuele Table Editor (geen SQL kennis nodig)
|
|
||||||
- Simpele JavaScript SDK
|
|
||||||
- Gratis tier is ruim voldoende
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 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"
|
### Deel 2 — Queries (klassikaal, TODO's invullen)
|
||||||
- Naam: `todo-app`
|
- `getPolls()` — `select("*, options(*)")`
|
||||||
- Database Password: (bewaar deze!)
|
- `getPollById(id)` — `eq("id", id).single()`
|
||||||
- Region: `West EU (Frankfurt)` (dichtst bij NL)
|
- `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:
|
### Deel 4 — /create pagina (zelfstandig)
|
||||||
- `Project URL`
|
1. RLS INSERT policy voor `polls` en `options`
|
||||||
- `anon public` key
|
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
|
## Belangrijke leermomenten
|
||||||
|
- **Self-paced PDF werkt beter dan live coding** voor deze klas — studenten kunnen op eigen tempo
|
||||||
In Les 7 heb je een database schema ontworpen. Nu gaan we dat implementeren!
|
- **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
|
||||||
**In Supabase Dashboard → Table Editor:**
|
- **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`)
|
||||||
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 (
|
|
||||||
<Auth
|
|
||||||
supabaseClient={supabase}
|
|
||||||
appearance={{ theme: ThemeSupa }}
|
|
||||||
providers={[]}
|
|
||||||
magicLink={true}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**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/**`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Supabase
|
- Next.js 15
|
||||||
- Next.js
|
- Supabase (SQL Editor, Table Editor, RLS)
|
||||||
- OpenCode/WebStorm
|
- `@supabase/supabase-js`
|
||||||
- Vercel
|
- TypeScript
|
||||||
- Git
|
- 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
|
**Extra:**
|
||||||
|
- Delete functionaliteit
|
||||||
**Groepsdiscussie (15 min):**
|
- SQL queries direct testen in Supabase
|
||||||
Bespreek klassikaal de database schemas uit Les 7 - wie heeft welke structuur gekozen en waarom?
|
- Realtime subscriptions uitproberen
|
||||||
|
- Styling polish
|
||||||
**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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Lesmateriaal
|
||||||
|
- `Les08-Slide-Overzicht.md`
|
||||||
### Deploy naar Productie + Uitbreiden
|
- `Les08-Docenttekst.md`
|
||||||
|
- `Les08-Lesopdracht.pdf` (de self-paced handleiding)
|
||||||
**Deel 1: Deployment (30 min)**
|
- `Les08-Slides.pptx`
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een Supabase project aanmaken en configureren
|
- De Supabase JavaScript client installeren en configureren
|
||||||
- Database schema implementeren via Table Editor
|
- Environment variables gebruiken voor API keys
|
||||||
- Environment variables correct beheren
|
- Data ophalen via Supabase queries (`select` met relaties, `eq`, `single`)
|
||||||
- De Supabase client installeren en configureren
|
- Een PostgreSQL function aanroepen via `.rpc()`
|
||||||
- CRUD operaties uitvoeren met de Supabase SDK
|
- Het verschil uitleggen tussen Server en Client Components in Next.js 15
|
||||||
- Authenticatie implementeren met Auth UI
|
- Een formulier bouwen dat data INSERT in Supabase
|
||||||
- Deployen naar Vercel met environment variables
|
- RLS policies schrijven voor publieke read en insert
|
||||||
- Database principles uit Les 7 toepassen in de praktijk
|
- 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
|
||||||
|
|||||||
@@ -1,126 +1,96 @@
|
|||||||
# Les 9: Full-Stack Mini Project
|
# Les 9: Cursor Deep Dive (Student Plan)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Deel 3: Integration & AI Tooling** (Les 9-12)
|
**Deel 2: Technical Foundations** (Les 4-9)
|
||||||
|
|
||||||
## Beschrijving
|
## 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)
|
| Tijd | Onderwerp | Vorm |
|
||||||
Bespreek klassikaal de Supabase ervaringen uit Les 8 - welke uitdagingen kwamen jullie tegen bij authenticatie en RLS?
|
|------|-----------|------|
|
||||||
|
| 09:00–09:10 | Welkom + terugblik | Klassikaal |
|
||||||
### Doel van deze les
|
| 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 |
|
||||||
Je hebt nu alle bouwstenen:
|
| 09:55–10:15 | Plan Mode: plan LinkVault → review → Build | Klassikaal |
|
||||||
- TypeScript (Les 4)
|
| 10:15–10:30 | Pauze | — |
|
||||||
- Next.js met App Router (Les 5-6)
|
| 10:30–11:05 | Agent Mode: features bouwen | Klassikaal |
|
||||||
- Supabase database & auth (Les 7-8)
|
| 11:05–11:25 | Debug Mode: deterministische bug vinden en fixen | Klassikaal |
|
||||||
|
| 11:25–11:45 | Code Review & Testing + semantic commits + git push | Klassikaal |
|
||||||
Vandaag combineren we dit in een **werkende mini-app**. Geen nieuwe concepten - alleen integratie en toepassing.
|
| 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:**
|
### 2. Plan Mode
|
||||||
- Login met Supabase Auth
|
- `Shift+Tab` → agent researcht, stelt vragen, maakt interactief plan
|
||||||
- Bookmarks toevoegen (URL + titel)
|
- Plan bewerken in markdown → "Build" klikken
|
||||||
- Bookmarks bekijken en verwijderen
|
- Start elke feature met een plan
|
||||||
|
|
||||||
**Tech stack:**
|
### 3. Agent Mode
|
||||||
- Next.js 14 met App Router
|
- Agent = uitvoeren (files, terminal, multi-file). Ask = alleen vragen.
|
||||||
- TypeScript
|
- Goede context geven: `@file`, `@folder`, `@codebase`, `@docs`
|
||||||
- Tailwind CSS
|
- Itereren met screenshots en feedback
|
||||||
- Supabase (auth + database)
|
|
||||||
- React Query
|
|
||||||
|
|
||||||
---
|
### 4. Debug Mode
|
||||||
|
- Voor complexe bugs: hypotheses → logging → reproduceren → analyseren → fix
|
||||||
|
- Tim introduceert bug handmatig (deterministic) → studenten debuggen
|
||||||
|
|
||||||
### Stap-voor-stap
|
### 5. Code Review & Testing
|
||||||
|
- "Find Issues" voor self-review
|
||||||
#### Database Schema
|
- Tests schrijven met Agent Mode
|
||||||
|
- Semantic commits: achteraf changes opdelen in logische groepen
|
||||||
**Tabel: bookmarks**
|
- (Optioneel) PR review met Cursor
|
||||||
| 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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- VS Code
|
- Cursor (Student Plan)
|
||||||
- Supabase Dashboard
|
- Next.js 16
|
||||||
- Browser DevTools
|
- TypeScript
|
||||||
|
- Tailwind CSS
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2.5 uur)
|
## Lesmateriaal
|
||||||
|
- `Les09-Slide-Overzicht.md`
|
||||||
### Bouw de Bookmark Manager
|
- `Les09-Docenttekst.md`
|
||||||
|
- `Les09-Huiswerk.md`
|
||||||
**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
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een complete full-stack applicatie bouwen met Next.js, TypeScript en Supabase
|
- Uitleggen hoe een coding agent werkt (harness: instructions + tools + model)
|
||||||
- CRUD operaties implementeren met React Query
|
- `.cursor/rules` opzetten met meerdere bestanden (alwaysApply, globs)
|
||||||
- Authenticatie integreren in een applicatie
|
- Plan Mode gebruiken om een feature te plannen
|
||||||
- Zelfstandig integratieproblemen oplossen
|
- 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*
|
||||||
|
|||||||
162
readme.md
162
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 |
|
| 04 | [TypeScript Fundamentals](Samenvattingen/Les04-Samenvatting.md) | 2 | ✅ Gegeven |
|
||||||
| 05 | [Next.js — Het React Framework (Part 1)](Samenvattingen/Les05-Samenvatting.md) | 2 | ✅ Gegeven (v1) |
|
| 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 |
|
| 06 | [Next.js — QuickPoll Vervolg (Part 2)](Samenvattingen/Les06-Samenvatting.md) | 2 | 📋 Gepland |
|
||||||
| 07 | [Database Principles & Supabase Setup](Samenvattingen/Les07-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 07 | [Van In-Memory naar Supabase (Introductie)](Samenvattingen/Les07-Samenvatting.md) | 2 | ✅ Gegeven |
|
||||||
| 08 | [Supabase: Auth & CRUD](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 08 | [Van In-Memory naar Supabase (Self-Paced + /create)](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Gepland |
|
||||||
| 09 | [Full-Stack Mini Project](Samenvattingen/Les09-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 09 | [Cursor Deep Dive (Student Plan)](Samenvattingen/Les09-Samenvatting.md) | 2 | 📋 Gepland |
|
||||||
| 10 | [Styling: Tailwind CSS & shadcn/ui](Samenvattingen/Les10-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 10 | [Styling: Tailwind CSS & shadcn/ui](Samenvattingen/Les10-Samenvatting.md) | 3 | 📋 Samenvatting |
|
||||||
| 11 | [Van Idee naar Prototype](Samenvattingen/Les11-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 |
|
| 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 | Lessen | Tools | Kosten |
|
||||||
|------|--------|-------|--------|
|
|------|--------|-------|--------|
|
||||||
| Deel 1: AI Foundations | 1-3 | ChatGPT, v0.dev, OpenCode, **Cursor** | Gratis (Cursor Student Plan) |
|
| 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 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) |
|
| 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
|
# 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:**
|
**Docent vertelt (~75 min, klassikaal):**
|
||||||
- Wat is een relationele database? Tabellen, rijen, kolommen
|
- Recap Les 6: QuickPoll met in-memory data — wat mist nog?
|
||||||
- Primary Keys, Foreign Keys en relaties
|
- Server Component + Client Component patroon (kernmoment)
|
||||||
- Relatie types: one-to-one, one-to-many, many-to-many
|
- Wat is Supabase? Open-source Firebase alternatief op Postgres
|
||||||
- Normalisatie basics
|
- Tabellen, primary keys, foreign keys, CASCADE
|
||||||
- Wat is Supabase? (database + auth in één)
|
- RLS policies basics
|
||||||
- Supabase project setup
|
- SQL: SELECT, WHERE, JOIN
|
||||||
- Table Editor: tabellen maken zonder SQL
|
- Environment variables in Next.js (`NEXT_PUBLIC_` prefix)
|
||||||
- Environment variables configuratie
|
- Supabase JavaScript client (`from`, `select`, `eq`, `single`)
|
||||||
|
|
||||||
**Studenten doen:**
|
**Samen bouwen (~120 min, klassikaal):**
|
||||||
- Database schema tekenen voor eigen project
|
- **Deel 1:** Poll afmaken — `votePoll()`, POST route, Server/Client split, percentage bars
|
||||||
- Supabase account en project aanmaken
|
- **Deel 2:** Supabase no-code — project, polls + options tabellen met foreign key, RLS, testdata, SQL Editor
|
||||||
- Tabellen maken via UI (op basis van eigen schema)
|
- **Deel 3:** Supabase koppelen — `npm install`, `.env.local`, `lib/supabase.ts`, types, `data.ts` herschrijven, components aanpassen, testen
|
||||||
- `.env.local` configureren
|
|
||||||
- Supabase client instellen
|
|
||||||
|
|
||||||
**Lesopdracht:**
|
**Lesopdracht:** Volg klassikaal mee. Aan het eind draait je QuickPoll app met data uit Supabase.
|
||||||
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
|
|
||||||
|
|
||||||
**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)
|
[→ 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:**
|
**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).
|
||||||
- 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
|
|
||||||
|
|
||||||
**Studenten doen:**
|
**Aanpak:** Deel 1-3 klassikaal door de PDF. Deel 4 (/create pagina) zelfstandig met docent als coach.
|
||||||
- **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
|
|
||||||
|
|
||||||
**Lesopdracht:**
|
**Tijdsindeling:**
|
||||||
1. Setup Supabase Auth (email/password)
|
- 09:00–09:15 Welkom + PDF uitdelen
|
||||||
2. Maak login/signup forms
|
- 09:15–09:45 **PDF Deel 1** — Setup (npm, .env, supabase.ts, types, `vote_option` SQL functie)
|
||||||
3. Implementeer user sessions
|
- 09:45–10:00 **PDF Deel 2** — Queries (`getPolls`, `getPollById`, `votePoll` met TODO's)
|
||||||
4. Schrijf RLS policies voor je tabellen
|
- 10:00–10:15 **PDF Deel 3** — Componenten (page, PollItem, VoteForm, [id])
|
||||||
5. Bouw complete CRUD app met auth
|
- 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)
|
[→ 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
|
**Tools:** Cursor, Supabase, Browser DevTools
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user