fix: implement lessons feedback
This commit is contained in:
@@ -72,7 +72,13 @@ Introductie tot standalone AI coding tools. OpenCode als eerste hands-on ervarin
|
|||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
**Component Library Bouwen:**
|
### React Opfrissen (30 min)
|
||||||
|
**BELANGRIJK:** Voordat je verder gaat, fris je React kennis op via EdHub.
|
||||||
|
- Bekijk de React basics modules
|
||||||
|
- Focus op: components, props, state, hooks
|
||||||
|
- Dit is essentieel voor de rest van de cursus!
|
||||||
|
|
||||||
|
### Component Library Bouwen (1.5 uur)
|
||||||
Bouw een volledige landing page component library met OpenCode:
|
Bouw een volledige landing page component library met OpenCode:
|
||||||
- Hero section
|
- Hero section
|
||||||
- Features section (3 cards met icons)
|
- Features section (3 cards met icons)
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ Cruciale kennis over veilig en ethisch werken met AI, gecombineerd met professio
|
|||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de blog posts uit Les 2 - wat waren de ervaringen met AI-assisted coding? Welke limitations ontdekte je?
|
||||||
|
|
||||||
### Deel 1: Ethics, Privacy & Security (1 uur)
|
### Deel 1: Ethics, Privacy & Security (1 uur)
|
||||||
|
|
||||||
**Privacy Risico's - Wat NOOIT te delen:**
|
**Privacy Risico's - Wat NOOIT te delen:**
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 1: AI Foundations** (Les 1-4)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Geavanceerde prompt engineering technieken en introductie tot Skills.sh voor herbruikbare AI best practices.
|
Geavanceerde prompt engineering technieken en introductie tot Skills.sh voor herbruikbare AI best practices.
|
||||||
@@ -20,6 +20,9 @@ Geavanceerde prompt engineering technieken en introductie tot Skills.sh voor her
|
|||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de security/privacy bevindingen uit Les 3 - welke issues vonden jullie in AI-gegenereerde code? Hoe zien jullie AI Safety Checklists eruit?
|
||||||
|
|
||||||
### Geavanceerde Prompt Engineering
|
### Geavanceerde Prompt Engineering
|
||||||
- Zero-shot vs few-shot prompting
|
- Zero-shot vs few-shot prompting
|
||||||
- Chain-of-thought reasoning
|
- Chain-of-thought reasoning
|
||||||
|
|||||||
@@ -1,307 +1,393 @@
|
|||||||
# Les 5: AI Tool Selection & Workflows
|
# Les 5: TypeScript Basics
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 2: Technical Foundations** (Les 5-9)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Leer de sterke en zwakke punten van elke AI tool kennen. Ontwikkel een framework om de juiste tool te kiezen voor de juiste taak en bouw je eigen workflow.
|
Introductie tot TypeScript voor React developers. Leer waarom TypeScript waardevol is, hoe je types schrijft, en hoe je het combineert met React.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Waarom Tool Selection Belangrijk Is
|
### Waarom TypeScript?
|
||||||
|
|
||||||
Je kent nu meerdere AI tools:
|
**Het probleem met JavaScript:**
|
||||||
- ChatGPT (brainstormen, planning, uitleg)
|
```javascript
|
||||||
- Claude (lange context, nuance, analyse)
|
function greet(name) {
|
||||||
- v0.dev (UI prototyping)
|
return "Hello, " + name.toUpperCase();
|
||||||
- OpenCode (code schrijven met project context)
|
}
|
||||||
|
|
||||||
**Het probleem:** Elke tool heeft sterke en zwakke punten. De juiste tool kiezen bespaart tijd en levert betere resultaten.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Tool Vergelijking
|
|
||||||
|
|
||||||
| Tool | Sterk in | Minder sterk in | Kosten |
|
|
||||||
|------|----------|-----------------|--------|
|
|
||||||
| **ChatGPT** | Brainstormen, uitleg, planning, algemene kennis | Grote codebases, lange context | Gratis / Pro €20/maand |
|
|
||||||
| **Claude** | Lange documenten, nuance, analyse, veiligheid | Soms te voorzichtig, geen images genereren | Gratis / Pro $20/maand |
|
|
||||||
| **v0.dev** | UI components, snel prototypen, Tailwind | Complexe logica, backend | Gratis tier |
|
|
||||||
| **OpenCode** | Code schrijven, project context, terminal | Geen web access, geen images | Gratis |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Tool Selection Framework
|
|
||||||
|
|
||||||
**Stap 1: Identificeer de taak**
|
|
||||||
- Wat wil je bereiken?
|
|
||||||
- Hoe complex is het?
|
|
||||||
- Hoeveel context is nodig?
|
|
||||||
|
|
||||||
**Stap 2: Kies de juiste tool**
|
|
||||||
|
|
||||||
|
greet(42); // Runtime error! 42.toUpperCase is not a function
|
||||||
```
|
```
|
||||||
Als je wilt... Gebruik...
|
|
||||||
─────────────────────────────────────────────────
|
**De oplossing met TypeScript:**
|
||||||
Brainstormen over een idee → ChatGPT
|
```typescript
|
||||||
Een lange codebase analyseren → Claude
|
function greet(name: string): string {
|
||||||
Snel een UI component maken → v0.dev
|
return "Hello, " + name.toUpperCase();
|
||||||
Code schrijven met project context → OpenCode
|
}
|
||||||
Een complex document begrijpen → Claude
|
|
||||||
Uitleg krijgen over een concept → ChatGPT
|
greet(42); // Compile error! Argument of type 'number' is not assignable to type 'string'
|
||||||
React component met styling → v0.dev
|
```
|
||||||
Feature implementeren in project → OpenCode
|
|
||||||
|
**Voordelen:**
|
||||||
|
- Fouten vinden VOORDAT je code runt
|
||||||
|
- Betere autocomplete in je editor
|
||||||
|
- Code is zelf-documenterend
|
||||||
|
- AI tools begrijpen je code beter
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Basic Types
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Primitives
|
||||||
|
let name: string = "Tim";
|
||||||
|
let age: number = 25;
|
||||||
|
let isStudent: boolean = true;
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
let numbers: number[] = [1, 2, 3];
|
||||||
|
let names: string[] = ["Tim", "Anna"];
|
||||||
|
|
||||||
|
// Alternative array syntax
|
||||||
|
let scores: Array<number> = [90, 85, 88];
|
||||||
|
|
||||||
|
// Objects
|
||||||
|
let user: { name: string; age: number } = {
|
||||||
|
name: "Tim",
|
||||||
|
age: 25
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Workflow Patterns
|
### Type Inference
|
||||||
|
|
||||||
**Pattern 1: Planning → Prototyping → Implementation**
|
TypeScript raadt types vaak zelf:
|
||||||
```
|
|
||||||
1. ChatGPT: Brainstorm features, maak planning
|
```typescript
|
||||||
2. v0.dev: Genereer UI prototypes
|
// TypeScript weet dat dit een string is
|
||||||
3. OpenCode: Implementeer met project context
|
let message = "Hello"; // type: string
|
||||||
|
|
||||||
|
// TypeScript weet dat dit een number is
|
||||||
|
let count = 42; // type: number
|
||||||
|
|
||||||
|
// TypeScript weet wat de functie returned
|
||||||
|
function double(x: number) {
|
||||||
|
return x * 2; // return type: number (inferred)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pattern 2: Research → Design → Build**
|
**Regel:** Je hoeft niet altijd types te schrijven. Laat TypeScript inferren waar mogelijk.
|
||||||
```
|
|
||||||
1. ChatGPT/Claude: Research beste aanpak
|
|
||||||
2. v0.dev: Design components
|
|
||||||
3. OpenCode: Bouw en integreer
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pattern 3: Quick Iteration**
|
---
|
||||||
```
|
|
||||||
1. v0.dev: Snel component genereren
|
### Interfaces
|
||||||
2. OpenCode: Aanpassen en integreren
|
|
||||||
3. Repeat
|
Voor het beschrijven van object shapes:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user: User = {
|
||||||
|
id: 1,
|
||||||
|
name: "Tim",
|
||||||
|
email: "tim@example.com",
|
||||||
|
isActive: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optional properties met ?
|
||||||
|
interface Product {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
description?: string; // optioneel
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Praktijk: Dezelfde Taak, Drie Tools
|
### Type Aliases
|
||||||
|
|
||||||
**Opdracht:** Bouw een Contact Form component
|
Alternatief voor interfaces, meer flexibel:
|
||||||
|
|
||||||
**Met ChatGPT:**
|
```typescript
|
||||||
```
|
// Type alias voor object
|
||||||
Prompt: Ik wil een contact form maken met React en Tailwind.
|
type User = {
|
||||||
Velden: naam, email, bericht. Validatie nodig.
|
id: number;
|
||||||
Geef me de code en leg uit hoe het werkt.
|
name: string;
|
||||||
```
|
};
|
||||||
→ Krijg: Uitleg + code, maar zonder project context
|
|
||||||
|
|
||||||
**Met v0.dev:**
|
// Type alias voor union types
|
||||||
```
|
type Status = "pending" | "approved" | "rejected";
|
||||||
Prompt: Modern contact form with name, email, message fields.
|
|
||||||
Tailwind styling, validation, responsive design.
|
|
||||||
```
|
|
||||||
→ Krijg: Visueel prototype, direct te gebruiken
|
|
||||||
|
|
||||||
**Met OpenCode:**
|
// Type alias voor functie
|
||||||
|
type GreetFunction = (name: string) => string;
|
||||||
```
|
```
|
||||||
Prompt: Maak een ContactForm component in src/components/
|
|
||||||
met naam, email en bericht velden. Gebruik onze bestaande
|
**Interface vs Type:**
|
||||||
Input en Button components. Voeg Zod validatie toe.
|
- Interface: voor objecten, kan extended worden
|
||||||
```
|
- Type: voor alles, meer flexibel
|
||||||
→ Krijg: Geïntegreerde code die past in je project
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Wanneer Combineer Je Tools?
|
### TypeScript met React
|
||||||
|
|
||||||
**Scenario 1: Nieuwe feature bouwen**
|
**Props typen:**
|
||||||
1. ChatGPT: "Hoe zou je een dark mode toggle implementeren in React?"
|
|
||||||
2. v0.dev: "Dark mode toggle component with smooth transition"
|
|
||||||
3. OpenCode: "Integreer deze toggle in onze navbar, sla preference op in localStorage"
|
|
||||||
|
|
||||||
**Scenario 2: Bug oplossen**
|
```typescript
|
||||||
1. OpenCode: Vraag om bug te identificeren
|
// Interface voor props
|
||||||
2. Claude: Als de foutmelding complex is, vraag om uitleg
|
interface ButtonProps {
|
||||||
3. OpenCode: Implementeer de fix
|
label: string;
|
||||||
|
onClick: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
**Scenario 3: Nieuwe technologie leren**
|
// Component met typed props
|
||||||
1. ChatGPT: "Leg uit hoe React Server Components werken"
|
function Button({ label, onClick, disabled = false }: ButtonProps) {
|
||||||
2. v0.dev: "Example of React Server Component with data fetching"
|
return (
|
||||||
3. OpenCode: "Help me dit toe te passen in mijn Next.js project"
|
<button onClick={onClick} disabled={disabled}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gebruik
|
||||||
|
<Button label="Click me" onClick={() => console.log("Clicked!")} />
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Anti-Patterns (Wat Niet Te Doen)
|
### useState met Types
|
||||||
|
|
||||||
**❌ Verkeerde tool voor de taak:**
|
```typescript
|
||||||
- ChatGPT vragen om een hele app te bouwen → te weinig context
|
import { useState } from 'react';
|
||||||
- v0.dev vragen om complexe backend logica → niet zijn sterke punt
|
|
||||||
- OpenCode vragen om design inspiratie → kan geen images maken
|
|
||||||
|
|
||||||
**❌ Heen en weer kopiëren zonder begrip:**
|
// Type inference werkt vaak
|
||||||
- Kopieer niet blind code van ChatGPT naar je project
|
const [count, setCount] = useState(0); // number
|
||||||
- Begrijp eerst WAT de code doet
|
|
||||||
|
|
||||||
**❌ Dezelfde prompt in elke tool:**
|
// Explicit type voor complexe data
|
||||||
- Pas je prompt aan per tool
|
interface User {
|
||||||
- v0.dev wil visuele beschrijvingen
|
id: number;
|
||||||
- OpenCode wil project-specifieke context
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [user, setUser] = useState<User | null>(null);
|
||||||
|
|
||||||
|
// Array van objecten
|
||||||
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Je Eigen Workflow Documenteren
|
### Generics Basics
|
||||||
|
|
||||||
Maak een `docs/WORKFLOW.md` in je project:
|
Generics maken code herbruikbaar:
|
||||||
|
|
||||||
```markdown
|
```typescript
|
||||||
# Mijn AI Workflow
|
// Array is een generic type
|
||||||
|
const numbers: Array<number> = [1, 2, 3];
|
||||||
|
const names: Array<string> = ["Tim", "Anna"];
|
||||||
|
|
||||||
## Planning Fase
|
// Promise is een generic type
|
||||||
- Tool: ChatGPT
|
async function fetchUser(): Promise<User> {
|
||||||
- Wat: Feature breakdown, technische beslissingen
|
const response = await fetch('/api/user');
|
||||||
- Template prompt: "Ik wil [feature]. Wat zijn de stappen?"
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
## UI Design Fase
|
// Je kunt ook eigen generics maken
|
||||||
- Tool: v0.dev
|
function firstElement<T>(arr: T[]): T | undefined {
|
||||||
- Wat: Component prototypes
|
return arr[0];
|
||||||
- Template prompt: "Modern [component] with [requirements]"
|
}
|
||||||
|
|
||||||
## Implementation Fase
|
const first = firstElement([1, 2, 3]); // type: number | undefined
|
||||||
- Tool: OpenCode
|
```
|
||||||
- Wat: Code schrijven en integreren
|
|
||||||
- Template prompt: "Maak [component] in [locatie] met [requirements]"
|
|
||||||
|
|
||||||
## Debugging
|
---
|
||||||
- Tool: OpenCode (eerst), Claude (als het complex is)
|
|
||||||
- Wat: Errors oplossen
|
### Veelvoorkomende Errors
|
||||||
- Template prompt: "Ik krijg deze error: [error]. Dit is mijn code: [code]"
|
|
||||||
|
**Error 1: Type 'X' is not assignable to type 'Y'**
|
||||||
|
```typescript
|
||||||
|
let name: string = 42; // Error!
|
||||||
|
// Fix: gebruik correct type
|
||||||
|
let name: string = "Tim";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error 2: Property 'X' does not exist on type 'Y'**
|
||||||
|
```typescript
|
||||||
|
interface User { name: string; }
|
||||||
|
const user: User = { name: "Tim" };
|
||||||
|
console.log(user.age); // Error! 'age' bestaat niet
|
||||||
|
// Fix: voeg property toe aan interface
|
||||||
|
```
|
||||||
|
|
||||||
|
**Error 3: Object is possibly 'undefined'**
|
||||||
|
```typescript
|
||||||
|
const users: User[] = [];
|
||||||
|
console.log(users[0].name); // Error! users[0] kan undefined zijn
|
||||||
|
// Fix: check eerst
|
||||||
|
if (users[0]) {
|
||||||
|
console.log(users[0].name);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### JS naar TS Omzetten
|
||||||
|
|
||||||
|
**Stap 1:** Rename `.js` naar `.tsx` (voor React) of `.ts`
|
||||||
|
|
||||||
|
**Stap 2:** Fix de rode errors - meestal:
|
||||||
|
- Voeg types toe aan function parameters
|
||||||
|
- Maak interfaces voor objecten
|
||||||
|
- Handle nullable values
|
||||||
|
|
||||||
|
**Voorbeeld:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Voorheen (JavaScript)
|
||||||
|
function UserCard({ user }) {
|
||||||
|
return <div>{user.name}</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Nu (TypeScript)
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UserCardProps {
|
||||||
|
user: User;
|
||||||
|
}
|
||||||
|
|
||||||
|
function UserCard({ user }: UserCardProps) {
|
||||||
|
return <div>{user.name}</div>;
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- ChatGPT
|
|
||||||
- Claude
|
|
||||||
- v0.dev
|
|
||||||
- OpenCode/WebStorm
|
- OpenCode/WebStorm
|
||||||
|
- TypeScript (via Next.js)
|
||||||
|
- React
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Tool Comparison Challenge
|
### TypeScript Hands-on
|
||||||
|
|
||||||
**Deel 1: Dezelfde Taak, Drie Tools (1 uur)**
|
**Deel 1: JS naar TS Omzetten (45 min)**
|
||||||
|
|
||||||
Bouw een "Contact Form" component met alle drie de tools:
|
Gegeven JavaScript component:
|
||||||
|
|
||||||
1. **ChatGPT (20 min)**
|
```javascript
|
||||||
- Vraag om code + uitleg
|
function ProductCard({ product, onAddToCart }) {
|
||||||
- Noteer: hoe lang duurde het, kwaliteit output, wat miste?
|
return (
|
||||||
|
<div className="p-4 border rounded">
|
||||||
|
<h2>{product.name}</h2>
|
||||||
|
<p>${product.price}</p>
|
||||||
|
{product.description && <p>{product.description}</p>}
|
||||||
|
<button onClick={() => onAddToCart(product.id)}>
|
||||||
|
Add to Cart
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
2. **v0.dev (20 min)**
|
Zet dit om naar TypeScript:
|
||||||
- Genereer visueel prototype
|
1. Maak `Product` interface
|
||||||
- Noteer: hoe snel, hoe mooi, hoe aanpasbaar?
|
2. Maak `ProductCardProps` interface
|
||||||
|
3. Type de component
|
||||||
|
4. Fix alle TypeScript errors
|
||||||
|
|
||||||
3. **OpenCode (20 min)**
|
**Deel 2: Interfaces Schrijven (30 min)**
|
||||||
- Integreer in bestaand project
|
|
||||||
- Noteer: hoe goed past het, hoeveel aanpassing nodig?
|
|
||||||
|
|
||||||
**Deel 2: Analyse (30 min)**
|
Maak interfaces voor:
|
||||||
|
|
||||||
Vul dit schema in:
|
1. **User** met: id, name, email, avatar (optioneel), createdAt
|
||||||
|
2. **Product** met: id, name, price, description (optioneel), inStock, category
|
||||||
|
3. **Order** met: id, userId, products (array), total, status (pending/shipped/delivered)
|
||||||
|
|
||||||
| Aspect | ChatGPT | v0.dev | OpenCode |
|
**Deel 3: React Component met Types (45 min)**
|
||||||
|--------|---------|--------|----------|
|
|
||||||
| Tijd tot werkend component | | | |
|
|
||||||
| Kwaliteit code | | | |
|
|
||||||
| Visueel design | | | |
|
|
||||||
| Past in project | | | |
|
|
||||||
| Hoeveel aanpassing nodig | | | |
|
|
||||||
| Totaalscore (1-10) | | | |
|
|
||||||
|
|
||||||
**Deel 3: Workflow Documentatie (30 min)**
|
Bouw een `UserList` component:
|
||||||
|
- Props: users array, onSelectUser callback
|
||||||
|
- State: selectedUserId (number of null)
|
||||||
|
- Toon lijst van users, highlight geselecteerde
|
||||||
|
|
||||||
- Maak `docs/WORKFLOW.md` in je project
|
Alle types moeten correct zijn. Geen `any` gebruiken!
|
||||||
- Documenteer je ideale workflow per taaktype
|
|
||||||
- Inclusief template prompts voor elke tool
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Screenshot van alle 3 contact forms
|
- ProductCard.tsx met correcte types
|
||||||
- Ingevuld vergelijkingsschema
|
- types.ts met alle interfaces
|
||||||
- `docs/WORKFLOW.md` bestand
|
- UserList.tsx volledig getypt
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Bouw Je Tool Selection Cheat Sheet
|
### TypeScript Verdieping
|
||||||
|
|
||||||
**Deel 1: Cheat Sheet Maken (1 uur)**
|
**Deel 1: Drie Components Bouwen (1 uur)**
|
||||||
|
|
||||||
Maak een persoonlijke "Tool Selection Cheat Sheet" (1 pagina):
|
Bouw volledig in TypeScript:
|
||||||
|
|
||||||
```markdown
|
1. **SearchInput** component
|
||||||
# Mijn AI Tool Cheat Sheet
|
- Props: value, onChange, placeholder (optioneel)
|
||||||
|
- Volledig getypt
|
||||||
|
|
||||||
## Wanneer gebruik ik wat?
|
2. **DataTable** component
|
||||||
|
- Generic: werkt met elk type data
|
||||||
|
- Props: data array, columns config
|
||||||
|
- Type-safe rendering
|
||||||
|
|
||||||
### ChatGPT
|
3. **Modal** component
|
||||||
- ✅ Gebruik voor: [jouw ervaring]
|
- Props: isOpen, onClose, title, children
|
||||||
- ❌ Niet voor: [jouw ervaring]
|
- Correct gebruik van React.ReactNode
|
||||||
- 💡 Beste prompt tip: [jouw tip]
|
|
||||||
|
|
||||||
### Claude
|
**Deel 2: Eindproject Interfaces (30 min)**
|
||||||
- ✅ Gebruik voor: [jouw ervaring]
|
|
||||||
- ❌ Niet voor: [jouw ervaring]
|
|
||||||
- 💡 Beste prompt tip: [jouw tip]
|
|
||||||
|
|
||||||
### v0.dev
|
Bedenk de data structuur voor je eindproject:
|
||||||
- ✅ Gebruik voor: [jouw ervaring]
|
- Welke entiteiten heb je? (users, posts, products, etc.)
|
||||||
- ❌ Niet voor: [jouw ervaring]
|
- Maak interface voor elke entiteit
|
||||||
- 💡 Beste prompt tip: [jouw tip]
|
- Documenteer relaties tussen entiteiten
|
||||||
|
|
||||||
### OpenCode
|
**Deel 3: Cheat Sheet (30 min)**
|
||||||
- ✅ Gebruik voor: [jouw ervaring]
|
|
||||||
- ❌ Niet voor: [jouw ervaring]
|
|
||||||
- 💡 Beste prompt tip: [jouw tip]
|
|
||||||
|
|
||||||
## Mijn Favoriete Combinaties
|
Maak persoonlijke TypeScript cheat sheet:
|
||||||
1. [Workflow 1]
|
- Meest gebruikte types
|
||||||
2. [Workflow 2]
|
- Interface vs Type wanneer
|
||||||
```
|
- Common patterns met React
|
||||||
|
- Hoe je errors oplost
|
||||||
**Deel 2: Testen op Nieuwe Taken (45 min)**
|
|
||||||
|
|
||||||
Test je cheat sheet op 2 nieuwe taken:
|
|
||||||
1. Bouw een "Testimonial Card" component
|
|
||||||
2. Voeg een "Dark Mode Toggle" toe
|
|
||||||
|
|
||||||
Per taak:
|
|
||||||
- Kies tools op basis van je cheat sheet
|
|
||||||
- Voer uit en noteer resultaat
|
|
||||||
- Update cheat sheet indien nodig
|
|
||||||
|
|
||||||
**Deel 3: Reflectie (15 min)**
|
|
||||||
|
|
||||||
Schrijf korte reflectie (400 woorden):
|
|
||||||
- Welke tool is jouw favoriet en waarom?
|
|
||||||
- Wanneer combineer je tools?
|
|
||||||
- Wat ga je anders doen na deze les?
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Tool Selection Cheat Sheet (1 pagina)
|
- 3 TypeScript components
|
||||||
- 2 gebouwde components (Testimonial Card, Dark Mode Toggle)
|
- types/index.ts met eindproject interfaces
|
||||||
- Reflectie (400 woorden)
|
- TypeScript cheat sheet (1 pagina)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- De sterke en zwakke punten van elke AI tool benoemen
|
- Uitleggen waarom TypeScript waardevol is
|
||||||
- De juiste tool kiezen voor een specifieke taak
|
- Basic types gebruiken (string, number, boolean, arrays)
|
||||||
- Meerdere tools combineren in een effectieve workflow
|
- Interfaces en type aliases schrijven
|
||||||
- Een persoonlijke workflow documenteren
|
- React components typen met props
|
||||||
- Template prompts schrijven per tool
|
- useState met types gebruiken
|
||||||
- Kritisch evalueren welke tool wanneer het beste werkt
|
- Generics op basisniveau begrijpen
|
||||||
|
- JavaScript code omzetten naar TypeScript
|
||||||
|
- TypeScript errors lezen en oplossen
|
||||||
|
|||||||
@@ -1,288 +1,365 @@
|
|||||||
# Les 6: Hands-on: Van Idee naar Prototype
|
# Les 6: Next.js Fundamentals 1 - SSR & Routing
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 2: Technical Foundations** (Les 5-9)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Pas alles wat je hebt geleerd toe in een hands-on sessie. Ga van een vaag idee naar een werkend prototype met behulp van je AI workflow.
|
Introductie tot Next.js voor React developers. Leer wat Server-Side Rendering is, hoe de App Router werkt, en bouw je eerste Next.js applicatie met meerdere pagina's.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Van Idee naar Feature Breakdown
|
### Wat is Next.js?
|
||||||
|
|
||||||
**Het probleem:** Je hebt een idee, maar waar begin je?
|
**React met superpowers:**
|
||||||
|
- React = library voor UI components
|
||||||
|
- Next.js = framework dat React complete maakt
|
||||||
|
|
||||||
**Stap 1: Beschrijf je idee in 1-2 zinnen**
|
**Next.js voegt toe:**
|
||||||
```
|
- Routing (geen extra library nodig)
|
||||||
"Ik wil een app waar je kunt bijhouden welke planten water nodig hebben."
|
- Server-Side Rendering (SEO, performance)
|
||||||
```
|
- API routes (backend in je frontend project)
|
||||||
|
- Optimalisaties (images, fonts, bundling)
|
||||||
**Stap 2: Vraag AI om feature breakdown**
|
|
||||||
```
|
|
||||||
Prompt: Ik wil een plant watering tracker app bouwen.
|
|
||||||
Wat zijn de minimale features voor een werkend prototype?
|
|
||||||
Denk aan: wat moet een gebruiker kunnen doen?
|
|
||||||
```
|
|
||||||
|
|
||||||
**Stap 3: Prioriteer (MVP denken)**
|
|
||||||
- Wat is essentieel? → In prototype
|
|
||||||
- Wat is nice-to-have? → Later
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Component Thinking
|
### Server-Side Rendering (SSR) vs Client-Side Rendering (CSR)
|
||||||
|
|
||||||
**Vraag jezelf af:**
|
**Client-Side Rendering (gewone React):**
|
||||||
- Welke "blokken" zie ik op het scherm?
|
|
||||||
- Welke blokken worden herhaald?
|
|
||||||
- Welke blokken komen op meerdere pagina's?
|
|
||||||
|
|
||||||
**Voorbeeld: Plant Tracker**
|
|
||||||
```
|
```
|
||||||
Herhaalde componenten:
|
1. Browser vraagt pagina
|
||||||
- PlantCard (naam, foto, laatste water datum)
|
2. Server stuurt lege HTML + JavaScript
|
||||||
- WaterButton (markeer als water gegeven)
|
3. JavaScript laadt in browser
|
||||||
|
4. JavaScript rendert de pagina
|
||||||
|
5. Gebruiker ziet content
|
||||||
|
```
|
||||||
|
**Probleem:** Lege pagina tot JS klaar is. Google ziet ook lege pagina.
|
||||||
|
|
||||||
Pagina componenten:
|
**Server-Side Rendering (Next.js):**
|
||||||
- PlantList (toont alle PlantCards)
|
```
|
||||||
- AddPlantForm (nieuw plant toevoegen)
|
1. Browser vraagt pagina
|
||||||
|
2. Server rendert HTML met content
|
||||||
|
3. Browser toont direct de content
|
||||||
|
4. JavaScript laadt (hydration)
|
||||||
|
5. Pagina wordt interactief
|
||||||
|
```
|
||||||
|
**Voordeel:** Direct content zichtbaar, beter voor SEO.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### De App Router
|
||||||
|
|
||||||
|
Next.js 13+ gebruikt de "App Router" met file-based routing:
|
||||||
|
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
├── page.tsx → /
|
||||||
|
├── about/
|
||||||
|
│ └── page.tsx → /about
|
||||||
|
├── products/
|
||||||
|
│ ├── page.tsx → /products
|
||||||
|
│ └── [id]/
|
||||||
|
│ └── page.tsx → /products/123
|
||||||
|
└── layout.tsx → Wrapper voor alle pagina's
|
||||||
|
```
|
||||||
|
|
||||||
|
**De regel:** Elke `page.tsx` wordt een route!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Project Aanmaken
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-next-app@latest mijn-app
|
||||||
|
|
||||||
|
# Antwoorden:
|
||||||
|
# ✔ TypeScript? → Yes
|
||||||
|
# ✔ ESLint? → Yes
|
||||||
|
# ✔ Tailwind CSS? → Yes
|
||||||
|
# ✔ `src/` directory? → Yes
|
||||||
|
# ✔ App Router? → Yes
|
||||||
|
# ✔ Customize import alias? → No
|
||||||
|
|
||||||
|
cd mijn-app
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open `http://localhost:3000` - je app draait!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Pagina's Maken
|
||||||
|
|
||||||
|
**Simpele pagina (`app/about/page.tsx`):**
|
||||||
|
```tsx
|
||||||
|
export default function AboutPage() {
|
||||||
|
return (
|
||||||
|
<div className="p-8">
|
||||||
|
<h1 className="text-3xl font-bold">Over Ons</h1>
|
||||||
|
<p>Welkom op de about pagina!</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dat is alles! Ga naar `/about` en je ziet je pagina.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Layouts
|
||||||
|
|
||||||
|
Layouts wrappen pagina's en blijven behouden tijdens navigatie.
|
||||||
|
|
||||||
|
**Root Layout (`app/layout.tsx`):**
|
||||||
|
```tsx
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="nl">
|
||||||
|
<body>
|
||||||
|
<header className="p-4 bg-blue-500 text-white">
|
||||||
|
<nav>Mijn App</nav>
|
||||||
|
</header>
|
||||||
|
<main>{children}</main>
|
||||||
|
<footer className="p-4 bg-gray-200">
|
||||||
|
© 2024
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### MVP (Minimum Viable Product) Denken
|
### Nested Layouts
|
||||||
|
|
||||||
**Wat is MVP?**
|
Je kunt layouts nesten voor secties:
|
||||||
De simpelste versie van je app die nog steeds waarde levert.
|
|
||||||
|
|
||||||
**❌ Niet MVP:**
|
|
||||||
- Alle features tegelijk
|
|
||||||
- Perfect design
|
|
||||||
- Edge cases afhandelen
|
|
||||||
- Login systeem
|
|
||||||
|
|
||||||
**✅ Wel MVP:**
|
|
||||||
- Core functionaliteit werkt
|
|
||||||
- Basis styling
|
|
||||||
- Happy path werkt
|
|
||||||
- Hardcoded data is oké
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### De Prototype Workflow
|
|
||||||
|
|
||||||
```
|
```
|
||||||
1. IDEE (1-2 zinnen)
|
app/
|
||||||
↓
|
├── layout.tsx → Root layout
|
||||||
2. FEATURES (AI breakdown)
|
├── page.tsx → Homepage
|
||||||
↓
|
└── dashboard/
|
||||||
3. PRIORITEER (wat is MVP?)
|
├── layout.tsx → Dashboard layout (sidebar)
|
||||||
↓
|
└── page.tsx → Dashboard pagina
|
||||||
4. COMPONENTS (welke blokken?)
|
```
|
||||||
↓
|
|
||||||
5. BOUWEN (tool per stap)
|
**Dashboard Layout (`app/dashboard/layout.tsx`):**
|
||||||
↓
|
```tsx
|
||||||
6. ITEREREN (feedback → aanpassen)
|
export default function DashboardLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="flex">
|
||||||
|
<aside className="w-64 bg-gray-100 p-4">
|
||||||
|
<nav>Sidebar hier</nav>
|
||||||
|
</aside>
|
||||||
|
<div className="flex-1">{children}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Voorbeeld: Weer Widget Prototype
|
### Dynamic Routes
|
||||||
|
|
||||||
**Stap 1: Idee**
|
Voor pagina's met parameters zoals `/products/123`:
|
||||||
"Simpele weer widget met 3-daagse forecast"
|
|
||||||
|
|
||||||
**Stap 2: AI Feature Breakdown**
|
**Folder structuur:**
|
||||||
```
|
```
|
||||||
Vraag aan ChatGPT:
|
app/products/[id]/page.tsx
|
||||||
"Wat zijn de minimale features voor een weer widget met 3-daagse forecast?"
|
|
||||||
|
|
||||||
Antwoord:
|
|
||||||
- Huidige temperatuur tonen
|
|
||||||
- Weer icoon (zon, regen, etc.)
|
|
||||||
- 3-daagse forecast (dag + temp + icoon)
|
|
||||||
- Locatie tonen
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Stap 3: MVP Selectie**
|
**De pagina:**
|
||||||
- ✅ Huidige temperatuur
|
```tsx
|
||||||
- ✅ Weer icoon
|
interface Props {
|
||||||
- ✅ 3 dagen forecast
|
params: { id: string }
|
||||||
- ❌ Locatie selectie (later)
|
}
|
||||||
- ❌ Animated icons (later)
|
|
||||||
|
|
||||||
**Stap 4: Components**
|
export default function ProductPage({ params }: Props) {
|
||||||
```
|
return (
|
||||||
WeatherWidget/
|
<div>
|
||||||
├── CurrentWeather (temp + icoon)
|
<h1>Product {params.id}</h1>
|
||||||
├── ForecastDay (dag + temp + icoon)
|
</div>
|
||||||
└── ForecastList (3x ForecastDay)
|
)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Stap 5: Bouwen**
|
Nu werkt `/products/1`, `/products/abc`, etc.
|
||||||
1. v0.dev: "Weather widget with current temp and 3 day forecast, minimal design"
|
|
||||||
2. OpenCode: "Integreer dit in mijn project, maak components in src/components/weather/"
|
|
||||||
|
|
||||||
**Stap 6: Itereren**
|
|
||||||
- Wat werkt niet?
|
|
||||||
- Wat kan beter?
|
|
||||||
- Vraag AI om verbeteringen
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Mini-Project Ideeën
|
### Link Component
|
||||||
|
|
||||||
Kies een van deze voor je lesopdracht:
|
Gebruik `Link` voor client-side navigatie (snel, geen page reload):
|
||||||
|
|
||||||
| Project | Core Feature | Complexiteit |
|
```tsx
|
||||||
|---------|-------------|--------------|
|
import Link from 'next/link'
|
||||||
| **Weer Widget** | 3-daagse forecast | ⭐ |
|
|
||||||
| **Quiz App** | 3 vragen + score | ⭐ |
|
export default function Navigation() {
|
||||||
| **Recipe Card** | Ingrediënten toggle | ⭐ |
|
return (
|
||||||
| **Pomodoro Timer** | Start/stop + countdown | ⭐⭐ |
|
<nav className="flex gap-4">
|
||||||
| **Expense Tracker** | Lijst + totaal | ⭐⭐ |
|
<Link href="/">Home</Link>
|
||||||
|
<Link href="/about">About</Link>
|
||||||
|
<Link href="/products">Products</Link>
|
||||||
|
<Link href="/products/123">Product 123</Link>
|
||||||
|
</nav>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Niet doen:**
|
||||||
|
```tsx
|
||||||
|
// ❌ Dit werkt maar is langzamer
|
||||||
|
<a href="/about">About</a>
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Documenteer Je Proces
|
### Special Files
|
||||||
|
|
||||||
Maak aantekeningen tijdens het bouwen:
|
Next.js heeft speciale bestanden:
|
||||||
|
|
||||||
```markdown
|
| File | Doel |
|
||||||
# Mijn Prototype: [naam]
|
|------|------|
|
||||||
|
| `page.tsx` | De pagina content |
|
||||||
|
| `layout.tsx` | Wrapper, blijft behouden |
|
||||||
|
| `loading.tsx` | Loading state |
|
||||||
|
| `error.tsx` | Error boundary |
|
||||||
|
| `not-found.tsx` | 404 pagina |
|
||||||
|
|
||||||
## Idee
|
**Loading state (`app/products/loading.tsx`):**
|
||||||
[1-2 zinnen]
|
```tsx
|
||||||
|
export default function Loading() {
|
||||||
## Feature Breakdown
|
return <div>Laden...</div>
|
||||||
1. [feature 1]
|
}
|
||||||
2. [feature 2]
|
|
||||||
3. [feature 3]
|
|
||||||
|
|
||||||
## MVP Selectie
|
|
||||||
- ✅ [wat wel]
|
|
||||||
- ❌ [wat niet (nog)]
|
|
||||||
|
|
||||||
## Components
|
|
||||||
- [Component 1]
|
|
||||||
- [Component 2]
|
|
||||||
|
|
||||||
## Prompts die Werkten
|
|
||||||
```
|
```
|
||||||
[prompt]
|
|
||||||
```
|
|
||||||
→ [wat leverde het op]
|
|
||||||
|
|
||||||
## Wat Ging Fout
|
---
|
||||||
- [probleem 1] → [hoe opgelost]
|
|
||||||
|
|
||||||
## Lessons Learned
|
### Metadata (SEO)
|
||||||
- [les 1]
|
|
||||||
- [les 2]
|
Voeg metadata toe per pagina:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import type { Metadata } from 'next'
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'Over Ons | Mijn App',
|
||||||
|
description: 'Lees meer over ons bedrijf',
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AboutPage() {
|
||||||
|
return <h1>Over Ons</h1>
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- ChatGPT (voor planning)
|
- Next.js 14
|
||||||
- v0.dev (voor prototypes)
|
- TypeScript
|
||||||
- OpenCode/WebStorm (voor implementation)
|
- Tailwind CSS
|
||||||
|
- OpenCode/WebStorm
|
||||||
|
- Vercel
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Bouw Je Mini-Prototype
|
### Bouw Multi-Page Next.js App
|
||||||
|
|
||||||
**Deel 1: Planning (30 min)**
|
**Deel 1: Project Setup (20 min)**
|
||||||
|
|
||||||
1. Kies een project uit de lijst (of bedenk eigen simpel idee)
|
1. `npx create-next-app@latest my-shop` (TypeScript + Tailwind + App Router)
|
||||||
2. Schrijf je idee in 1-2 zinnen
|
2. Open in editor
|
||||||
3. Vraag ChatGPT om feature breakdown
|
3. `npm run dev`
|
||||||
4. Selecteer MVP features (max 3)
|
4. Verifieer: `localhost:3000` werkt
|
||||||
5. Schets de components op papier
|
|
||||||
|
|
||||||
**Deel 2: Bouwen (1 uur)**
|
**Deel 2: Pagina's Maken (40 min)**
|
||||||
|
|
||||||
1. Genereer UI in v0.dev
|
Maak deze pagina's:
|
||||||
2. Open project in OpenCode
|
1. `/` - Homepage met welkomstbericht
|
||||||
3. Integreer en pas aan
|
2. `/about` - Over ons pagina
|
||||||
4. Zorg dat het werkt (happy path)
|
3. `/products` - Producten overzicht
|
||||||
|
4. `/contact` - Contact pagina
|
||||||
|
|
||||||
**Focus op WORKFLOW, niet perfectie!**
|
Elke pagina moet unieke content hebben.
|
||||||
|
|
||||||
**Deel 3: Documentatie (30 min)**
|
**Deel 3: Layout met Navigatie (30 min)**
|
||||||
|
|
||||||
Maak `docs/PROTOTYPE-LOG.md`:
|
1. Maak Header component met navigatie (gebruik Link)
|
||||||
- Je idee
|
2. Maak Footer component
|
||||||
- Feature breakdown
|
3. Voeg beide toe aan root layout
|
||||||
- MVP keuzes
|
4. Test: navigatie werkt zonder page reload
|
||||||
- Prompts die werkten
|
|
||||||
- Wat ging fout en hoe opgelost
|
**Deel 4: Dynamic Route (30 min)**
|
||||||
- Lessons learned
|
|
||||||
|
1. Maak `/products/[id]` route
|
||||||
|
2. Toon product ID op de pagina
|
||||||
|
3. Maak links naar `/products/1`, `/products/2`, `/products/3`
|
||||||
|
4. Test: alle links werken
|
||||||
|
|
||||||
|
**Bonus:** Voeg `loading.tsx` toe aan products folder
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkend prototype (kan simpel zijn)
|
- Werkende Next.js app met 4+ pagina's
|
||||||
- `docs/PROTOTYPE-LOG.md` met je proces
|
- Navigatie met Link component
|
||||||
- Screenshot van werkend prototype
|
- Dynamic route die werkt
|
||||||
|
- Deploy naar Vercel
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Verbeter en Reflecteer
|
### Uitbreiden en Verdiepen
|
||||||
|
|
||||||
**Deel 1: Prototype Verbeteren (1 uur)**
|
**Deel 1: Nested Layout (45 min)**
|
||||||
|
|
||||||
1. Fix eventuele bugs
|
1. Maak `/dashboard` section met eigen layout
|
||||||
2. Voeg 1 extra feature toe
|
2. Dashboard layout heeft sidebar
|
||||||
3. Verbeter styling
|
3. Maak `/dashboard/settings` en `/dashboard/profile` pagina's
|
||||||
4. Handle 1 edge case
|
4. Test: sidebar blijft bij navigatie binnen dashboard
|
||||||
|
|
||||||
**Deel 2: Peer Review (30 min)**
|
**Deel 2: Special Files (45 min)**
|
||||||
|
|
||||||
- Deel je prototype met een klasgenoot
|
1. Maak `loading.tsx` voor products (toon "Laden...")
|
||||||
- Krijg feedback
|
2. Maak `error.tsx` voor products (toon error message)
|
||||||
- Geef feedback op hun prototype
|
3. Maak `not-found.tsx` in app root (custom 404)
|
||||||
|
4. Test elk van deze states
|
||||||
|
|
||||||
**Deel 3: Reflectie (30 min)**
|
**Deel 3: Metadata (30 min)**
|
||||||
|
|
||||||
Schrijf "Lessons Learned" document (300 woorden):
|
1. Voeg metadata toe aan elke pagina (title, description)
|
||||||
- Wat ging goed in je workflow?
|
2. Bekijk in browser: `<head>` toont juiste meta tags
|
||||||
- Waar liep je vast?
|
3. Test met Lighthouse: SEO score
|
||||||
- Welke tool was het meest nuttig?
|
|
||||||
- Wat doe je volgende keer anders?
|
|
||||||
- Hoe voelde het om met AI te bouwen vs alleen?
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Verbeterd prototype
|
- App met nested layouts
|
||||||
- Peer review feedback (gegeven en ontvangen)
|
- Special files (loading, error, not-found)
|
||||||
- Lessons Learned document (300 woorden)
|
- Metadata op elke pagina
|
||||||
|
- Screenshot van Lighthouse SEO score
|
||||||
---
|
|
||||||
|
|
||||||
## Voorbereiding Les 7
|
|
||||||
|
|
||||||
In Les 7 gaan we echt bouwen met Next.js. Zorg dat je klaar bent:
|
|
||||||
- Node.js geïnstalleerd (versie 18+)
|
|
||||||
- Git geconfigureerd
|
|
||||||
- GitHub account aangemaakt
|
|
||||||
- OpenCode/WebStorm werkt
|
|
||||||
|
|
||||||
Test: run `node --version` in je terminal. Je zou v18 of hoger moeten zien.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Van een vaag idee naar concrete features gaan
|
- Uitleggen wat Next.js toevoegt aan React
|
||||||
- AI gebruiken voor feature breakdown
|
- Het verschil tussen SSR en CSR beschrijven
|
||||||
- MVP denken toepassen (essentieel vs nice-to-have)
|
- Een Next.js project opzetten met App Router
|
||||||
- Een app opdelen in components
|
- Pagina's maken met file-based routing
|
||||||
- De complete workflow doorlopen (idee → prototype)
|
- Layouts gebruiken voor herhalende elementen
|
||||||
- Het bouwproces documenteren
|
- Dynamic routes maken met parameters
|
||||||
- Reflecteren op wat werkt en wat niet
|
- Link component gebruiken voor navigatie
|
||||||
|
- Special files toepassen (loading, error, not-found)
|
||||||
|
- Metadata toevoegen voor SEO
|
||||||
|
|||||||
@@ -1,349 +1,412 @@
|
|||||||
# Les 7: Backend Basics met Supabase
|
# Les 7: Next.js Fundamentals 2 - API Routes & Data Fetching
|
||||||
|
|
||||||
> 📋 **Lesmateriaal nog niet uitgewerkt**
|
|
||||||
>
|
|
||||||
> De volgende bestanden worden gegenereerd wanneer deze les wordt uitgewerkt:
|
|
||||||
> - Les07-Slide-Overzicht.md
|
|
||||||
> - Les07-Lesplan.md
|
|
||||||
> - Les07-Bijlage-A-Lesopdracht.md
|
|
||||||
> - Les07-Bijlage-B-Huiswerkopdracht.md
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 2: Technical Foundations** (Les 5-9)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Zet je eerste "echte" Next.js project op en koppel het aan Supabase voor database en authenticatie. Je leert de complete flow van lokaal ontwikkelen tot productie deployment.
|
Leer data fetching in Next.js: Server Components, Client Components, API routes en React Query. Bouw een volledig werkende app met data.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Stap 1: Next.js Project Aanmaken
|
### Server Components vs Client Components
|
||||||
|
|
||||||
Dit is de eerste keer dat je een volledig Next.js project opzet.
|
**Server Components (default in Next.js):**
|
||||||
|
- Renderen op de server
|
||||||
|
- Geen JavaScript naar de browser
|
||||||
|
- Kunnen direct data fetchen (async/await)
|
||||||
|
- Kunnen NIET: useState, useEffect, event handlers
|
||||||
|
|
||||||
```bash
|
**Client Components:**
|
||||||
# Maak nieuw project
|
- Renderen in de browser
|
||||||
npx create-next-app@latest todo-app
|
- JavaScript naar de browser
|
||||||
|
- Kunnen interactief zijn
|
||||||
|
- Markeer met `'use client'` bovenaan
|
||||||
|
|
||||||
# Beantwoord de vragen:
|
---
|
||||||
# ✔ Would you like to use TypeScript? → Yes
|
|
||||||
# ✔ Would you like to use ESLint? → Yes
|
|
||||||
# ✔ Would you like to use Tailwind CSS? → Yes
|
|
||||||
# ✔ Would you like to use `src/` directory? → Yes
|
|
||||||
# ✔ Would you like to use App Router? → Yes
|
|
||||||
# ✔ Would you like to customize the default import alias? → No
|
|
||||||
|
|
||||||
# Ga naar project folder
|
### Wanneer Wat?
|
||||||
cd todo-app
|
|
||||||
|
|
||||||
# Open in je editor
|
|
||||||
code . # of: cursor .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 2: Project Structuur Begrijpen
|
|
||||||
|
|
||||||
```
|
```
|
||||||
todo-app/
|
Server Component → Data tonen, geen interactie
|
||||||
├── src/
|
Client Component → Interactie nodig (forms, buttons, state)
|
||||||
│ └── app/
|
|
||||||
│ ├── layout.tsx # Root layout (header, footer)
|
|
||||||
│ ├── page.tsx # Homepage (/)
|
|
||||||
│ └── globals.css # Global styles + Tailwind
|
|
||||||
├── public/ # Static files (images, etc.)
|
|
||||||
├── .env.local # Environment variables (maak zelf aan)
|
|
||||||
├── next.config.js # Next.js configuratie
|
|
||||||
├── tailwind.config.ts # Tailwind configuratie
|
|
||||||
├── package.json # Dependencies
|
|
||||||
└── tsconfig.json # TypeScript configuratie
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Stap 3: Lokaal Draaien
|
**Voorbeeld:**
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start development server
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# Open browser: http://localhost:3000
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 4: Supabase Project Aanmaken
|
|
||||||
|
|
||||||
**Op supabase.com:**
|
|
||||||
|
|
||||||
1. Ga naar [supabase.com](https://supabase.com) en maak account (gratis)
|
|
||||||
2. Klik "New Project"
|
|
||||||
3. Kies een naam (bijv. `todo-app`)
|
|
||||||
4. Kies een database wachtwoord (bewaar deze!)
|
|
||||||
5. Kies region: `West EU (Frankfurt)` (dichtst bij NL)
|
|
||||||
6. Wacht ~2 minuten tot project klaar is
|
|
||||||
|
|
||||||
**Credentials ophalen:**
|
|
||||||
|
|
||||||
1. Ga naar Settings → API
|
|
||||||
2. Kopieer:
|
|
||||||
- `Project URL` → dit wordt `NEXT_PUBLIC_SUPABASE_URL`
|
|
||||||
- `anon public` key → dit wordt `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
|
||||||
|
|
||||||
### Stap 5: Environment Variables (Lokaal)
|
|
||||||
|
|
||||||
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` (deze WEL committen):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# .env.example (template voor anderen)
|
|
||||||
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
||||||
```
|
|
||||||
|
|
||||||
**Check .gitignore:**
|
|
||||||
```
|
|
||||||
# .gitignore moet bevatten:
|
|
||||||
.env*.local
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 6: Supabase SDK Installeren
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install @supabase/supabase-js
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 7: Supabase Client Maken
|
|
||||||
|
|
||||||
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)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 8: Database Tabel Maken (via UI)
|
|
||||||
|
|
||||||
**In Supabase Dashboard:**
|
|
||||||
|
|
||||||
1. Ga naar Table Editor
|
|
||||||
2. Klik "New Table"
|
|
||||||
3. Naam: `todos`
|
|
||||||
4. Kolommen:
|
|
||||||
| Name | Type | Default | Primary |
|
|
||||||
|------|------|---------|---------|
|
|
||||||
| id | int8 | - | ✓ (auto) |
|
|
||||||
| title | text | - | |
|
|
||||||
| completed | bool | false | |
|
|
||||||
| created_at | timestamptz | now() | |
|
|
||||||
| user_id | uuid | auth.uid() | |
|
|
||||||
|
|
||||||
5. Klik "Save"
|
|
||||||
|
|
||||||
### Stap 9: CRUD Operaties
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// CREATE - nieuwe todo toevoegen
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('todos')
|
|
||||||
.insert({ title: 'Nieuwe taak' })
|
|
||||||
|
|
||||||
// READ - todos ophalen
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('todos')
|
|
||||||
.select('*')
|
|
||||||
.order('created_at', { ascending: false })
|
|
||||||
|
|
||||||
// UPDATE - todo afvinken
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('todos')
|
|
||||||
.update({ completed: true })
|
|
||||||
.eq('id', todoId)
|
|
||||||
|
|
||||||
// DELETE - todo verwijderen
|
|
||||||
const { error } = await supabase
|
|
||||||
.from('todos')
|
|
||||||
.delete()
|
|
||||||
.eq('id', todoId)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Stap 10: Authenticatie Setup
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install @supabase/auth-ui-react @supabase/auth-ui-shared
|
|
||||||
```
|
|
||||||
|
|
||||||
**Login component:**
|
|
||||||
```tsx
|
```tsx
|
||||||
import { Auth } from '@supabase/auth-ui-react'
|
// Server Component - data ophalen
|
||||||
import { ThemeSupa } from '@supabase/auth-ui-shared'
|
async function ProductList() {
|
||||||
import { supabase } from '@/lib/supabase'
|
const products = await fetchProducts() // Direct fetchen!
|
||||||
|
return <ul>{products.map(p => <li>{p.name}</li>)}</ul>
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client Component - interactie
|
||||||
|
'use client'
|
||||||
|
function AddToCartButton({ productId }) {
|
||||||
|
const [added, setAdded] = useState(false)
|
||||||
|
return <button onClick={() => setAdded(true)}>Add</button>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Data Fetching in Server Components
|
||||||
|
|
||||||
|
Simpelweg `async/await` gebruiken:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// app/products/page.tsx
|
||||||
|
interface Product {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getProducts(): Promise<Product[]> {
|
||||||
|
const res = await fetch('https://api.example.com/products')
|
||||||
|
return res.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ProductsPage() {
|
||||||
|
const products = await getProducts()
|
||||||
|
|
||||||
export function LoginForm() {
|
|
||||||
return (
|
return (
|
||||||
<Auth
|
<div>
|
||||||
supabaseClient={supabase}
|
<h1>Producten</h1>
|
||||||
appearance={{ theme: ThemeSupa }}
|
<ul>
|
||||||
providers={[]}
|
{products.map(product => (
|
||||||
magicLink={true}
|
<li key={product.id}>
|
||||||
/>
|
{product.name} - €{product.price}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Session checken:**
|
---
|
||||||
```typescript
|
|
||||||
const { data: { user } } = await supabase.auth.getUser()
|
|
||||||
|
|
||||||
if (user) {
|
### API Routes (Route Handlers)
|
||||||
// User is ingelogd
|
|
||||||
} else {
|
Bouw je eigen API in Next.js:
|
||||||
// Redirect naar login
|
|
||||||
|
**Folder structuur:**
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
└── api/
|
||||||
|
└── products/
|
||||||
|
└── route.ts → /api/products
|
||||||
|
```
|
||||||
|
|
||||||
|
**GET request (`app/api/products/route.ts`):**
|
||||||
|
```typescript
|
||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
const products = [
|
||||||
|
{ id: 1, name: 'Laptop', price: 999 },
|
||||||
|
{ id: 2, name: 'Phone', price: 699 },
|
||||||
|
]
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
return NextResponse.json(products)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**POST request:**
|
||||||
|
```typescript
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
const body = await request.json()
|
||||||
|
|
||||||
|
const newProduct = {
|
||||||
|
id: Date.now(),
|
||||||
|
name: body.name,
|
||||||
|
price: body.price,
|
||||||
|
}
|
||||||
|
|
||||||
|
products.push(newProduct)
|
||||||
|
|
||||||
|
return NextResponse.json(newProduct, { status: 201 })
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Deployment naar Vercel (Productie)
|
### 'use client' Directive
|
||||||
|
|
||||||
### Stap 1: GitHub Repository
|
Wanneer je interactie nodig hebt:
|
||||||
|
|
||||||
```bash
|
```tsx
|
||||||
# In je project folder
|
'use client' // MOET bovenaan!
|
||||||
git init
|
|
||||||
git add .
|
|
||||||
git commit -m "Initial commit"
|
|
||||||
|
|
||||||
# Maak repo op GitHub, dan:
|
import { useState } from 'react'
|
||||||
git remote add origin https://github.com/jouw-username/todo-app.git
|
|
||||||
git push -u origin main
|
export function Counter() {
|
||||||
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button onClick={() => setCount(count + 1)}>
|
||||||
|
Count: {count}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Stap 2: Vercel Deployment
|
|
||||||
|
|
||||||
1. Ga naar [vercel.com](https://vercel.com)
|
|
||||||
2. "Add New Project"
|
|
||||||
3. Import je GitHub repository
|
|
||||||
4. **BELANGRIJK:** Voeg Environment Variables toe:
|
|
||||||
- `NEXT_PUBLIC_SUPABASE_URL` → je Supabase URL
|
|
||||||
- `NEXT_PUBLIC_SUPABASE_ANON_KEY` → je anon key
|
|
||||||
5. Klik "Deploy"
|
|
||||||
|
|
||||||
### Stap 3: Supabase URL Toestaan
|
|
||||||
|
|
||||||
In Supabase Dashboard:
|
|
||||||
1. Ga naar Authentication → URL Configuration
|
|
||||||
2. Voeg je Vercel URL toe aan "Redirect URLs":
|
|
||||||
- `https://jouw-app.vercel.app/**`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overzicht: Lokaal vs Productie
|
### React Query (TanStack Query)
|
||||||
|
|
||||||
| Aspect | Lokaal | Productie |
|
**Waarom React Query?**
|
||||||
|--------|--------|-----------|
|
- Automatische caching
|
||||||
| URL | `localhost:3000` | `jouw-app.vercel.app` |
|
- Loading en error states
|
||||||
| Env vars | `.env.local` | Vercel Dashboard |
|
- Refetching (focus, interval)
|
||||||
| Database | Supabase (zelfde) | Supabase (zelfde) |
|
- Optimistic updates
|
||||||
| Command | `npm run dev` | Automatisch via Vercel |
|
|
||||||
|
|
||||||
**Let op:** Je gebruikt dezelfde Supabase database voor lokaal en productie. Voor een echt project zou je aparte databases hebben, maar voor deze cursus is dat niet nodig.
|
**Installatie:**
|
||||||
|
```bash
|
||||||
|
npm install @tanstack/react-query
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setup Provider (`app/providers.tsx`):**
|
||||||
|
```tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
export function Providers({ children }: { children: React.ReactNode }) {
|
||||||
|
const [queryClient] = useState(() => new QueryClient())
|
||||||
|
|
||||||
|
return (
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
{children}
|
||||||
|
</QueryClientProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**In Layout:**
|
||||||
|
```tsx
|
||||||
|
import { Providers } from './providers'
|
||||||
|
|
||||||
|
export default function RootLayout({ children }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<Providers>{children}</Providers>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### useQuery - Data Ophalen
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useQuery } from '@tanstack/react-query'
|
||||||
|
|
||||||
|
interface Product {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchProducts(): Promise<Product[]> {
|
||||||
|
const res = await fetch('/api/products')
|
||||||
|
return res.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProductList() {
|
||||||
|
const { data, isLoading, error } = useQuery({
|
||||||
|
queryKey: ['products'],
|
||||||
|
queryFn: fetchProducts,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isLoading) return <div>Laden...</div>
|
||||||
|
if (error) return <div>Error: {error.message}</div>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{data?.map(product => (
|
||||||
|
<li key={product.id}>{product.name}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### useMutation - Data Wijzigen
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||||
|
|
||||||
|
interface NewProduct {
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createProduct(product: NewProduct) {
|
||||||
|
const res = await fetch('/api/products', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(product),
|
||||||
|
})
|
||||||
|
return res.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AddProductForm() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const mutation = useMutation({
|
||||||
|
mutationFn: createProduct,
|
||||||
|
onSuccess: () => {
|
||||||
|
// Invalidate and refetch
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['products'] })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
mutation.mutate({ name: 'New Product', price: 99 })
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<button type="submit" disabled={mutation.isPending}>
|
||||||
|
{mutation.isPending ? 'Toevoegen...' : 'Voeg toe'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Combineren: Server + Client
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// app/products/page.tsx (Server Component)
|
||||||
|
import { ProductList } from './product-list'
|
||||||
|
import { AddProductForm } from './add-product-form'
|
||||||
|
|
||||||
|
export default function ProductsPage() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Producten</h1>
|
||||||
|
<AddProductForm /> {/* Client Component */}
|
||||||
|
<ProductList /> {/* Client Component */}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Next.js
|
- Next.js 14
|
||||||
- Supabase (gratis tier)
|
- React Query (TanStack Query)
|
||||||
- Vercel (gratis tier)
|
- TypeScript
|
||||||
- Cursor/OpenCode
|
- OpenCode/WebStorm
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Bouw een Todo App met Supabase
|
### Bouw CRUD App met API Routes
|
||||||
|
|
||||||
**Deel 1: Project Setup (30 min)**
|
**Deel 1: API Routes (40 min)**
|
||||||
- Run `npx create-next-app@latest todo-app` met juiste opties
|
|
||||||
- Maak Supabase account en project aan
|
|
||||||
- Configureer `.env.local` met credentials
|
|
||||||
- Installeer `@supabase/supabase-js`
|
|
||||||
- Maak `src/lib/supabase.ts`
|
|
||||||
- Test: `npm run dev` werkt zonder errors
|
|
||||||
|
|
||||||
**Deel 2: Database (20 min)**
|
1. Maak `app/api/products/route.ts`
|
||||||
- Maak `todos` tabel via Supabase Table Editor
|
2. Implementeer GET (alle producten)
|
||||||
- Voeg 3 test todos toe via de UI
|
3. Implementeer POST (product toevoegen)
|
||||||
- Test: data is zichtbaar in Table Editor
|
4. Test met browser/Postman: `/api/products`
|
||||||
|
|
||||||
**Deel 3: CRUD Interface (50 min)**
|
**Deel 2: React Query Setup (20 min)**
|
||||||
- Bouw UI om todos te tonen (lijst)
|
|
||||||
- Voeg form toe om nieuwe todo te maken
|
|
||||||
- Voeg checkbox toe om todo af te vinken
|
|
||||||
- Voeg delete button toe
|
|
||||||
- Test: alle CRUD operaties werken
|
|
||||||
|
|
||||||
**Deel 4: Authenticatie (20 min)**
|
1. Installeer `@tanstack/react-query`
|
||||||
- Installeer auth packages
|
2. Maak `app/providers.tsx`
|
||||||
- Maak login pagina met Auth UI
|
3. Wrap app in `QueryClientProvider`
|
||||||
- Toon alleen todos voor ingelogde user
|
|
||||||
- Test: login met magic link werkt
|
**Deel 3: Data Tonen met useQuery (30 min)**
|
||||||
|
|
||||||
|
1. Maak `ProductList` Client Component
|
||||||
|
2. Gebruik `useQuery` om data te fetchen
|
||||||
|
3. Toon loading state
|
||||||
|
4. Toon error state
|
||||||
|
5. Render product lijst
|
||||||
|
|
||||||
|
**Deel 4: Data Toevoegen met useMutation (30 min)**
|
||||||
|
|
||||||
|
1. Maak `AddProductForm` Client Component
|
||||||
|
2. Gebruik `useMutation` voor POST
|
||||||
|
3. Invalidate query na success
|
||||||
|
4. Toon "Adding..." state
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende Todo app lokaal
|
- Werkende API routes (GET, POST)
|
||||||
- GitHub repository met code
|
- ProductList met useQuery
|
||||||
- Screenshot van werkende app
|
- AddProductForm met useMutation
|
||||||
|
- Loading en error states
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Deploy naar Productie + Uitbreiden
|
### Volledige CRUD Interface
|
||||||
|
|
||||||
**Deel 1: Deployment (30 min)**
|
**Deel 1: PUT en DELETE Routes (45 min)**
|
||||||
- Push code naar GitHub
|
|
||||||
- Deploy naar Vercel
|
|
||||||
- Configureer environment variables in Vercel
|
|
||||||
- Voeg Vercel URL toe aan Supabase Redirect URLs
|
|
||||||
- Test: app werkt op productie URL
|
|
||||||
|
|
||||||
**Deel 2: Features Uitbreiden (1 uur)**
|
1. Maak `app/api/products/[id]/route.ts`
|
||||||
- Filter buttons: Alle / Actief / Voltooid
|
2. Implementeer PUT (update product)
|
||||||
- Sorteer op datum (nieuwste eerst)
|
3. Implementeer DELETE (verwijder product)
|
||||||
- Toon alleen todos van ingelogde user (filter op `user_id`)
|
4. Test beide endpoints
|
||||||
- Loading state tijdens data ophalen
|
|
||||||
- Error state bij problemen
|
|
||||||
- Empty state: "Geen todos gevonden"
|
|
||||||
|
|
||||||
**Deel 3: Polish (30 min)**
|
**Deel 2: Update Functionaliteit (45 min)**
|
||||||
- Styling verbeteren met Tailwind
|
|
||||||
- Responsive design (mobile friendly)
|
1. Maak edit form in ProductList
|
||||||
- Kleine animaties (fade in/out)
|
2. Gebruik useMutation voor PUT
|
||||||
|
3. Inline editing OF modal
|
||||||
|
4. Invalidate query na success
|
||||||
|
|
||||||
|
**Deel 3: Delete Functionaliteit (30 min)**
|
||||||
|
|
||||||
|
1. Voeg delete button toe per product
|
||||||
|
2. Gebruik useMutation voor DELETE
|
||||||
|
3. Voeg confirmation dialog toe
|
||||||
|
4. Invalidate query na success
|
||||||
|
|
||||||
|
**Bonus:** Optimistic Updates
|
||||||
|
- Product direct uit UI verwijderen
|
||||||
|
- Rollback als server faalt
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Deployed app op Vercel (werkende URL)
|
- Complete CRUD API (GET, POST, PUT, DELETE)
|
||||||
- Alle features werken in productie
|
- UI voor alle operaties
|
||||||
- Screenshot van productie app
|
- Error handling
|
||||||
|
- Optimistic updates (bonus)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een Next.js project opzetten met `npx create-next-app`
|
- Uitleggen wanneer Server vs Client Components
|
||||||
- De project structuur begrijpen en navigeren
|
- De 'use client' directive correct gebruiken
|
||||||
- Een Supabase project aanmaken en configureren
|
- Data fetchen in Server Components met async/await
|
||||||
- Environment variables correct beheren (lokaal en productie)
|
- API routes maken met Route Handlers
|
||||||
- De Supabase client installeren en configureren
|
- GET en POST requests implementeren
|
||||||
- Tabellen maken via de Supabase UI
|
- React Query installeren en configureren
|
||||||
- CRUD operaties uitvoeren met de Supabase SDK
|
- useQuery gebruiken voor data fetching
|
||||||
- Authenticatie implementeren met Auth UI
|
- useMutation gebruiken voor data mutations
|
||||||
- Deployen naar Vercel met environment variables
|
- Loading en error states afhandelen
|
||||||
- Het verschil tussen lokale en productie omgeving begrijpen
|
- Query invalidation toepassen
|
||||||
|
|||||||
@@ -1,320 +1,372 @@
|
|||||||
# Les 8: Supabase Basics
|
# Les 8: Database Principles
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 2: Technical Foundations** (Les 5-9)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Leer werken met Supabase: een complete backend-as-a-service met database en authenticatie. Je bouwt je eerste full-stack app met data die persistent is.
|
Leer de basisprincipes van relationele databases voordat we Supabase gaan gebruiken. Begrijp tabellen, relaties, keys en normalisatie - essentiële kennis voor elke developer.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Wat is Supabase?
|
### Wat is een Relationele Database?
|
||||||
|
|
||||||
**Supabase = Database + Auth in één**
|
**Een database is:** Een georganiseerde verzameling van data.
|
||||||
- PostgreSQL database (gratis tier: 500MB)
|
|
||||||
- Ingebouwde authenticatie
|
|
||||||
- Real-time subscriptions
|
|
||||||
- File storage
|
|
||||||
- Auto-generated API
|
|
||||||
|
|
||||||
**Waarom Supabase voor beginners:**
|
**Relationeel betekent:** Data is opgeslagen in tabellen die aan elkaar gerelateerd zijn.
|
||||||
- Geen eigen server nodig
|
|
||||||
- Visuele Table Editor (geen SQL kennis nodig)
|
**Vergelijk het met Excel:**
|
||||||
- Simpele JavaScript SDK
|
- Database = Excel workbook
|
||||||
- Gratis tier is ruim voldoende
|
- Tabel = Excel sheet
|
||||||
|
- Kolom = Excel kolom (field)
|
||||||
|
- Rij = Excel rij (record)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Supabase Project Aanmaken
|
### Tabellen, Kolommen en Rijen
|
||||||
|
|
||||||
**Stap 1:** Ga naar [supabase.com](https://supabase.com) en maak account
|
**Voorbeeld: Users tabel**
|
||||||
|
|
||||||
**Stap 2:** Klik "New Project"
|
| id | name | email | created_at |
|
||||||
- Naam: `todo-app`
|
|----|------|-------|------------|
|
||||||
- Database Password: (bewaar deze!)
|
| 1 | Tim | tim@email.com | 2024-01-15 |
|
||||||
- Region: `West EU (Frankfurt)` (dichtst bij NL)
|
| 2 | Anna | anna@email.com | 2024-01-16 |
|
||||||
|
| 3 | Jan | jan@email.com | 2024-01-17 |
|
||||||
|
|
||||||
**Stap 3:** Wacht ~2 minuten tot project klaar is
|
**Terminologie:**
|
||||||
|
- **Tabel:** users
|
||||||
**Stap 4:** Ga naar Settings → API en kopieer:
|
- **Kolommen:** id, name, email, created_at
|
||||||
- `Project URL`
|
- **Rijen:** 3 records (Tim, Anna, Jan)
|
||||||
- `anon public` key
|
- **Cell:** Eén specifieke waarde (bijv. "tim@email.com")
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Tabel Maken via Table Editor
|
### Data Types
|
||||||
|
|
||||||
**In Supabase Dashboard:**
|
Elke kolom heeft een type:
|
||||||
|
|
||||||
1. Ga naar "Table Editor"
|
| Type | Beschrijving | Voorbeeld |
|
||||||
2. Klik "New Table"
|
|------|--------------|-----------|
|
||||||
3. Naam: `todos`
|
| `text` / `varchar` | Tekst | "Tim", "Hello world" |
|
||||||
4. Kolommen:
|
| `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-... |
|
||||||
|
|
||||||
| Name | Type | Default | Primary |
|
**Kies het juiste type:**
|
||||||
|------|------|---------|---------|
|
- Prijs? → `decimal` (niet `integer`, want centen)
|
||||||
| id | int8 | - | ✓ (auto) |
|
- Is actief? → `boolean`
|
||||||
| title | text | - | |
|
- Naam? → `text`
|
||||||
| completed | bool | false | |
|
- Aantal? → `integer`
|
||||||
| created_at | timestamptz | now() | |
|
|
||||||
|
|
||||||
5. Klik "Save"
|
|
||||||
|
|
||||||
**Test:** Voeg een paar rijen toe via de UI om te zien dat het werkt.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Environment Variables
|
### Primary Keys
|
||||||
|
|
||||||
**Wat zijn environment variables?**
|
**Wat:** Een kolom die elke rij UNIEK identificeert.
|
||||||
- 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:**
|
**Regels:**
|
||||||
```bash
|
- Moet uniek zijn per rij
|
||||||
# .env.local - NOOIT committen naar Git!
|
- Mag nooit NULL zijn
|
||||||
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
|
- Verandert nooit
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
|
|
||||||
|
**Voorbeeld:**
|
||||||
|
```
|
||||||
|
users
|
||||||
|
------
|
||||||
|
id (PRIMARY KEY) | name | email
|
||||||
|
1 | Tim | tim@email.com
|
||||||
|
2 | Anna | anna@email.com
|
||||||
```
|
```
|
||||||
|
|
||||||
**Maak ook `.env.example` (WEL committen):**
|
**Waarom niet `email` als primary key?**
|
||||||
```bash
|
- Emails kunnen veranderen
|
||||||
# .env.example - template voor anderen
|
- `id` is stabiel en snel
|
||||||
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
---
|
||||||
|
|
||||||
|
### 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
|
||||||
```
|
```
|
||||||
|
|
||||||
**Check `.gitignore` bevat:**
|
**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!
|
||||||
```
|
```
|
||||||
.env*.local
|
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)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Supabase SDK Installeren
|
### One-to-Many Voorbeeld
|
||||||
|
|
||||||
```bash
|
```
|
||||||
npm install @supabase/supabase-js
|
users posts
|
||||||
|
------ ------
|
||||||
|
id | name id | title | user_id
|
||||||
|
1 | Tim ←────────── 1 | "Blog 1" | 1
|
||||||
|
2 | Anna ←────┬───── 2 | "Blog 2" | 1
|
||||||
|
└───── 3 | "Tips" | 2
|
||||||
```
|
```
|
||||||
|
|
||||||
**Maak `src/lib/supabase.ts`:**
|
**Lees:** Tim heeft 2 posts, Anna heeft 1 post.
|
||||||
```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)
|
### 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
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### CRUD Operaties
|
### Database Schema Tekenen
|
||||||
|
|
||||||
**C - Create (toevoegen):**
|
**Tools:** draw.io, Excalidraw, pen en papier
|
||||||
```typescript
|
|
||||||
const { data, error } = await supabase
|
**Conventie:**
|
||||||
.from('todos')
|
```
|
||||||
.insert({ title: 'Nieuwe taak' })
|
┌──────────────┐ ┌──────────────┐
|
||||||
|
│ users │ │ posts │
|
||||||
|
├──────────────┤ ├──────────────┤
|
||||||
|
│ id (PK) │───┐ │ id (PK) │
|
||||||
|
│ name │ │ │ title │
|
||||||
|
│ email │ └────→│ user_id (FK) │
|
||||||
|
│ created_at │ │ content │
|
||||||
|
└──────────────┘ │ created_at │
|
||||||
|
└──────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
**R - Read (ophalen):**
|
PK = Primary Key
|
||||||
```typescript
|
FK = Foreign Key
|
||||||
const { data, error } = await supabase
|
Pijl = Relatie richting
|
||||||
.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/**`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Lokaal vs Productie
|
|
||||||
|
|
||||||
| Aspect | Lokaal | Productie |
|
|
||||||
|--------|--------|-----------|
|
|
||||||
| URL | `localhost:3000` | `jouw-app.vercel.app` |
|
|
||||||
| Env vars | `.env.local` | Vercel Dashboard |
|
|
||||||
| Database | Supabase (zelfde) | Supabase (zelfde) |
|
|
||||||
| Command | `npm run dev` | Automatisch via Vercel |
|
|
||||||
|
|
||||||
**Let op:** Je gebruikt dezelfde Supabase database voor lokaal en productie. Voor echte projecten zou je aparte databases hebben.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Supabase
|
- Pen en papier / Excalidraw / draw.io
|
||||||
- Next.js
|
- Supabase Table Editor (vooruitblik)
|
||||||
- OpenCode/WebStorm
|
|
||||||
- Vercel
|
|
||||||
- Git
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Bouw een Todo App met Supabase
|
### Database Design Oefening
|
||||||
|
|
||||||
**Deel 1: Supabase Setup (30 min)**
|
**Deel 1: Blog Database Ontwerpen (45 min)**
|
||||||
|
|
||||||
1. Maak Supabase account en project
|
Ontwerp een database voor een blog met:
|
||||||
2. Maak `todos` tabel via Table Editor
|
- Users (kunnen posts schrijven)
|
||||||
3. Kopieer credentials
|
- Posts (hebben een auteur)
|
||||||
4. Installeer `@supabase/supabase-js`
|
- Comments (op posts, door users)
|
||||||
5. Maak `src/lib/supabase.ts`
|
|
||||||
6. Configureer `.env.local`
|
|
||||||
|
|
||||||
Test: `npm run dev` werkt zonder errors
|
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: CRUD Interface (1 uur)**
|
**Deel 2: Normalisatie Oefening (30 min)**
|
||||||
|
|
||||||
Bouw UI voor todos:
|
Gegeven deze "slechte" tabel:
|
||||||
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!
|
```
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
**Deel 3: Authenticatie (30 min)**
|
Normaliseer naar aparte tabellen:
|
||||||
|
1. Welke entiteiten zie je?
|
||||||
|
2. Maak aparte tabellen
|
||||||
|
3. Voeg relaties toe
|
||||||
|
|
||||||
1. Installeer auth packages
|
**Deel 3: Eindproject Schema (45 min)**
|
||||||
2. Maak login pagina met Auth UI
|
|
||||||
3. Toon alleen app voor ingelogde users
|
Ontwerp het database schema voor jouw eindproject:
|
||||||
4. Test: login met magic link
|
1. Welke entiteiten heb je nodig?
|
||||||
|
2. Teken elke tabel met kolommen
|
||||||
|
3. Bepaal relaties
|
||||||
|
4. Documenteer je keuzes
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende Todo app lokaal
|
- Blog database schema (tekening)
|
||||||
- GitHub repository met code
|
- Genormaliseerde library database
|
||||||
- Screenshot van werkende app
|
- Eindproject database schema
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Deploy naar Productie + Uitbreiden
|
### Verdieping en Voorbereiding
|
||||||
|
|
||||||
**Deel 1: Deployment (30 min)**
|
**Deel 1: Eindproject Schema Uitwerken (1 uur)**
|
||||||
|
|
||||||
1. Push naar GitHub
|
Werk je database schema volledig uit:
|
||||||
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)**
|
1. **Per tabel:**
|
||||||
|
- Naam
|
||||||
|
- Alle kolommen met data types
|
||||||
|
- Primary key
|
||||||
|
- Foreign keys
|
||||||
|
- Defaults
|
||||||
|
- Nullable fields
|
||||||
|
|
||||||
Voeg toe:
|
2. **Documenteer:**
|
||||||
1. Filter buttons: Alle / Actief / Voltooid
|
- Waarom deze structuur?
|
||||||
2. Sorteer op datum (nieuwste eerst)
|
- Welke relaties?
|
||||||
3. Loading state tijdens data ophalen
|
- Eventuele alternatieve overwegingen
|
||||||
4. Error state bij problemen
|
|
||||||
5. Empty state: "Geen todos gevonden"
|
|
||||||
|
|
||||||
**Deel 3: Polish (30 min)**
|
**Deel 2: Supabase Account (30 min)**
|
||||||
|
|
||||||
1. Styling verbeteren met Tailwind
|
Bereid je voor op volgende les:
|
||||||
2. Responsive design (mobile friendly)
|
1. Maak account op [supabase.com](https://supabase.com)
|
||||||
3. Kleine animaties (fade in/out)
|
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
|
### Deliverable
|
||||||
- Deployed app op Vercel (werkende URL!)
|
- Volledig uitgewerkt database schema voor eindproject
|
||||||
- Alle features werken in productie
|
- Supabase account aangemaakt
|
||||||
- Screenshot van productie app
|
- Reflectie vragen beantwoord
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een Supabase project aanmaken en configureren
|
- Uitleggen wat een relationele database is
|
||||||
- Tabellen maken via de Table Editor (zonder SQL)
|
- Tabellen, kolommen en rijen beschrijven
|
||||||
- Environment variables correct beheren
|
- De juiste data types kiezen
|
||||||
- De Supabase client installeren en configureren
|
- Primary keys en hun doel uitleggen
|
||||||
- CRUD operaties uitvoeren met de Supabase SDK
|
- Foreign keys en relaties begrijpen
|
||||||
- Authenticatie implementeren met Auth UI
|
- One-to-many en many-to-many relaties herkennen
|
||||||
- Deployen naar Vercel met environment variables
|
- Het probleem van data duplicatie identificeren
|
||||||
- Het verschil tussen lokale en productie omgeving begrijpen
|
- Een database normaliseren
|
||||||
|
- NULL values en defaults begrijpen
|
||||||
|
- Een database schema ontwerpen en tekenen
|
||||||
|
|||||||
@@ -1,302 +1,305 @@
|
|||||||
# Les 9: AI Agents - Custom GPTs & Claude Projects
|
# Les 9: Supabase Basics
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 2: Intermediate** (Les 4-9)
|
**Deel 2: Technical Foundations** (Les 5-9)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Leer werken met AI Agents: gepersonaliseerde AI assistenten die je kunt trainen op jouw specifieke taken en werkwijze.
|
Leer werken met Supabase: een complete backend-as-a-service met database en authenticatie. Pas je database schema uit Les 8 toe en bouw je eerste full-stack app.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Wat zijn AI Agents?
|
### Wat is Supabase?
|
||||||
|
|
||||||
**Chatbot vs Agent:**
|
**Supabase = Database + Auth in één**
|
||||||
|
- PostgreSQL database (gratis tier: 500MB)
|
||||||
|
- Ingebouwde authenticatie
|
||||||
|
- Real-time subscriptions
|
||||||
|
- File storage
|
||||||
|
- Auto-generated API
|
||||||
|
|
||||||
| Chatbot | Agent |
|
**Waarom Supabase voor beginners:**
|
||||||
|---------|-------|
|
- Geen eigen server nodig
|
||||||
| Reageert op vragen | Neemt initiatief |
|
- Visuele Table Editor (geen SQL kennis nodig)
|
||||||
| Geen geheugen | Onthoudt context |
|
- Simpele JavaScript SDK
|
||||||
| Algemene kennis | Specifieke expertise |
|
- Gratis tier is ruim voldoende
|
||||||
| Eenmalige interactie | Langere samenwerkingen |
|
|
||||||
|
|
||||||
**Agent = AI met:**
|
|
||||||
- Custom instructies (hoe moet hij zich gedragen)
|
|
||||||
- Eigen kennis (documenten, voorbeelden)
|
|
||||||
- Specifieke taken (waar is hij goed in)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Custom GPTs (ChatGPT)
|
### Supabase Project Aanmaken
|
||||||
|
|
||||||
**Wat is een Custom GPT?**
|
**Stap 1:** Ga naar [supabase.com](https://supabase.com) en maak account
|
||||||
Een gepersonaliseerde versie van ChatGPT voor specifieke taken.
|
|
||||||
|
|
||||||
**Onderdelen:**
|
**Stap 2:** Klik "New Project"
|
||||||
1. **Instructions:** Hoe moet de GPT zich gedragen?
|
- Naam: `todo-app`
|
||||||
2. **Conversation starters:** Voorbeeld prompts
|
- Database Password: (bewaar deze!)
|
||||||
3. **Knowledge:** Upload documenten als context
|
- Region: `West EU (Frankfurt)` (dichtst bij NL)
|
||||||
4. **Capabilities:** Web browsing, code interpreter, DALL-E
|
|
||||||
|
|
||||||
**Voorbeeld: Code Reviewer GPT**
|
**Stap 3:** Wacht ~2 minuten tot project klaar is
|
||||||
|
|
||||||
*Instructions:*
|
**Stap 4:** Ga naar Settings → API en kopieer:
|
||||||
|
- `Project URL`
|
||||||
|
- `anon public` key
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Je Database Schema Implementeren
|
||||||
|
|
||||||
|
In Les 8 heb je een database schema ontworpen. Nu gaan we dat implementeren!
|
||||||
|
|
||||||
|
**In Supabase Dashboard → Table Editor:**
|
||||||
|
|
||||||
|
1. Klik "New Table"
|
||||||
|
2. Gebruik je schema uit Les 8
|
||||||
|
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
|
||||||
```
|
```
|
||||||
Je bent een strenge code reviewer voor React/TypeScript projecten.
|
|
||||||
|
|
||||||
Bij elke code review check je:
|
**Maak ook `.env.example` (WEL committen):**
|
||||||
1. TypeScript types correct?
|
```bash
|
||||||
2. React best practices gevolgd?
|
# .env.example - template voor anderen
|
||||||
3. Geen hardcoded values?
|
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
||||||
4. Error handling aanwezig?
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||||
5. Accessibility (ARIA labels)?
|
|
||||||
|
|
||||||
Geef feedback in dit format:
|
|
||||||
- ✅ Goed: [wat is goed]
|
|
||||||
- ⚠️ Verbeter: [wat kan beter]
|
|
||||||
- ❌ Fix: [wat moet gefixed worden]
|
|
||||||
|
|
||||||
Wees streng maar constructief.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Claude Projects
|
### Supabase SDK Installeren
|
||||||
|
|
||||||
**Wat is een Claude Project?**
|
```bash
|
||||||
Een Claude-omgeving met custom context voor een specifiek project.
|
npm install @supabase/supabase-js
|
||||||
|
|
||||||
**Onderdelen:**
|
|
||||||
1. **Project Knowledge:** Upload relevante documenten
|
|
||||||
2. **Custom Instructions:** Hoe moet Claude zich gedragen
|
|
||||||
3. **Conversation History:** Context blijft bewaard
|
|
||||||
|
|
||||||
**Voordelen:**
|
|
||||||
- Langere context dan ChatGPT
|
|
||||||
- Betere nuance in antwoorden
|
|
||||||
- Artifacts voor code en documenten
|
|
||||||
|
|
||||||
**Voorbeeld: Project voor je Todo App**
|
|
||||||
|
|
||||||
*Custom Instructions:*
|
|
||||||
```
|
|
||||||
Dit is mijn Todo app project.
|
|
||||||
|
|
||||||
Tech stack:
|
|
||||||
- Next.js 14 met App Router
|
|
||||||
- TypeScript
|
|
||||||
- Tailwind CSS
|
|
||||||
- Supabase voor database en auth
|
|
||||||
|
|
||||||
Code conventies:
|
|
||||||
- Functional components
|
|
||||||
- Named exports
|
|
||||||
- Async/await (geen .then)
|
|
||||||
|
|
||||||
Als je code schrijft, volg altijd deze conventies.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
*Project Knowledge:*
|
**Maak `src/lib/supabase.ts`:**
|
||||||
- Upload je belangrijkste component files
|
```typescript
|
||||||
- Upload je Supabase schema
|
import { createClient } from '@supabase/supabase-js'
|
||||||
|
|
||||||
---
|
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
||||||
|
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||||
|
|
||||||
### Wanneer Welke Gebruiken?
|
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||||
|
|
||||||
| Situatie | Tool |
|
|
||||||
|----------|------|
|
|
||||||
| Snelle code review | Custom GPT |
|
|
||||||
| Werken aan specifiek project | Claude Project |
|
|
||||||
| Documentatie genereren | Custom GPT |
|
|
||||||
| Lange context nodig | Claude Project |
|
|
||||||
| Wil delen met anderen | Custom GPT |
|
|
||||||
| Privé project context | Claude Project |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Custom GPT Maken
|
|
||||||
|
|
||||||
**Stap 1:** Ga naar chat.openai.com → "Explore GPTs" → "Create"
|
|
||||||
|
|
||||||
**Stap 2:** Vul in:
|
|
||||||
- Naam: "React Code Reviewer"
|
|
||||||
- Beschrijving: "Reviews React/TypeScript code"
|
|
||||||
- Instructions: (zie voorbeeld hierboven)
|
|
||||||
|
|
||||||
**Stap 3:** Test met echte code
|
|
||||||
|
|
||||||
**Stap 4:** Itereer op instructions
|
|
||||||
- Wat mist hij?
|
|
||||||
- Wat doet hij verkeerd?
|
|
||||||
- Pas aan en test opnieuw
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Claude Project Maken
|
|
||||||
|
|
||||||
**Stap 1:** Ga naar claude.ai → "Projects" → "Create project"
|
|
||||||
|
|
||||||
**Stap 2:** Geef project een naam
|
|
||||||
|
|
||||||
**Stap 3:** Upload Project Knowledge
|
|
||||||
- Drag & drop je belangrijkste files
|
|
||||||
- Of kopieer/plak code snippets
|
|
||||||
|
|
||||||
**Stap 4:** Schrijf Custom Instructions
|
|
||||||
- Beschrijf je tech stack
|
|
||||||
- Beschrijf je conventies
|
|
||||||
- Beschrijf wat je wilt dat Claude doet
|
|
||||||
|
|
||||||
**Stap 5:** Start chatten binnen het project
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Agent Instructions Schrijven
|
|
||||||
|
|
||||||
**Goede instructions bevatten:**
|
|
||||||
|
|
||||||
1. **Rol:** Wie is de agent?
|
|
||||||
```
|
|
||||||
Je bent een senior React developer die code reviewt.
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Context:** Wat is de situatie?
|
|
||||||
```
|
|
||||||
Je reviewt code voor een startup met strakke deadlines.
|
|
||||||
Focus op kritieke issues, niet op style preferences.
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Gedrag:** Hoe moet hij reageren?
|
|
||||||
```
|
|
||||||
Wees direct maar vriendelijk.
|
|
||||||
Geef altijd een voorbeeld van de betere oplossing.
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Format:** Hoe moet output eruitzien?
|
|
||||||
```
|
|
||||||
Gebruik markdown formatting.
|
|
||||||
Groepeer feedback per categorie.
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Beperkingen:** Wat moet hij NIET doen?
|
|
||||||
```
|
|
||||||
Herschrijf niet de hele codebase.
|
|
||||||
Focus op de gevraagde code, niet op andere files.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Praktische Agent Ideeën
|
### CRUD Operaties
|
||||||
|
|
||||||
| Agent | Doel |
|
**C - Create (toevoegen):**
|
||||||
|-------|------|
|
```typescript
|
||||||
| **Code Reviewer** | Check code op bugs en best practices |
|
const { data, error } = await supabase
|
||||||
| **Doc Generator** | Genereer documentatie voor components |
|
.from('todos')
|
||||||
| **Bug Debugger** | Help bij error messages uitleggen |
|
.insert({ title: 'Nieuwe taak' })
|
||||||
| **Refactor Helper** | Suggesties voor code verbetering |
|
```
|
||||||
| **Test Writer** | Genereer unit tests |
|
|
||||||
| **Rubber Duck** | Denk hardop mee over problemen |
|
**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
|
||||||
- ChatGPT (Custom GPTs)
|
- Supabase
|
||||||
- Claude Desktop (Projects)
|
- Next.js
|
||||||
|
- OpenCode/WebStorm
|
||||||
|
- Vercel
|
||||||
|
- Git
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Bouw Je Eerste AI Agents
|
### Bouw een Todo App met Supabase
|
||||||
|
|
||||||
**Deel 1: Custom GPT - Code Reviewer (45 min)**
|
**Groepsdiscussie (15 min):**
|
||||||
|
Bespreek klassikaal de database schemas uit Les 8 - wie heeft welke structuur gekozen en waarom?
|
||||||
|
|
||||||
1. Ga naar ChatGPT → Create GPT
|
**Deel 1: Supabase Setup (30 min)**
|
||||||
2. Maak "Code Reviewer" met deze checklist:
|
|
||||||
- TypeScript types
|
|
||||||
- React best practices
|
|
||||||
- Error handling
|
|
||||||
- Accessibility
|
|
||||||
- Performance
|
|
||||||
3. Upload sample "goede" code als knowledge
|
|
||||||
4. Test met code uit je Todo app
|
|
||||||
5. Itereer op de instructions
|
|
||||||
|
|
||||||
**Deel 2: Claude Project - Todo App Context (45 min)**
|
1. Maak Supabase account en project
|
||||||
|
2. Maak je tabellen via Table Editor (gebaseerd op Les 8 schema)
|
||||||
|
3. Kopieer credentials
|
||||||
|
4. Installeer `@supabase/supabase-js`
|
||||||
|
5. Maak `src/lib/supabase.ts`
|
||||||
|
6. Configureer `.env.local`
|
||||||
|
|
||||||
1. Maak nieuw Claude Project
|
Test: `npm run dev` werkt zonder errors
|
||||||
2. Upload je Todo app files als knowledge
|
|
||||||
3. Schrijf custom instructions met je tech stack
|
|
||||||
4. Test: vraag Claude om een nieuwe feature te bouwen
|
|
||||||
5. Vergelijk: kent hij je project context?
|
|
||||||
|
|
||||||
**Deel 3: Vergelijking (30 min)**
|
**Deel 2: CRUD Interface (1 uur)**
|
||||||
|
|
||||||
Test dezelfde vraag in beide:
|
Bouw UI voor todos:
|
||||||
```
|
1. Lijst van todos tonen
|
||||||
Review deze code en geef verbeter suggesties:
|
2. Form om nieuwe todo toe te voegen
|
||||||
[plak je TodoList component]
|
3. Checkbox om todo af te vinken
|
||||||
```
|
4. Delete button per todo
|
||||||
|
|
||||||
Documenteer:
|
Gebruik AI hulp voor de components!
|
||||||
- Welke geeft betere feedback?
|
|
||||||
- Welke voelt meer "op maat"?
|
**Deel 3: Authenticatie (30 min)**
|
||||||
- Wanneer zou je welke gebruiken?
|
|
||||||
|
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
|
### Deliverable
|
||||||
- Werkende Custom GPT (link delen)
|
- Werkende Todo app lokaal
|
||||||
- Claude Project met project context
|
- GitHub repository met code
|
||||||
- Vergelijkings notities
|
- Screenshot van werkende app
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Personal Dev Assistant
|
### Deploy naar Productie + Uitbreiden
|
||||||
|
|
||||||
**Deel 1: Bouw Je Personal Assistant (1 uur)**
|
**Deel 1: Deployment (30 min)**
|
||||||
|
|
||||||
Maak een Custom GPT of Claude Project die:
|
1. Push naar GitHub
|
||||||
- Jouw coding standards kent
|
2. Deploy naar Vercel
|
||||||
- Jouw tech stack begrijpt
|
3. Configureer env vars in Vercel
|
||||||
- Jouw workflow ondersteunt
|
4. Voeg Vercel URL toe aan Supabase Redirect URLs
|
||||||
|
5. Test: app werkt op productie URL!
|
||||||
|
|
||||||
**Include in instructions:**
|
**Deel 2: Features Uitbreiden (1 uur)**
|
||||||
- Jouw voorkeuren (tabs vs spaces, etc.)
|
|
||||||
- Jouw tech stack details
|
|
||||||
- Typische taken die je doet
|
|
||||||
- Hoe je feedback wilt krijgen
|
|
||||||
|
|
||||||
**Deel 2: Test in Echt Werk (45 min)**
|
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"
|
||||||
|
|
||||||
Gebruik je assistant voor echte taken:
|
**Deel 3: Polish (30 min)**
|
||||||
1. Code review van een component
|
|
||||||
2. Help bij een bug
|
|
||||||
3. Genereer documentatie
|
|
||||||
|
|
||||||
**Deel 3: Reflectie (15 min)**
|
1. Styling verbeteren met Tailwind
|
||||||
|
2. Responsive design (mobile friendly)
|
||||||
Schrijf korte reflectie (300 woorden):
|
3. Kleine animaties (fade in/out)
|
||||||
- Hoe helpful was je agent?
|
|
||||||
- Wat zou je verbeteren?
|
|
||||||
- Ga je dit blijven gebruiken?
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Personal Dev Assistant (GPT link of Claude Project screenshot)
|
- Deployed app op Vercel (werkende URL!)
|
||||||
- 3 voorbeelden van gebruik
|
- Alle features werken in productie
|
||||||
- Reflectie (300 woorden)
|
- Screenshot van productie app
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Het verschil uitleggen tussen chatbots en AI agents
|
- Een Supabase project aanmaken en configureren
|
||||||
- Custom GPTs bouwen met instructions en knowledge base
|
- Database schema implementeren via Table Editor
|
||||||
- Claude Projects opzetten met custom instructions en context
|
- Environment variables correct beheren
|
||||||
- Effectieve agent instructions schrijven
|
- De Supabase client installeren en configureren
|
||||||
- De juiste tool kiezen (Custom GPT vs Claude Project)
|
- CRUD operaties uitvoeren met de Supabase SDK
|
||||||
- Een personal dev assistant maken voor eigen workflow
|
- Authenticatie implementeren met Auth UI
|
||||||
|
- Deployen naar Vercel met environment variables
|
||||||
|
- Database principles uit Les 8 toepassen in de praktijk
|
||||||
|
|||||||
@@ -1,278 +1,270 @@
|
|||||||
# Les 10: Introduction to Cursor
|
# Les 10: AI Tool Selection & Workflows
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 3: AI Tooling & Prototyping** (Les 10-12)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Kennismaking met Cursor - de professionele AI code editor. Leer de core features en ontdek waarom dit de tool is voor serieuze AI-assisted development.
|
Leer de sterke en zwakke punten van elke AI tool kennen. Ontwikkel een framework om de juiste tool te kiezen voor de juiste taak en bouw je eigen workflow.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Waarom Cursor?
|
### Waarom Tool Selection Belangrijk Is
|
||||||
|
|
||||||
**Tot nu toe gebruikten we:**
|
Je kent nu meerdere AI tools:
|
||||||
- OpenCode (gratis, goed voor leren)
|
- ChatGPT (brainstormen, planning, uitleg)
|
||||||
- Claude Desktop (voor agents en projects)
|
- Claude (lange context, nuance, analyse)
|
||||||
|
- v0.dev (UI prototyping)
|
||||||
|
- OpenCode (code schrijven met project context)
|
||||||
|
|
||||||
**Cursor is de volgende stap:**
|
**Het probleem:** Elke tool heeft sterke en zwakke punten. De juiste tool kiezen bespaart tijd en levert betere resultaten.
|
||||||
- Purpose-built voor AI-assisted coding
|
|
||||||
- Professionele editor (gebaseerd op VS Code)
|
|
||||||
- Superieure AI integratie
|
|
||||||
- Free tier beschikbaar (voldoende voor de cursus)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Free vs Pro
|
### Tool Vergelijking
|
||||||
|
|
||||||
| Aspect | Free Tier | Pro ($20/maand) |
|
| Tool | Sterk in | Minder sterk in | Kosten |
|
||||||
|--------|-----------|-----------------|
|
|------|----------|-----------------|--------|
|
||||||
| Tab completion | ✅ | ✅ |
|
| **ChatGPT** | Brainstormen, uitleg, planning, algemene kennis | Grote codebases, lange context | Gratis / Pro €20/maand |
|
||||||
| CMD+K edits | Beperkt | Onbeperkt |
|
| **Claude** | Lange documenten, nuance, analyse, veiligheid | Soms te voorzichtig, geen images genereren | Gratis / Pro $20/maand |
|
||||||
| Chat | Beperkt | Onbeperkt |
|
| **v0.dev** | UI components, snel prototypen, Tailwind | Complexe logica, backend | Gratis tier |
|
||||||
| Composer | Beperkt | Onbeperkt |
|
| **OpenCode** | Code schrijven, project context, terminal | Geen web access, geen images | Gratis |
|
||||||
| Models | GPT-4, Claude | Alle modellen |
|
|
||||||
|
|
||||||
**Voor deze cursus:** Free tier is voldoende!
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Installatie
|
### Tool Selection Framework
|
||||||
|
|
||||||
1. Ga naar [cursor.sh](https://cursor.sh)
|
**Stap 1: Identificeer de taak**
|
||||||
2. Download voor jouw OS
|
- Wat wil je bereiken?
|
||||||
3. Installeer
|
- Hoe complex is het?
|
||||||
4. Open Cursor
|
- Hoeveel context is nodig?
|
||||||
5. Sign in met GitHub
|
|
||||||
|
|
||||||
**Eerste keer:**
|
**Stap 2: Kies de juiste tool**
|
||||||
- Cursor vraagt om settings te importeren van VS Code (optioneel)
|
|
||||||
- Accept default keybindings
|
|
||||||
|
|
||||||
---
|
```
|
||||||
|
Als je wilt... Gebruik...
|
||||||
### Core Features
|
─────────────────────────────────────────────────
|
||||||
|
Brainstormen over een idee → ChatGPT
|
||||||
#### 1. Tab Completion
|
Een lange codebase analyseren → Claude
|
||||||
AI-powered autocomplete die hele blokken code voorspelt.
|
Snel een UI component maken → v0.dev
|
||||||
|
Code schrijven met project context → OpenCode
|
||||||
**Hoe het werkt:**
|
Een complex document begrijpen → Claude
|
||||||
- Begin met typen
|
Uitleg krijgen over een concept → ChatGPT
|
||||||
- Cursor suggereert code in grijs
|
React component met styling → v0.dev
|
||||||
- Druk Tab om te accepteren
|
Feature implementeren in project → OpenCode
|
||||||
- Druk Escape om te negeren
|
|
||||||
|
|
||||||
**Tip:** Schrijf een comment over wat je wilt, en Tab completion vult de code in.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Function that calculates the total price with tax
|
|
||||||
// [Tab completion vult de functie in]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2. CMD+K (Inline Editing)
|
---
|
||||||
Selecteer code en vraag AI om het aan te passen.
|
|
||||||
|
|
||||||
**Hoe het werkt:**
|
### Workflow Patterns
|
||||||
1. Selecteer code (of zet cursor op een regel)
|
|
||||||
2. Druk CMD+K (Mac) of Ctrl+K (Windows)
|
|
||||||
3. Typ je instructie
|
|
||||||
4. Enter om te genereren
|
|
||||||
5. Accept of Reject de wijziging
|
|
||||||
|
|
||||||
**Voorbeelden:**
|
**Pattern 1: Planning → Prototyping → Implementation**
|
||||||
- "Add error handling"
|
|
||||||
- "Convert to TypeScript"
|
|
||||||
- "Make this responsive"
|
|
||||||
- "Add loading state"
|
|
||||||
|
|
||||||
#### 3. Chat (Sidebar)
|
|
||||||
Converseer met AI over je code.
|
|
||||||
|
|
||||||
**Hoe het werkt:**
|
|
||||||
1. CMD+Shift+L opent Chat
|
|
||||||
2. Stel je vraag
|
|
||||||
3. AI heeft context van je open file
|
|
||||||
|
|
||||||
**Voorbeelden:**
|
|
||||||
- "Explain what this function does"
|
|
||||||
- "How can I optimize this?"
|
|
||||||
- "What's wrong with this code?"
|
|
||||||
|
|
||||||
#### 4. @ Mentions
|
|
||||||
Refereer naar files, folders, of documentatie.
|
|
||||||
|
|
||||||
**Syntax:**
|
|
||||||
- `@filename.tsx` - specifieke file
|
|
||||||
- `@folder/` - hele folder
|
|
||||||
- `@Docs` - officiële docs zoeken
|
|
||||||
- `@Web` - web zoeken
|
|
||||||
|
|
||||||
**Voorbeeld:**
|
|
||||||
```
|
```
|
||||||
@components/Button.tsx - How can I add a loading prop to this?
|
1. ChatGPT: Brainstorm features, maak planning
|
||||||
|
2. v0.dev: Genereer UI prototypes
|
||||||
|
3. OpenCode: Implementeer met project context
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5. Composer Mode
|
**Pattern 2: Research → Design → Build**
|
||||||
Multi-file generatie in één keer.
|
```
|
||||||
|
1. ChatGPT/Claude: Research beste aanpak
|
||||||
|
2. v0.dev: Design components
|
||||||
|
3. OpenCode: Bouw en integreer
|
||||||
|
```
|
||||||
|
|
||||||
**Hoe het werkt:**
|
**Pattern 3: Quick Iteration**
|
||||||
1. CMD+I opent Composer
|
```
|
||||||
2. Beschrijf wat je wilt bouwen
|
1. v0.dev: Snel component genereren
|
||||||
3. AI genereert meerdere files tegelijk
|
2. OpenCode: Aanpassen en integreren
|
||||||
4. Review en accept changes
|
3. Repeat
|
||||||
|
```
|
||||||
**Wanneer gebruiken:**
|
|
||||||
- Nieuwe features met meerdere components
|
|
||||||
- Refactoring over meerdere files
|
|
||||||
- Boilerplate code genereren
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Workflow Vergelijking
|
### Praktijk: Dezelfde Taak, Drie Tools
|
||||||
|
|
||||||
| Taak | OpenCode | Cursor |
|
**Opdracht:** Bouw een Contact Form component
|
||||||
|------|----------|--------|
|
|
||||||
| Snelle fix | Chat | CMD+K |
|
**Met ChatGPT:**
|
||||||
| Nieuwe component | Chat | Tab completion + CMD+K |
|
```
|
||||||
| Multi-file feature | Meerdere chats | Composer |
|
Prompt: Ik wil een contact form maken met React en Tailwind.
|
||||||
| Code uitleg | Chat | Chat + @ mentions |
|
Velden: naam, email, bericht. Validatie nodig.
|
||||||
| Refactoring | Chat | CMD+K of Composer |
|
Geef me de code en leg uit hoe het werkt.
|
||||||
|
```
|
||||||
|
→ Krijg: Uitleg + code, maar zonder project context
|
||||||
|
|
||||||
|
**Met v0.dev:**
|
||||||
|
```
|
||||||
|
Prompt: Modern contact form with name, email, message fields.
|
||||||
|
Tailwind styling, validation, responsive design.
|
||||||
|
```
|
||||||
|
→ Krijg: Visueel prototype, direct te gebruiken
|
||||||
|
|
||||||
|
**Met OpenCode:**
|
||||||
|
```
|
||||||
|
Prompt: Maak een ContactForm component in src/components/
|
||||||
|
met naam, email en bericht velden. Gebruik onze bestaande
|
||||||
|
Input en Button components. Voeg Zod validatie toe.
|
||||||
|
```
|
||||||
|
→ Krijg: Geïntegreerde code die past in je project
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Tips voor Beginners
|
### Wanneer Combineer Je Tools?
|
||||||
|
|
||||||
1. **Start met Tab completion**
|
**Scenario 1: Nieuwe feature bouwen**
|
||||||
- Gewoon typen en kijken wat er gebeurt
|
1. ChatGPT: "Hoe zou je een dark mode toggle implementeren in React?"
|
||||||
- Comments zijn je vriend
|
2. v0.dev: "Dark mode toggle component with smooth transition"
|
||||||
|
3. OpenCode: "Integreer deze toggle in onze navbar, sla preference op in localStorage"
|
||||||
|
|
||||||
2. **CMD+K voor snelle edits**
|
**Scenario 2: Bug oplossen**
|
||||||
- Selecteer precies wat je wilt aanpassen
|
1. OpenCode: Vraag om bug te identificeren
|
||||||
- Wees specifiek in je instructie
|
2. Claude: Als de foutmelding complex is, vraag om uitleg
|
||||||
|
3. OpenCode: Implementeer de fix
|
||||||
|
|
||||||
3. **Chat voor vragen**
|
**Scenario 3: Nieuwe technologie leren**
|
||||||
- Als je iets niet begrijpt
|
1. ChatGPT: "Leg uit hoe React Server Components werken"
|
||||||
- Als je opties wilt vergelijken
|
2. v0.dev: "Example of React Server Component with data fetching"
|
||||||
|
3. OpenCode: "Help me dit toe te passen in mijn Next.js project"
|
||||||
4. **@ mentions voor context**
|
|
||||||
- AI weet niet automatisch over andere files
|
|
||||||
- Voeg relevante files toe met @
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Keyboard Shortcuts Cheat Sheet
|
### Anti-Patterns (Wat Niet Te Doen)
|
||||||
|
|
||||||
| Actie | Mac | Windows |
|
**❌ Verkeerde tool voor de taak:**
|
||||||
|-------|-----|---------|
|
- ChatGPT vragen om een hele app te bouwen → te weinig context
|
||||||
| Tab completion accept | Tab | Tab |
|
- v0.dev vragen om complexe backend logica → niet zijn sterke punt
|
||||||
| Inline edit | CMD+K | Ctrl+K |
|
- OpenCode vragen om design inspiratie → kan geen images maken
|
||||||
| Open Chat | CMD+Shift+L | Ctrl+Shift+L |
|
|
||||||
| Open Composer | CMD+I | Ctrl+I |
|
**❌ Heen en weer kopiëren zonder begrip:**
|
||||||
| Accept suggestion | CMD+Y | Ctrl+Y |
|
- Kopieer niet blind code van ChatGPT naar je project
|
||||||
| Reject suggestion | CMD+N | Ctrl+N |
|
- Begrijp eerst WAT de code doet
|
||||||
|
|
||||||
|
**❌ Dezelfde prompt in elke tool:**
|
||||||
|
- Pas je prompt aan per tool
|
||||||
|
- v0.dev wil visuele beschrijvingen
|
||||||
|
- OpenCode wil project-specifieke context
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Cursor
|
- ChatGPT
|
||||||
- GitHub
|
- Claude
|
||||||
|
- v0.dev
|
||||||
|
- OpenCode/WebStorm
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Cursor Verkennen
|
### Tool Comparison Challenge
|
||||||
|
|
||||||
**Deel 1: Setup (20 min)**
|
**Deel 1: Dezelfde Taak, Drie Tools (1 uur)**
|
||||||
|
|
||||||
1. Download en installeer Cursor
|
Bouw een "Contact Form" component met alle drie de tools:
|
||||||
2. Sign in met GitHub
|
|
||||||
3. Open je Todo app project
|
|
||||||
4. Verken de interface
|
|
||||||
|
|
||||||
**Deel 2: Tab Completion (30 min)**
|
1. **ChatGPT (20 min)**
|
||||||
|
- Vraag om code + uitleg
|
||||||
|
- Noteer: hoe lang duurde het, kwaliteit output, wat miste?
|
||||||
|
|
||||||
Maak nieuwe file `src/components/LoadingSpinner.tsx`:
|
2. **v0.dev (20 min)**
|
||||||
1. Typ comment: `// Loading spinner component with size prop`
|
- Genereer visueel prototype
|
||||||
2. Laat Tab completion de rest doen
|
- Noteer: hoe snel, hoe mooi, hoe aanpasbaar?
|
||||||
3. Itereer met meer comments
|
|
||||||
4. Noteer: hoe goed is de completion?
|
|
||||||
|
|
||||||
**Deel 3: CMD+K Oefenen (30 min)**
|
3. **OpenCode (20 min)**
|
||||||
|
- Integreer in bestaand project
|
||||||
|
- Noteer: hoe goed past het, hoeveel aanpassing nodig?
|
||||||
|
|
||||||
Open je TodoList component:
|
**Deel 2: Analyse (30 min)**
|
||||||
1. Selecteer de list rendering code
|
|
||||||
2. CMD+K → "Add loading state with skeleton"
|
|
||||||
3. Selecteer een button
|
|
||||||
4. CMD+K → "Add disabled state while loading"
|
|
||||||
5. Selecteer een function
|
|
||||||
6. CMD+K → "Add try-catch with error toast"
|
|
||||||
|
|
||||||
Noteer wat werkt en wat niet.
|
Vul dit schema in:
|
||||||
|
|
||||||
**Deel 4: Chat + @ Mentions (20 min)**
|
| Aspect | ChatGPT | v0.dev | OpenCode |
|
||||||
|
|--------|---------|--------|----------|
|
||||||
|
| Tijd tot werkend component | | | |
|
||||||
|
| Kwaliteit code | | | |
|
||||||
|
| Visueel design | | | |
|
||||||
|
| Past in project | | | |
|
||||||
|
| Hoeveel aanpassing nodig | | | |
|
||||||
|
| Totaalscore (1-10) | | | |
|
||||||
|
|
||||||
1. Open Chat (CMD+Shift+L)
|
**Deel 3: Workflow Documentatie (30 min)**
|
||||||
2. Vraag: "@TodoList.tsx What could I improve in this component?"
|
|
||||||
3. Vraag: "@lib/supabase.ts How do I add real-time subscriptions?"
|
|
||||||
4. Probeer @Docs voor Next.js documentatie
|
|
||||||
|
|
||||||
**Deel 5: Composer Proberen (20 min)**
|
- Maak `docs/WORKFLOW.md` in je project
|
||||||
|
- Documenteer je ideale workflow per taaktype
|
||||||
1. Open Composer (CMD+I)
|
- Inclusief template prompts voor elke tool
|
||||||
2. Vraag: "Create a Settings page with dark mode toggle and notification preferences. Use our existing component style."
|
|
||||||
3. Review de gegenereerde files
|
|
||||||
4. Accept of reject
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Screenshot van werkende Tab completion
|
- Screenshot van alle 3 contact forms
|
||||||
- 3 voorbeelden van CMD+K edits
|
- Ingevuld vergelijkingsschema
|
||||||
- Notities: wat werkt wel/niet goed
|
- `docs/WORKFLOW.md` bestand
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Bouw Feature met Cursor
|
### Bouw Je Tool Selection Cheat Sheet
|
||||||
|
|
||||||
**Deel 1: Feature Bouwen (1.5 uur)**
|
**Deel 1: Cheat Sheet Maken (1 uur)**
|
||||||
|
|
||||||
Voeg "Due Dates" toe aan je Todo app:
|
Maak een persoonlijke "Tool Selection Cheat Sheet" (1 pagina):
|
||||||
1. Elk todo kan een due date hebben
|
|
||||||
2. Toon due date in de lijst
|
|
||||||
3. Sorteer op due date
|
|
||||||
4. Markeer overdue items in rood
|
|
||||||
|
|
||||||
**Gebruik ALLE Cursor features:**
|
```markdown
|
||||||
- Tab completion voor nieuwe code
|
# Mijn AI Tool Cheat Sheet
|
||||||
- CMD+K voor aanpassingen
|
|
||||||
- Chat voor vragen
|
|
||||||
- Composer voor multi-file changes
|
|
||||||
|
|
||||||
**Deel 2: Reflectie (30 min)**
|
## Wanneer gebruik ik wat?
|
||||||
|
|
||||||
Schrijf vergelijking (400 woorden):
|
### ChatGPT
|
||||||
- Cursor vs OpenCode: wat is beter?
|
- ✅ Gebruik voor: [jouw ervaring]
|
||||||
- Welke feature gebruik je het meest?
|
- ❌ Niet voor: [jouw ervaring]
|
||||||
- Is free tier voldoende?
|
- 💡 Beste prompt tip: [jouw tip]
|
||||||
- Ga je overstappen?
|
|
||||||
|
### Claude
|
||||||
|
- ✅ Gebruik voor: [jouw ervaring]
|
||||||
|
- ❌ Niet voor: [jouw ervaring]
|
||||||
|
- 💡 Beste prompt tip: [jouw tip]
|
||||||
|
|
||||||
|
### v0.dev
|
||||||
|
- ✅ Gebruik voor: [jouw ervaring]
|
||||||
|
- ❌ Niet voor: [jouw ervaring]
|
||||||
|
- 💡 Beste prompt tip: [jouw tip]
|
||||||
|
|
||||||
|
### OpenCode
|
||||||
|
- ✅ Gebruik voor: [jouw ervaring]
|
||||||
|
- ❌ Niet voor: [jouw ervaring]
|
||||||
|
- 💡 Beste prompt tip: [jouw tip]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deel 2: Testen op Nieuwe Taken (45 min)**
|
||||||
|
|
||||||
|
Test je cheat sheet op 2 nieuwe taken:
|
||||||
|
1. Bouw een "Testimonial Card" component
|
||||||
|
2. Voeg een "Dark Mode Toggle" toe
|
||||||
|
|
||||||
|
Per taak: kies tools op basis van cheat sheet, voer uit, update cheat sheet.
|
||||||
|
|
||||||
|
**Deel 3: Reflectie (15 min)**
|
||||||
|
|
||||||
|
Schrijf korte reflectie (400 woorden):
|
||||||
|
- Welke tool is jouw favoriet en waarom?
|
||||||
|
- Wanneer combineer je tools?
|
||||||
|
- Wat ga je anders doen na deze les?
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende Due Dates feature
|
- Tool Selection Cheat Sheet (1 pagina)
|
||||||
- GitHub commit met de changes
|
- 2 gebouwde components
|
||||||
- Reflectie (400 woorden)
|
- Reflectie (400 woorden)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Cursor installeren en configureren
|
- De sterke en zwakke punten van elke AI tool benoemen
|
||||||
- Tab completion effectief gebruiken
|
- De juiste tool kiezen voor een specifieke taak
|
||||||
- CMD+K gebruiken voor inline edits
|
- Meerdere tools combineren in een effectieve workflow
|
||||||
- Chat gebruiken met @ mentions voor context
|
- Een persoonlijke workflow documenteren
|
||||||
- Composer mode gebruiken voor multi-file generatie
|
- Template prompts schrijven per tool
|
||||||
- Het verschil beoordelen tussen Cursor en OpenCode
|
- Kritisch evalueren welke tool wanneer het beste werkt
|
||||||
- De juiste Cursor feature kiezen per taak
|
|
||||||
|
|||||||
@@ -1,448 +1,237 @@
|
|||||||
# Les 11: Project Setup & Repository Structure
|
# Les 11: Hands-on: Van Idee naar Prototype
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 3: AI Tooling & Prototyping** (Les 10-12)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Zet je eindproject professioneel op met de juiste structuur, documentatie, en AI-configuratie. Je past alles toe wat je hebt geleerd en maakt je project klaar voor Cursor.
|
Pas alles wat je hebt geleerd toe in een hands-on sessie. Ga van een vaag idee naar een werkend prototype met behulp van je AI workflow.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Waarom Goede Structuur Belangrijk Is
|
### Van Idee naar Feature Breakdown
|
||||||
|
|
||||||
**Voor AI:**
|
**Het probleem:** Je hebt een idee, maar waar begin je?
|
||||||
- AI begrijpt beter wat je project doet
|
|
||||||
- Betere code suggestions
|
|
||||||
- Minder hallucinaties
|
|
||||||
|
|
||||||
**Voor jezelf:**
|
**Stap 1: Beschrijf je idee in 1-2 zinnen**
|
||||||
- Makkelijker navigeren
|
```
|
||||||
- Sneller features bouwen
|
"Ik wil een app waar je kunt bijhouden welke planten water nodig hebben."
|
||||||
- Betere samenwerking
|
```
|
||||||
|
|
||||||
|
**Stap 2: Vraag AI om feature breakdown**
|
||||||
|
```
|
||||||
|
Prompt: Ik wil een plant watering tracker app bouwen.
|
||||||
|
Wat zijn de minimale features voor een werkend prototype?
|
||||||
|
Denk aan: wat moet een gebruiker kunnen doen?
|
||||||
|
```
|
||||||
|
|
||||||
|
**Stap 3: Prioriteer (MVP denken)**
|
||||||
|
- Wat is essentieel? → In prototype
|
||||||
|
- Wat is nice-to-have? → Later
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Eindproject Aanmaken
|
### Component Thinking
|
||||||
|
|
||||||
```bash
|
**Vraag jezelf af:**
|
||||||
# Kies een goede naam voor je project
|
- Welke "blokken" zie ik op het scherm?
|
||||||
npx create-next-app@latest ai-recipe-generator
|
- Welke blokken worden herhaald?
|
||||||
# of: smart-budget-buddy
|
- Welke blokken komen op meerdere pagina's?
|
||||||
# of: travel-planner-ai
|
|
||||||
# of: jouw-eigen-idee
|
|
||||||
|
|
||||||
# Beantwoord de vragen:
|
**Voorbeeld: Plant Tracker**
|
||||||
# ✔ Would you like to use TypeScript? → Yes
|
```
|
||||||
# ✔ Would you like to use ESLint? → Yes
|
Herhaalde componenten:
|
||||||
# ✔ Would you like to use Tailwind CSS? → Yes
|
- PlantCard (naam, foto, laatste water datum)
|
||||||
# ✔ Would you like to use `src/` directory? → Yes
|
- WaterButton (markeer als water gegeven)
|
||||||
# ✔ Would you like to use App Router? → Yes
|
|
||||||
# ✔ Would you like to customize the default import alias? → No
|
|
||||||
|
|
||||||
cd ai-recipe-generator
|
Pagina componenten:
|
||||||
|
- PlantList (toont alle PlantCards)
|
||||||
|
- AddPlantForm (nieuw plant toevoegen)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### De Ideale Folder Structuur
|
### MVP (Minimum Viable Product) Denken
|
||||||
|
|
||||||
|
**Wat is MVP?**
|
||||||
|
De simpelste versie van je app die nog steeds waarde levert.
|
||||||
|
|
||||||
|
**❌ Niet MVP:**
|
||||||
|
- Alle features tegelijk
|
||||||
|
- Perfect design
|
||||||
|
- Edge cases afhandelen
|
||||||
|
- Login systeem
|
||||||
|
|
||||||
|
**✅ Wel MVP:**
|
||||||
|
- Core functionaliteit werkt
|
||||||
|
- Basis styling
|
||||||
|
- Happy path werkt
|
||||||
|
- Hardcoded data is oké
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### De Prototype Workflow
|
||||||
|
|
||||||
```
|
```
|
||||||
ai-recipe-generator/
|
1. IDEE (1-2 zinnen)
|
||||||
├── .cursor/
|
↓
|
||||||
│ └── rules/
|
2. FEATURES (AI breakdown)
|
||||||
│ └── general.mdc # Cursor instructies
|
↓
|
||||||
├── docs/
|
3. PRIORITEER (wat is MVP?)
|
||||||
│ ├── PROJECT-BRIEF.md # Project beschrijving
|
↓
|
||||||
│ ├── PROMPT-LOG.md # AI prompts logboek
|
4. COMPONENTS (welke blokken?)
|
||||||
│ └── AI-DECISIONS.md # Architectuur beslissingen
|
↓
|
||||||
├── src/
|
5. BOUWEN (tool per stap)
|
||||||
│ ├── app/
|
↓
|
||||||
│ │ ├── api/ # API routes (voor AI)
|
6. ITEREREN (feedback → aanpassen)
|
||||||
│ │ ├── layout.tsx
|
|
||||||
│ │ └── page.tsx
|
|
||||||
│ ├── components/
|
|
||||||
│ │ ├── ui/ # Herbruikbare UI components
|
|
||||||
│ │ └── features/ # Feature-specifieke components
|
|
||||||
│ ├── lib/
|
|
||||||
│ │ └── supabase.ts # Supabase client
|
|
||||||
│ └── types/
|
|
||||||
│ └── index.ts # TypeScript types
|
|
||||||
├── .env.example # Template voor env vars
|
|
||||||
├── .env.local # Echte env vars (niet committen!)
|
|
||||||
├── .gitignore
|
|
||||||
└── README.md
|
|
||||||
```
|
|
||||||
|
|
||||||
**Maak de folders aan:**
|
|
||||||
```bash
|
|
||||||
mkdir -p .cursor/rules
|
|
||||||
mkdir -p docs
|
|
||||||
mkdir -p src/components/ui
|
|
||||||
mkdir -p src/components/features
|
|
||||||
mkdir -p src/lib
|
|
||||||
mkdir -p src/types
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### .cursorrules Files
|
### Voorbeeld: Weer Widget Prototype
|
||||||
|
|
||||||
**.cursor/rules/general.mdc:**
|
**Stap 1: Idee**
|
||||||
```markdown
|
"Simpele weer widget met 3-daagse forecast"
|
||||||
# Project: AI Recipe Generator
|
|
||||||
|
|
||||||
## Tech Stack
|
**Stap 2: AI Feature Breakdown**
|
||||||
- Next.js 14 met App Router
|
|
||||||
- TypeScript (strict mode)
|
|
||||||
- Tailwind CSS voor styling
|
|
||||||
- Supabase voor database en auth
|
|
||||||
- Vercel AI SDK voor chat features
|
|
||||||
|
|
||||||
## Code Conventies
|
|
||||||
- Gebruik functionele React components
|
|
||||||
- Gebruik named exports (geen default exports)
|
|
||||||
- Destructure props in function signature
|
|
||||||
- Gebruik async/await (geen .then() chains)
|
|
||||||
- Schrijf TypeScript types voor alle props en data
|
|
||||||
|
|
||||||
## File Naming
|
|
||||||
- Components: PascalCase (Button.tsx, RecipeCard.tsx)
|
|
||||||
- Utilities: camelCase (formatDate.ts, fetchRecipes.ts)
|
|
||||||
- Types: PascalCase met 'Type' suffix (RecipeType.ts)
|
|
||||||
|
|
||||||
## Styling
|
|
||||||
- Alleen Tailwind classes, geen inline styles
|
|
||||||
- Mobile-first approach
|
|
||||||
- Gebruik consistent spacing (4, 8, 16, 24, 32)
|
|
||||||
|
|
||||||
## Supabase
|
|
||||||
- Client in src/lib/supabase.ts
|
|
||||||
- Gebruik typed queries waar mogelijk
|
|
||||||
- Handle errors expliciet
|
|
||||||
|
|
||||||
## AI Features
|
|
||||||
- API routes in src/app/api/
|
|
||||||
- Gebruik Vercel AI SDK useChat hook
|
|
||||||
- Stream responses voor betere UX
|
|
||||||
```
|
```
|
||||||
|
Vraag aan ChatGPT:
|
||||||
|
"Wat zijn de minimale features voor een weer widget met 3-daagse forecast?"
|
||||||
|
|
||||||
|
Antwoord:
|
||||||
|
- Huidige temperatuur tonen
|
||||||
|
- Weer icoon (zon, regen, etc.)
|
||||||
|
- 3-daagse forecast (dag + temp + icoon)
|
||||||
|
- Locatie tonen
|
||||||
|
```
|
||||||
|
|
||||||
|
**Stap 3: MVP Selectie**
|
||||||
|
- ✅ Huidige temperatuur
|
||||||
|
- ✅ Weer icoon
|
||||||
|
- ✅ 3 dagen forecast
|
||||||
|
- ❌ Locatie selectie (later)
|
||||||
|
- ❌ Animated icons (later)
|
||||||
|
|
||||||
|
**Stap 4: Components**
|
||||||
|
```
|
||||||
|
WeatherWidget/
|
||||||
|
├── CurrentWeather (temp + icoon)
|
||||||
|
├── ForecastDay (dag + temp + icoon)
|
||||||
|
└── ForecastList (3x ForecastDay)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Stap 5: Bouwen**
|
||||||
|
1. v0.dev: "Weather widget with current temp and 3 day forecast, minimal design"
|
||||||
|
2. OpenCode: "Integreer dit in mijn project, maak components in src/components/weather/"
|
||||||
|
|
||||||
|
**Stap 6: Itereren**
|
||||||
|
- Wat werkt niet?
|
||||||
|
- Wat kan beter?
|
||||||
|
- Vraag AI om verbeteringen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### docs/ Folder
|
### Mini-Project Ideeën
|
||||||
|
|
||||||
#### docs/PROJECT-BRIEF.md
|
| Project | Core Feature | Complexiteit |
|
||||||
```markdown
|
|---------|-------------|--------------|
|
||||||
# Project Brief: AI Recipe Generator
|
| **Weer Widget** | 3-daagse forecast | ⭐ |
|
||||||
|
| **Quiz App** | 3 vragen + score | ⭐ |
|
||||||
## Projectnaam
|
| **Recipe Card** | Ingrediënten toggle | ⭐ |
|
||||||
AI Recipe Generator
|
| **Pomodoro Timer** | Start/stop + countdown | ⭐⭐ |
|
||||||
|
| **Expense Tracker** | Lijst + totaal | ⭐⭐ |
|
||||||
## Tagline
|
|
||||||
"Ontdek recepten op basis van wat je in huis hebt"
|
|
||||||
|
|
||||||
## Probleem
|
|
||||||
Mensen hebben vaak ingrediënten in huis maar weten niet wat ze
|
|
||||||
ermee kunnen maken. Ze verspillen voedsel of bestellen onnodig.
|
|
||||||
|
|
||||||
## Oplossing
|
|
||||||
Een app waar je ingrediënten invoert en AI receptsuggesties genereert.
|
|
||||||
Je kunt chatten met de AI voor variaties en tips.
|
|
||||||
|
|
||||||
## Doelgroep
|
|
||||||
- Studenten met beperkt budget
|
|
||||||
- Thuiskoks die inspiratie zoeken
|
|
||||||
- Mensen die voedselverspilling willen verminderen
|
|
||||||
|
|
||||||
## Core Features
|
|
||||||
1. Ingrediënten invoeren
|
|
||||||
2. AI genereert recepten op basis van ingrediënten
|
|
||||||
3. Chat interface voor follow-up vragen
|
|
||||||
4. Recepten opslaan als favoriet
|
|
||||||
5. Login om favorieten te bewaren
|
|
||||||
|
|
||||||
## Nice-to-have Features
|
|
||||||
- Dieetwensen (vegetarisch, glutenvrij, etc.)
|
|
||||||
- Boodschappenlijst genereren
|
|
||||||
- Recept delen
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
- Frontend: Next.js, TypeScript, Tailwind CSS
|
|
||||||
- Backend: Supabase (database, auth)
|
|
||||||
- AI: Vercel AI SDK met OpenAI
|
|
||||||
- Deployment: Vercel
|
|
||||||
```
|
|
||||||
|
|
||||||
#### docs/PROMPT-LOG.md
|
|
||||||
```markdown
|
|
||||||
# Prompt Log
|
|
||||||
|
|
||||||
Dit document bevat de belangrijkste prompts die ik heb gebruikt.
|
|
||||||
|
|
||||||
## Template per prompt:
|
|
||||||
|
|
||||||
### [Datum] - [Onderwerp]
|
|
||||||
**Doel:** Wat wilde ik bereiken?
|
|
||||||
**Prompt:**
|
|
||||||
\`\`\`
|
|
||||||
De exacte prompt die ik gebruikte
|
|
||||||
\`\`\`
|
|
||||||
**Resultaat:** Wat was het resultaat? Werkte het?
|
|
||||||
**Geleerd:** Wat heb ik hiervan geleerd?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prompts
|
|
||||||
|
|
||||||
### [Datum] - Project Setup
|
|
||||||
**Doel:** Basis project structuur opzetten
|
|
||||||
**Prompt:**
|
|
||||||
\`\`\`
|
|
||||||
[Nog in te vullen tijdens development]
|
|
||||||
\`\`\`
|
|
||||||
**Resultaat:**
|
|
||||||
**Geleerd:**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(Voeg minimaal 10 prompts toe tijdens je project)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### docs/AI-DECISIONS.md
|
|
||||||
```markdown
|
|
||||||
# AI Decisions Log
|
|
||||||
|
|
||||||
Dit document bevat architectuur- en designbeslissingen gemaakt met AI hulp.
|
|
||||||
|
|
||||||
## Template per beslissing:
|
|
||||||
|
|
||||||
### [Datum] - [Beslissing titel]
|
|
||||||
**Context:** Wat was de situatie?
|
|
||||||
**Vraag aan AI:** Wat heb ik gevraagd?
|
|
||||||
**Opties:** Welke opties werden voorgesteld?
|
|
||||||
**Keuze:** Wat heb ik gekozen en waarom?
|
|
||||||
**Trade-offs:** Wat zijn de voor- en nadelen?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Beslissingen
|
|
||||||
|
|
||||||
### [Datum] - Database Schema
|
|
||||||
**Context:** Ik moet bepalen hoe ik recepten opsla.
|
|
||||||
**Vraag aan AI:** "Wat is een goede database structuur voor een recept app?"
|
|
||||||
**Opties:**
|
|
||||||
1. Één tabel met JSON voor ingrediënten
|
|
||||||
2. Genormaliseerde tabellen (recipes, ingredients, recipe_ingredients)
|
|
||||||
**Keuze:** Optie 1 - één tabel met JSON
|
|
||||||
**Trade-offs:**
|
|
||||||
- Pro: Simpeler, sneller te implementeren
|
|
||||||
- Con: Minder flexibel voor complexe queries
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
(Voeg minimaal 5 beslissingen toe tijdens je project)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
**.env.example (WEL committen):**
|
|
||||||
```bash
|
|
||||||
# Supabase
|
|
||||||
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
|
||||||
|
|
||||||
# OpenAI (voor Vercel AI SDK)
|
|
||||||
OPENAI_API_KEY=your-openai-key
|
|
||||||
```
|
|
||||||
|
|
||||||
**.env.local (NIET committen):**
|
|
||||||
```bash
|
|
||||||
# Supabase
|
|
||||||
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
|
|
||||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx
|
|
||||||
|
|
||||||
# OpenAI
|
|
||||||
OPENAI_API_KEY=sk-xxxxx
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### README.md Best Practices
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# AI Recipe Generator
|
|
||||||
|
|
||||||
Ontdek recepten op basis van wat je in huis hebt.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- Voer ingrediënten in die je hebt
|
|
||||||
- AI genereert receptsuggesties
|
|
||||||
- Chat voor follow-up vragen
|
|
||||||
- Sla favoriete recepten op
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
- Next.js 14 (App Router)
|
|
||||||
- TypeScript
|
|
||||||
- Tailwind CSS
|
|
||||||
- Supabase
|
|
||||||
- Vercel AI SDK
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
- Node.js 18+
|
|
||||||
- npm of yarn
|
|
||||||
- Supabase account
|
|
||||||
- OpenAI API key
|
|
||||||
|
|
||||||
### Installation
|
|
||||||
|
|
||||||
1. Clone de repository:
|
|
||||||
\`\`\`bash
|
|
||||||
git clone https://github.com/jouw-username/ai-recipe-generator.git
|
|
||||||
cd ai-recipe-generator
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
2. Installeer dependencies:
|
|
||||||
\`\`\`bash
|
|
||||||
npm install
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
3. Kopieer environment variables:
|
|
||||||
\`\`\`bash
|
|
||||||
cp .env.example .env.local
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
4. Vul je credentials in `.env.local`
|
|
||||||
|
|
||||||
5. Start development server:
|
|
||||||
\`\`\`bash
|
|
||||||
npm run dev
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
6. Open [http://localhost:3000](http://localhost:3000)
|
|
||||||
|
|
||||||
## Scripts
|
|
||||||
- `npm run dev` - Start development server
|
|
||||||
- `npm run build` - Build voor productie
|
|
||||||
- `npm run lint` - Run ESLint
|
|
||||||
|
|
||||||
## Deployment
|
|
||||||
Deze app is gedeployed op Vercel: [link naar productie]
|
|
||||||
|
|
||||||
## Author
|
|
||||||
[Jouw naam]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### GitHub Repository Aanmaken
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Initialiseer Git (als dat nog niet is gebeurd)
|
|
||||||
git init
|
|
||||||
|
|
||||||
# Maak eerste commit
|
|
||||||
git add .
|
|
||||||
git commit -m "Initial Next.js setup with project structure"
|
|
||||||
|
|
||||||
# Maak repository op GitHub.com, dan:
|
|
||||||
git remote add origin https://github.com/jouw-username/ai-recipe-generator.git
|
|
||||||
git branch -M main
|
|
||||||
git push -u origin main
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Next.js
|
- ChatGPT (voor planning)
|
||||||
- Cursor
|
- v0.dev (voor prototypes)
|
||||||
- Git & GitHub
|
- OpenCode/WebStorm (voor implementation)
|
||||||
- Supabase
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Richt je Eindproject Repository In
|
### Bouw Je Mini-Prototype
|
||||||
|
|
||||||
**Deel 1: Project Aanmaken (20 min)**
|
**Groepsdiscussie (15 min):**
|
||||||
- Kies je eindproject (Recipe Generator / Budget Buddy / Travel Planner / eigen idee)
|
Bespreek klassikaal de Tool Selection reflecties uit Les 10 - welke workflows werken het beste?
|
||||||
- Run `npx create-next-app@latest [project-naam]`
|
|
||||||
- Open in Cursor
|
|
||||||
|
|
||||||
**Deel 2: Folder Structuur (20 min)**
|
**Deel 1: Planning (30 min)**
|
||||||
- Maak alle folders aan volgens de structuur
|
|
||||||
- Maak alle bestanden aan
|
|
||||||
- Test: folder structuur is compleet
|
|
||||||
|
|
||||||
**Deel 3: .cursorrules (30 min)**
|
1. Kies een project uit de lijst (of bedenk eigen simpel idee)
|
||||||
- Schrijf `general.mdc` met jouw project details
|
2. Schrijf je idee in 1-2 zinnen
|
||||||
- Pas de tech stack, conventies, en styling regels aan
|
3. Vraag ChatGPT om feature breakdown
|
||||||
- Test: open een file en vraag Cursor iets - volgt hij je regels?
|
4. Selecteer MVP features (max 3)
|
||||||
|
5. Schets de components op papier
|
||||||
|
|
||||||
**Deel 4: Documentatie (30 min)**
|
**Deel 2: Bouwen (1 uur)**
|
||||||
- Vul PROJECT-BRIEF.md volledig in
|
|
||||||
- Maak templates klaar in PROMPT-LOG.md en AI-DECISIONS.md
|
|
||||||
- Schrijf complete README.md
|
|
||||||
|
|
||||||
**Deel 5: Git (20 min)**
|
1. Genereer UI in v0.dev
|
||||||
- Initialiseer Git
|
2. Open project in OpenCode
|
||||||
- Maak GitHub repository
|
3. Integreer en pas aan
|
||||||
- Push alles
|
4. Zorg dat het werkt (happy path)
|
||||||
|
|
||||||
|
**Focus op WORKFLOW, niet perfectie!**
|
||||||
|
|
||||||
|
**Deel 3: Documentatie (15 min)**
|
||||||
|
|
||||||
|
Maak `docs/PROTOTYPE-LOG.md`:
|
||||||
|
- Je idee
|
||||||
|
- Feature breakdown
|
||||||
|
- MVP keuzes
|
||||||
|
- Prompts die werkten
|
||||||
|
- Wat ging fout en hoe opgelost
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- GitHub repository URL
|
- Werkend prototype (kan simpel zijn)
|
||||||
- Volledig ingevulde PROJECT-BRIEF.md
|
- `docs/PROTOTYPE-LOG.md` met je proces
|
||||||
- Werkende .cursorrules file
|
- Screenshot van werkend prototype
|
||||||
- Screenshot van Cursor die je regels volgt
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Verfijn Setup & Start Bouwen
|
### Verbeter en Reflecteer
|
||||||
|
|
||||||
**Deel 1: Extra .cursorrules (30 min)**
|
**Deel 1: Prototype Verbeteren (1 uur)**
|
||||||
- Maak `components.mdc` met component conventies
|
|
||||||
- Maak `api.mdc` met API route conventies
|
|
||||||
- Test beide in Cursor
|
|
||||||
|
|
||||||
**Deel 2: Basis Components (1 uur)**
|
1. Fix eventuele bugs
|
||||||
Maak 3-5 basis UI components in `src/components/ui/`:
|
2. Voeg 1 extra feature toe
|
||||||
- Button.tsx
|
3. Verbeter styling
|
||||||
- Card.tsx
|
4. Handle 1 edge case
|
||||||
- Input.tsx
|
|
||||||
- (optioneel: Modal.tsx, Toast.tsx)
|
|
||||||
|
|
||||||
Gebruik Cursor met je .cursorrules!
|
**Deel 2: Peer Review (30 min)**
|
||||||
Log effectieve prompts in PROMPT-LOG.md
|
|
||||||
|
|
||||||
**Deel 3: Supabase Setup (30 min)**
|
- Deel je prototype met een klasgenoot
|
||||||
- Maak nieuw Supabase project voor eindopdracht
|
- Krijg feedback
|
||||||
- Configureer `.env.local` en `.env.example`
|
- Geef feedback op hun prototype
|
||||||
- Bespreek met AI welke tabellen je nodig hebt
|
|
||||||
- Maak eerste tabel aan
|
**Deel 3: Reflectie (30 min)**
|
||||||
- Documenteer in AI-DECISIONS.md
|
|
||||||
|
Schrijf "Lessons Learned" document (300 woorden):
|
||||||
|
- Wat ging goed in je workflow?
|
||||||
|
- Waar liep je vast?
|
||||||
|
- Welke tool was het meest nuttig?
|
||||||
|
- Wat doe je volgende keer anders?
|
||||||
|
- Hoe voelde het om met AI te bouwen vs alleen?
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Minimaal 2 .cursorrules files
|
- Verbeterd prototype
|
||||||
- Minimaal 3 UI components
|
- Peer review feedback (gegeven en ontvangen)
|
||||||
- Supabase project gekoppeld
|
- Lessons Learned document (300 woorden)
|
||||||
- Eerste entries in PROMPT-LOG.md en AI-DECISIONS.md
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een professionele project structuur opzetten
|
- Van een vaag idee naar concrete features gaan
|
||||||
- .cursorrules files schrijven die Cursor instrueren
|
- AI gebruiken voor feature breakdown
|
||||||
- Documentatie files aanmaken (PROJECT-BRIEF, PROMPT-LOG, AI-DECISIONS)
|
- MVP denken toepassen (essentieel vs nice-to-have)
|
||||||
- Environment variables correct beheren
|
- Een app opdelen in components
|
||||||
- Een GitHub repository aanmaken en pushen
|
- De complete workflow doorlopen (idee → prototype)
|
||||||
- De basis leggen voor AI-assisted development met goede context
|
- Het bouwproces documenteren
|
||||||
|
- Reflecteren op wat werkt en wat niet
|
||||||
|
|||||||
@@ -1,363 +1,261 @@
|
|||||||
# Les 12: MCP & Context Management
|
# Les 12: Introduction to Cursor
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 3: AI Tooling & Prototyping** (Les 10-12)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Leer over MCP (Model Context Protocol) en hoe je context effectief beheert voor betere AI-assisted development.
|
Kennismaking met Cursor - de professionele AI code editor. Leer de core features en ontdek waarom dit de tool is voor serieuze AI-assisted development.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Wat is MCP?
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de prototype ervaringen uit Les 11 - welke workflow patterns werkten goed? Wat ging fout en hoe loste je dat op?
|
||||||
|
|
||||||
**MCP = Model Context Protocol**
|
### Waarom Cursor?
|
||||||
|
|
||||||
Een protocol van Anthropic waarmee AI tools veilig kunnen verbinden met externe data bronnen.
|
**Tot nu toe gebruikten we:**
|
||||||
|
- OpenCode (gratis, goed voor leren)
|
||||||
|
- Claude Desktop (voor agents en projects)
|
||||||
|
|
||||||
**Zonder MCP:**
|
**Cursor is de volgende stap:**
|
||||||
- Je kopieert handmatig data naar Claude
|
- Purpose-built voor AI-assisted coding
|
||||||
- Context gaat verloren tussen sessies
|
- Professionele editor (gebaseerd op VS Code)
|
||||||
- Geen toegang tot live data
|
- Superieure AI integratie
|
||||||
|
- Free tier beschikbaar (voldoende voor de cursus)
|
||||||
**Met MCP:**
|
|
||||||
- Claude kan direct je files lezen
|
|
||||||
- Toegang tot databases, APIs, GitHub
|
|
||||||
- Real-time data in je conversations
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### MCP Servers
|
### Free vs Pro
|
||||||
|
|
||||||
MCP werkt met "servers" - kleine programma's die specifieke data bronnen ontsluiten.
|
| Aspect | Free Tier | Pro ($20/maand) |
|
||||||
|
|--------|-----------|-----------------|
|
||||||
|
| Tab completion | ✅ | ✅ |
|
||||||
|
| CMD+K edits | Beperkt | Onbeperkt |
|
||||||
|
| Chat | Beperkt | Onbeperkt |
|
||||||
|
| Composer | Beperkt | Onbeperkt |
|
||||||
|
| Models | GPT-4, Claude | Alle modellen |
|
||||||
|
|
||||||
**Populaire MCP Servers:**
|
**Voor deze cursus:** Free tier is voldoende!
|
||||||
|
|
||||||
| Server | Wat het doet |
|
|
||||||
|--------|--------------|
|
|
||||||
| **filesystem** | Lees/schrijf lokale files |
|
|
||||||
| **github** | Toegang tot repos, issues, PRs |
|
|
||||||
| **postgres** | Direct database queries |
|
|
||||||
| **slack** | Berichten en channels |
|
|
||||||
| **brave-search** | Web zoeken |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Claude Desktop + MCP Configureren
|
### Installatie
|
||||||
|
|
||||||
**Stap 1:** Open Claude Desktop settings
|
1. Ga naar [cursor.sh](https://cursor.sh)
|
||||||
|
2. Download voor jouw OS
|
||||||
|
3. Installeer
|
||||||
|
4. Open Cursor
|
||||||
|
5. Sign in met GitHub
|
||||||
|
|
||||||
**Stap 2:** Ga naar "Developer" → "Edit Config"
|
**Eerste keer:**
|
||||||
|
- Cursor vraagt om settings te importeren van VS Code (optioneel)
|
||||||
**Stap 3:** Voeg MCP servers toe in `claude_desktop_config.json`:
|
- Accept default keybindings
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"filesystem": {
|
|
||||||
"command": "npx",
|
|
||||||
"args": [
|
|
||||||
"-y",
|
|
||||||
"@modelcontextprotocol/server-filesystem",
|
|
||||||
"/Users/jouw-username/projects/ai-recipe-generator"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Stap 4:** Herstart Claude Desktop
|
|
||||||
|
|
||||||
**Stap 5:** Je ziet nu een 🔧 icoon in Claude - dit toont actieve MCP servers
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Filesystem MCP Testen
|
### Core Features
|
||||||
|
|
||||||
Met filesystem MCP kan Claude:
|
#### 1. Tab Completion
|
||||||
- Je project files lezen
|
AI-powered autocomplete die hele blokken code voorspelt.
|
||||||
- File structuur bekijken
|
|
||||||
- Code analyseren
|
|
||||||
|
|
||||||
**Test prompt:**
|
**Hoe het werkt:**
|
||||||
```
|
- Begin met typen
|
||||||
Analyseer mijn project structuur en geef me een overzicht
|
- Cursor suggereert code in grijs
|
||||||
van de belangrijkste files en hun functies.
|
- Druk Tab om te accepteren
|
||||||
|
- Druk Escape om te negeren
|
||||||
|
|
||||||
|
**Tip:** Schrijf een comment over wat je wilt, en Tab completion vult de code in.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Function that calculates the total price with tax
|
||||||
|
// [Tab completion vult de functie in]
|
||||||
```
|
```
|
||||||
|
|
||||||
Claude kan nu direct je files lezen zonder dat je ze kopieert!
|
#### 2. CMD+K (Inline Editing)
|
||||||
|
Selecteer code en vraag AI om het aan te passen.
|
||||||
|
|
||||||
|
**Hoe het werkt:**
|
||||||
|
1. Selecteer code (of zet cursor op een regel)
|
||||||
|
2. Druk CMD+K (Mac) of Ctrl+K (Windows)
|
||||||
|
3. Typ je instructie
|
||||||
|
4. Enter om te genereren
|
||||||
|
5. Accept of Reject de wijziging
|
||||||
|
|
||||||
|
**Voorbeelden:**
|
||||||
|
- "Add error handling"
|
||||||
|
- "Convert to TypeScript"
|
||||||
|
- "Make this responsive"
|
||||||
|
- "Add loading state"
|
||||||
|
|
||||||
|
#### 3. Chat (Sidebar)
|
||||||
|
Converseer met AI over je code.
|
||||||
|
|
||||||
|
**Hoe het werkt:**
|
||||||
|
1. CMD+Shift+L opent Chat
|
||||||
|
2. Stel je vraag
|
||||||
|
3. AI heeft context van je open file
|
||||||
|
|
||||||
|
**Voorbeelden:**
|
||||||
|
- "Explain what this function does"
|
||||||
|
- "How can I optimize this?"
|
||||||
|
- "What's wrong with this code?"
|
||||||
|
|
||||||
|
#### 4. @ Mentions
|
||||||
|
Refereer naar files, folders, of documentatie.
|
||||||
|
|
||||||
|
**Syntax:**
|
||||||
|
- `@filename.tsx` - specifieke file
|
||||||
|
- `@folder/` - hele folder
|
||||||
|
- `@Docs` - officiële docs zoeken
|
||||||
|
- `@Web` - web zoeken
|
||||||
|
|
||||||
|
**Voorbeeld:**
|
||||||
|
```
|
||||||
|
@components/Button.tsx - How can I add a loading prop to this?
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Composer Mode
|
||||||
|
Multi-file generatie in één keer.
|
||||||
|
|
||||||
|
**Hoe het werkt:**
|
||||||
|
1. CMD+I opent Composer
|
||||||
|
2. Beschrijf wat je wilt bouwen
|
||||||
|
3. AI genereert meerdere files tegelijk
|
||||||
|
4. Review en accept changes
|
||||||
|
|
||||||
|
**Wanneer gebruiken:**
|
||||||
|
- Nieuwe features met meerdere components
|
||||||
|
- Refactoring over meerdere files
|
||||||
|
- Boilerplate code genereren
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### GitHub MCP
|
### Workflow Vergelijking
|
||||||
|
|
||||||
```json
|
| Taak | OpenCode | Cursor |
|
||||||
{
|
|------|----------|--------|
|
||||||
"mcpServers": {
|
| Snelle fix | Chat | CMD+K |
|
||||||
"github": {
|
| Nieuwe component | Chat | Tab completion + CMD+K |
|
||||||
"command": "npx",
|
| Multi-file feature | Meerdere chats | Composer |
|
||||||
"args": ["-y", "@modelcontextprotocol/server-github"],
|
| Code uitleg | Chat | Chat + @ mentions |
|
||||||
"env": {
|
| Refactoring | Chat | CMD+K of Composer |
|
||||||
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxx"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Wat kun je doen:**
|
|
||||||
- "Toon mijn open issues"
|
|
||||||
- "Maak een nieuwe branch"
|
|
||||||
- "Wat zijn de recente commits?"
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Context Management
|
### Keyboard Shortcuts Cheat Sheet
|
||||||
|
|
||||||
### Wat is Context?
|
| Actie | Mac | Windows |
|
||||||
|
|-------|-----|---------|
|
||||||
**Context = alle informatie die AI heeft tijdens een conversatie**
|
| Tab completion accept | Tab | Tab |
|
||||||
|
| Inline edit | CMD+K | Ctrl+K |
|
||||||
- Je vraag
|
| Open Chat | CMD+Shift+L | Ctrl+Shift+L |
|
||||||
- Eerdere berichten
|
| Open Composer | CMD+I | Ctrl+I |
|
||||||
- Geüploade files
|
| Accept suggestion | CMD+Y | Ctrl+Y |
|
||||||
- MCP data
|
| Reject suggestion | CMD+N | Ctrl+N |
|
||||||
|
|
||||||
**Beperking:** AI heeft een "context window" - maximale hoeveelheid tokens.
|
|
||||||
|
|
||||||
| Model | Context Window |
|
|
||||||
|-------|----------------|
|
|
||||||
| GPT-4 | ~128K tokens |
|
|
||||||
| Claude 3.5 | ~200K tokens |
|
|
||||||
| Claude 3 Opus | ~200K tokens |
|
|
||||||
|
|
||||||
**1 token ≈ 4 karakters** (of ~¾ woord)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Waarom Context Belangrijk Is
|
|
||||||
|
|
||||||
**Meer context = beter begrip**
|
|
||||||
|
|
||||||
Met context over je project kan AI:
|
|
||||||
- Consistente code genereren
|
|
||||||
- Bestaande patterns volgen
|
|
||||||
- Juiste imports gebruiken
|
|
||||||
|
|
||||||
**Te veel context = problemen**
|
|
||||||
- Langzamere responses
|
|
||||||
- Hogere kosten
|
|
||||||
- AI raakt "afgeleid"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Context Strategieën
|
|
||||||
|
|
||||||
**1. Start Breed, Narrow Down**
|
|
||||||
```
|
|
||||||
Begin: "Bekijk mijn hele project structuur"
|
|
||||||
Dan: "Focus op de components folder"
|
|
||||||
Dan: "Specifiek TodoList.tsx"
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Alleen Relevante Files**
|
|
||||||
- Niet je hele codebase delen
|
|
||||||
- Focus op files die relevant zijn voor de taak
|
|
||||||
|
|
||||||
**3. @ Mentions in Cursor**
|
|
||||||
```
|
|
||||||
@components/Button.tsx @lib/utils.ts
|
|
||||||
Hoe kan ik een loading state toevoegen aan de Button?
|
|
||||||
```
|
|
||||||
|
|
||||||
**4. Fresh Start bij Nieuwe Taken**
|
|
||||||
- Nieuwe chat voor nieuwe onderwerpen
|
|
||||||
- Voorkomt context pollution
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### .cursorignore
|
|
||||||
|
|
||||||
Net als .gitignore, maar voor Cursor's AI indexing.
|
|
||||||
|
|
||||||
**Maak `.cursorignore` in je project root:**
|
|
||||||
```
|
|
||||||
# Dependencies
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Build outputs
|
|
||||||
.next/
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Large files
|
|
||||||
*.log
|
|
||||||
*.lock
|
|
||||||
|
|
||||||
# Sensitive
|
|
||||||
.env.local
|
|
||||||
```
|
|
||||||
|
|
||||||
**Waarom:**
|
|
||||||
- Snellere indexing
|
|
||||||
- Geen irrelevante suggestions
|
|
||||||
- Betere focus op je code
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Context Optimalisatie Checklist
|
|
||||||
|
|
||||||
✅ **Goede project documentatie**
|
|
||||||
- README met overview
|
|
||||||
- Duidelijke folder structuur
|
|
||||||
- Comments in complexe code
|
|
||||||
|
|
||||||
✅ **Semantische naming**
|
|
||||||
- `fetchUserData()` niet `getData()`
|
|
||||||
- `UserProfileCard.tsx` niet `Card1.tsx`
|
|
||||||
|
|
||||||
✅ **Kleine, focused files**
|
|
||||||
- Max ~300 regels per file
|
|
||||||
- Eén verantwoordelijkheid per file
|
|
||||||
|
|
||||||
✅ **Proper imports**
|
|
||||||
- Absolute imports (`@/components/...`)
|
|
||||||
- Georganiseerde imports
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Context in Cursor vs Claude Desktop
|
|
||||||
|
|
||||||
| Aspect | Cursor | Claude Desktop + MCP |
|
|
||||||
|--------|--------|---------------------|
|
|
||||||
| Automatische context | Open files | MCP servers |
|
|
||||||
| File access | @ mentions | Filesystem MCP |
|
|
||||||
| Project begrip | .cursorrules | Project Knowledge |
|
|
||||||
| Beste voor | Coding | Research, planning |
|
|
||||||
|
|
||||||
**Combineer ze:**
|
|
||||||
- Claude Desktop + MCP voor planning en grote analyses
|
|
||||||
- Cursor voor daadwerkelijk coderen
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Claude Desktop
|
|
||||||
- MCP servers
|
|
||||||
- Cursor
|
- Cursor
|
||||||
- .cursorignore
|
- GitHub
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### MCP Setup & Context Optimalisatie
|
### Cursor Verkennen
|
||||||
|
|
||||||
**Deel 1: Claude Desktop MCP Setup (45 min)**
|
**Deel 1: Setup (20 min)**
|
||||||
|
|
||||||
1. Open Claude Desktop settings
|
1. Download en installeer Cursor
|
||||||
2. Configureer filesystem MCP voor je eindproject folder
|
2. Sign in met GitHub
|
||||||
3. Herstart Claude Desktop
|
3. Open je Todo app project
|
||||||
4. Verifieer: vraag Claude om je project te analyseren
|
4. Verken de interface
|
||||||
|
|
||||||
Test prompts:
|
**Deel 2: Tab Completion (30 min)**
|
||||||
- "Wat is de structuur van mijn project?"
|
|
||||||
- "Welke dependencies gebruik ik?"
|
|
||||||
- "Analyseer mijn TodoList component"
|
|
||||||
|
|
||||||
**Deel 2: GitHub MCP (optioneel) (30 min)**
|
Maak nieuwe file `src/components/LoadingSpinner.tsx`:
|
||||||
|
1. Typ comment: `// Loading spinner component with size prop`
|
||||||
|
2. Laat Tab completion de rest doen
|
||||||
|
3. Itereer met meer comments
|
||||||
|
4. Noteer: hoe goed is de completion?
|
||||||
|
|
||||||
1. Maak GitHub Personal Access Token
|
**Deel 3: CMD+K Oefenen (30 min)**
|
||||||
2. Configureer GitHub MCP
|
|
||||||
3. Test met je eindproject repo
|
|
||||||
|
|
||||||
Test prompts:
|
Open je TodoList component:
|
||||||
- "Toon mijn recente commits"
|
1. Selecteer de list rendering code
|
||||||
- "Wat zijn mijn open issues?"
|
2. CMD+K → "Add loading state with skeleton"
|
||||||
|
3. Selecteer een button
|
||||||
|
4. CMD+K → "Add disabled state while loading"
|
||||||
|
5. Selecteer een function
|
||||||
|
6. CMD+K → "Add try-catch with error toast"
|
||||||
|
|
||||||
**Deel 3: Context Optimalisatie (45 min)**
|
Noteer wat werkt en wat niet.
|
||||||
|
|
||||||
1. Maak `.cursorignore` voor je project
|
**Deel 4: Chat + @ Mentions (20 min)**
|
||||||
2. Voeg node_modules, .next, etc. toe
|
|
||||||
3. Herindexeer project in Cursor
|
|
||||||
|
|
||||||
4. Test context kwaliteit:
|
1. Open Chat (CMD+Shift+L)
|
||||||
- Vraag Cursor iets over je project
|
2. Vraag: "@TodoList.tsx What could I improve in this component?"
|
||||||
- Zijn de antwoorden accuraat?
|
3. Vraag: "@lib/supabase.ts How do I add real-time subscriptions?"
|
||||||
- Gebruikt hij de juiste patterns?
|
4. Probeer @Docs voor Next.js documentatie
|
||||||
|
|
||||||
5. Verbeter indien nodig:
|
**Deel 5: Composer Proberen (20 min)**
|
||||||
- Voeg comments toe aan complexe code
|
|
||||||
- Verbeter naming
|
1. Open Composer (CMD+I)
|
||||||
- Split grote files
|
2. Vraag: "Create a Settings page with dark mode toggle and notification preferences. Use our existing component style."
|
||||||
|
3. Review de gegenereerde files
|
||||||
|
4. Accept of reject
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende MCP configuratie (screenshot)
|
- Screenshot van werkende Tab completion
|
||||||
- .cursorignore file
|
- 3 voorbeelden van CMD+K edits
|
||||||
- Notities over context kwaliteit
|
- Notities: wat werkt wel/niet goed
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Context Deep Dive
|
### Bouw Feature met Cursor
|
||||||
|
|
||||||
**Deel 1: MCP Experimenteren (1 uur)**
|
**Deel 1: Feature Bouwen (1.5 uur)**
|
||||||
|
|
||||||
Kies en configureer nog een MCP server:
|
Voeg "Due Dates" toe aan je Todo app:
|
||||||
- brave-search (voor web zoeken)
|
1. Elk todo kan een due date hebben
|
||||||
- sqlite (voor lokale databases)
|
2. Toon due date in de lijst
|
||||||
- Of een andere uit de [MCP registry](https://github.com/modelcontextprotocol/servers)
|
3. Sorteer op due date
|
||||||
|
4. Markeer overdue items in rood
|
||||||
|
|
||||||
Test uitgebreid:
|
**Gebruik ALLE Cursor features:**
|
||||||
- Wat kun je ermee?
|
- Tab completion voor nieuwe code
|
||||||
- Wanneer is het nuttig?
|
- CMD+K voor aanpassingen
|
||||||
- Wat zijn beperkingen?
|
- Chat voor vragen
|
||||||
|
- Composer voor multi-file changes
|
||||||
|
|
||||||
**Deel 2: Context Playbook (1 uur)**
|
**Deel 2: Reflectie (30 min)**
|
||||||
|
|
||||||
Schrijf een persoonlijk "Context Management Playbook" (1 pagina):
|
Schrijf vergelijking (400 woorden):
|
||||||
|
- Cursor vs OpenCode: wat is beter?
|
||||||
```markdown
|
- Welke feature gebruik je het meest?
|
||||||
# Mijn Context Management Playbook
|
- Is free tier voldoende?
|
||||||
|
- Ga je overstappen?
|
||||||
## Wanneer gebruik ik wat?
|
|
||||||
|
|
||||||
### Claude Desktop + MCP
|
|
||||||
- [situaties]
|
|
||||||
|
|
||||||
### Cursor met @ mentions
|
|
||||||
- [situaties]
|
|
||||||
|
|
||||||
## Mijn .cursorignore template
|
|
||||||
- [wat ignore ik altijd]
|
|
||||||
|
|
||||||
## Context strategieën
|
|
||||||
- [wat werkt voor mij]
|
|
||||||
|
|
||||||
## Red flags
|
|
||||||
- [wanneer is context slecht]
|
|
||||||
|
|
||||||
## Optimalisatie tips
|
|
||||||
- [mijn beste tips]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Extra MCP server geconfigureerd
|
- Werkende Due Dates feature
|
||||||
- Context Management Playbook (1 pagina)
|
- GitHub commit met de changes
|
||||||
- Documentatie in AI-DECISIONS.md over je context keuzes
|
- Reflectie (400 woorden)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- MCP begrijpen en uitleggen
|
- Cursor installeren en configureren
|
||||||
- MCP servers configureren in Claude Desktop
|
- Tab completion effectief gebruiken
|
||||||
- Filesystem en GitHub MCP gebruiken
|
- CMD+K gebruiken voor inline edits
|
||||||
- Context windows en token limits begrijpen
|
- Chat gebruiken met @ mentions voor context
|
||||||
- .cursorignore effectief gebruiken
|
- Composer mode gebruiken voor multi-file generatie
|
||||||
- Context strategieën toepassen
|
- Het verschil beoordelen tussen Cursor en OpenCode
|
||||||
- De juiste tool kiezen voor context management
|
- De juiste Cursor feature kiezen per taak
|
||||||
|
|||||||
@@ -1,284 +1,287 @@
|
|||||||
# Les 13: Mastering Cursor
|
# Les 13: AI Agents & Custom GPTs
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Verdieping in Cursor's geavanceerde features. Leer model keuze, Composer Mode, @ mentions, en .cursorrules optimaal gebruiken.
|
Leer werken met AI agents en custom GPTs. Bouw je eigen gespecialiseerde AI assistenten en begrijp hoe agents autonome taken kunnen uitvoeren.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Model Keuze
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de Cursor reflecties uit Les 12 - welke features werken het beste voor welke taken?
|
||||||
|
|
||||||
**Wanneer welk model?**
|
### Wat zijn AI Agents?
|
||||||
|
|
||||||
| Model | Gebruik voor | Kosten |
|
**Definitie:** AI systemen die autonoom taken kunnen uitvoeren, niet alleen antwoorden geven.
|
||||||
|-------|-------------|--------|
|
|
||||||
| **Haiku** | Simpele taken, autocomplete | Goedkoop |
|
|
||||||
| **Sonnet** | Dagelijks werk, de meeste taken | Medium |
|
|
||||||
| **Opus** | Complexe architectuur, multi-file | Duur |
|
|
||||||
|
|
||||||
**Vuistregels:**
|
**Verschil Chat vs Agent:**
|
||||||
- Tab completion: Haiku (automatisch)
|
|
||||||
- CMD+K: Sonnet (default)
|
| Aspect | Chat | Agent |
|
||||||
- Composer: Sonnet of Opus
|
|--------|------|-------|
|
||||||
- Complexe debugging: Opus
|
| Gedrag | Beantwoordt vragen | Voert taken uit |
|
||||||
|
| Autonomie | Wacht op input | Kan zelf beslissingen nemen |
|
||||||
|
| Tools | Alleen tekst | Kan tools gebruiken |
|
||||||
|
| Voorbeeld | "Hoe maak ik X?" | "Maak X voor mij" |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Composer Mode Diepgaand
|
### Claude Projects
|
||||||
|
|
||||||
**Wat is Composer?**
|
**Wat is een Claude Project?**
|
||||||
Multi-file generatie in één keer. Cursor plant en voert wijzigingen uit over meerdere bestanden.
|
- Verzameling van context specifiek voor één doel
|
||||||
|
- Blijft behouden over conversaties
|
||||||
|
- Kan bestanden bevatten
|
||||||
|
|
||||||
**Wanneer Composer gebruiken:**
|
**Wanneer gebruiken:**
|
||||||
- Nieuwe feature met meerdere components
|
- Terugkerend werk aan hetzelfde project
|
||||||
- Refactoring over meerdere files
|
- Consistente coding style nodig
|
||||||
- Boilerplate generatie
|
- Documentatie die AI moet kennen
|
||||||
- Complexe wijzigingen
|
|
||||||
|
|
||||||
**Composer Workflow:**
|
**Project aanmaken:**
|
||||||
1. CMD+I opent Composer
|
1. Ga naar claude.ai → Projects
|
||||||
2. Beschrijf je doel duidelijk
|
2. Klik "New Project"
|
||||||
3. Voeg context toe met @ mentions
|
3. Voeg project knowledge toe (files, instructies)
|
||||||
4. Laat Cursor plannen
|
4. Start conversaties binnen het project
|
||||||
5. Review het plan
|
|
||||||
6. Accept of reject per file
|
|
||||||
7. Itereer met feedback
|
|
||||||
|
|
||||||
**Voorbeeld prompt:**
|
**Voorbeeld Project Instructions:**
|
||||||
```
|
```
|
||||||
Create a user profile page with:
|
Je bent een expert React/Next.js developer.
|
||||||
- @components/ui/ style components
|
|
||||||
- Profile header with avatar
|
Technologie stack:
|
||||||
- Edit form with validation
|
- Next.js 14 met App Router
|
||||||
- Save to @lib/supabase.ts
|
- TypeScript strict mode
|
||||||
- Loading and error states
|
- Tailwind CSS
|
||||||
|
- Supabase voor backend
|
||||||
|
|
||||||
|
Coding conventions:
|
||||||
|
- Functional components met TypeScript
|
||||||
|
- Named exports (geen default exports)
|
||||||
|
- Error handling met try/catch
|
||||||
|
- Nederlandse comments in code
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### @ Mentions Systeem
|
### Custom GPTs
|
||||||
|
|
||||||
**Alle types:**
|
**Wat zijn Custom GPTs?**
|
||||||
|
Gespecialiseerde ChatGPT versies met:
|
||||||
|
- Specifieke instructies
|
||||||
|
- Eigen kennis (uploaded files)
|
||||||
|
- Optioneel: Actions (API calls)
|
||||||
|
|
||||||
| Mention | Wat het doet | Voorbeeld |
|
**Wanneer een Custom GPT maken:**
|
||||||
|---------|--------------|-----------|
|
- Repetitieve taken met dezelfde context
|
||||||
| `@file.tsx` | Specifieke file | `@Button.tsx` |
|
- Specifieke expertise nodig
|
||||||
| `@folder/` | Hele folder | `@components/` |
|
- Delen met anderen
|
||||||
| `@codebase` | Zoek in codebase | `@codebase auth logic` |
|
|
||||||
| `@Docs` | Officiële docs | `@Docs Next.js routing` |
|
|
||||||
| `@Web` | Web zoeken | `@Web Supabase auth setup` |
|
|
||||||
|
|
||||||
**Best practices:**
|
**Custom GPT maken:**
|
||||||
- Wees specifiek met file mentions
|
1. Ga naar chat.openai.com/gpts
|
||||||
- Gebruik folder mentions voor context
|
2. Klik "Create"
|
||||||
- @Docs voor up-to-date informatie
|
3. Configureer in "Create" tab OF gebruik "Configure"
|
||||||
- Combineer mentions voor betere context
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### .cursorrules Advanced
|
|
||||||
|
|
||||||
**Meerdere rules files:**
|
|
||||||
|
|
||||||
|
**Voorbeeld: Code Review GPT**
|
||||||
```
|
```
|
||||||
.cursor/
|
Instructions:
|
||||||
└── rules/
|
Je bent een code reviewer gespecialiseerd in React/Next.js.
|
||||||
├── general.mdc # Project-brede regels
|
|
||||||
├── components.mdc # Component conventies
|
|
||||||
├── api.mdc # API route regels
|
|
||||||
└── testing.mdc # Test conventies
|
|
||||||
```
|
|
||||||
|
|
||||||
**Effectieve rules schrijven:**
|
Bij elke code review check je:
|
||||||
|
1. TypeScript best practices
|
||||||
|
2. React hooks correct gebruik
|
||||||
|
3. Performance (unnecessary re-renders)
|
||||||
|
4. Accessibility basics
|
||||||
|
5. Error handling
|
||||||
|
|
||||||
```markdown
|
Geef feedback in dit format:
|
||||||
# Component Rules
|
- ✅ Goed: [wat goed is]
|
||||||
|
- ⚠️ Suggestie: [verbeterpunten]
|
||||||
## Structure
|
- ❌ Issue: [problemen die gefixed moeten worden]
|
||||||
Alle components moeten volgen:
|
|
||||||
1. Props interface bovenaan
|
|
||||||
2. Component function
|
|
||||||
3. Named export onderaan
|
|
||||||
|
|
||||||
## Example
|
|
||||||
\`\`\`tsx
|
|
||||||
interface ButtonProps {
|
|
||||||
label: string
|
|
||||||
onClick: () => void
|
|
||||||
variant?: 'primary' | 'secondary'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
|
|
||||||
return (
|
|
||||||
<button onClick={onClick} className={...}>
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
\`\`\`
|
|
||||||
|
|
||||||
## DON'Ts
|
|
||||||
- Geen default exports
|
|
||||||
- Geen inline styles
|
|
||||||
- Geen any types
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Codebase Indexing
|
### Agent Capabilities
|
||||||
|
|
||||||
**Hoe Cursor indexeert:**
|
**Wat kunnen agents:**
|
||||||
- Scant alle files in je project
|
- Code schrijven en testen
|
||||||
- Bouwt semantic understanding
|
- Files aanmaken en bewerken
|
||||||
- Gebruikt voor autocomplete en context
|
- Terminal commands uitvoeren
|
||||||
|
- Web searches doen
|
||||||
|
- Meerdere stappen plannen
|
||||||
|
|
||||||
**Optimaliseren:**
|
**Cursor als Agent:**
|
||||||
1. Goede `.cursorignore` (node_modules, .next, etc.)
|
- Composer mode plant en voert multi-file changes uit
|
||||||
2. Semantische naming
|
- @ mentions geven context
|
||||||
3. Duidelijke file structuur
|
- Tab completion voorspelt volgende stappen
|
||||||
4. Comments waar nodig
|
|
||||||
|
|
||||||
**Re-indexeren:**
|
**Claude als Agent (met MCP):**
|
||||||
CMD+Shift+P → "Reindex"
|
- Kan tools gebruiken
|
||||||
|
- Filesystem access
|
||||||
|
- Database queries
|
||||||
|
- External APIs
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Cost Management
|
### Best Practices voor Agent Instructies
|
||||||
|
|
||||||
**Token gebruik monitoren:**
|
**Wees specifiek:**
|
||||||
- Cursor toont token count in chat
|
```
|
||||||
- Check monthly usage in settings
|
❌ "Help me met mijn project"
|
||||||
|
✅ "Review de auth logic in src/lib/auth.ts en check voor security issues"
|
||||||
|
```
|
||||||
|
|
||||||
**Bespaartips:**
|
**Geef constraints:**
|
||||||
1. Gebruik Haiku voor simpele taken
|
```
|
||||||
2. Beperk context (niet hele codebase)
|
❌ "Maak het beter"
|
||||||
3. Wees specifiek in prompts
|
✅ "Refactor naar max 50 regels, behoud dezelfde functionaliteit"
|
||||||
4. Fresh chat voor nieuwe onderwerpen
|
```
|
||||||
|
|
||||||
**Free tier strategie:**
|
**Definieer output format:**
|
||||||
- Focus op Tab completion (onbeperkt)
|
```
|
||||||
- Gebruik CMD+K spaarzaam
|
Geef je antwoord in dit format:
|
||||||
- Composer alleen voor grote taken
|
1. Samenvatting (1 zin)
|
||||||
|
2. Gevonden issues (bullet points)
|
||||||
|
3. Voorgestelde fix (code)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Prompt Templates
|
||||||
|
|
||||||
|
**Code Generation Template:**
|
||||||
|
```
|
||||||
|
Context: [beschrijf je project/stack]
|
||||||
|
Taak: [wat moet er gemaakt worden]
|
||||||
|
Requirements:
|
||||||
|
- [requirement 1]
|
||||||
|
- [requirement 2]
|
||||||
|
Constraints:
|
||||||
|
- [constraint 1]
|
||||||
|
Output: [gewenst format]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Debugging Template:**
|
||||||
|
```
|
||||||
|
Error message:
|
||||||
|
[plak error]
|
||||||
|
|
||||||
|
Relevante code:
|
||||||
|
[plak code]
|
||||||
|
|
||||||
|
Wat ik verwacht:
|
||||||
|
[gewenst gedrag]
|
||||||
|
|
||||||
|
Wat er gebeurt:
|
||||||
|
[actueel gedrag]
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Cursor
|
- ChatGPT Custom GPTs
|
||||||
- Claude models (Haiku/Sonnet/Opus)
|
- Claude Projects
|
||||||
- .cursorrules
|
- Cursor (Composer mode)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Multi-Step Form Wizard
|
### Bouw Je Eigen AI Assistant
|
||||||
|
|
||||||
**Bouw met Composer:**
|
**Deel 1: Claude Project (45 min)**
|
||||||
|
|
||||||
| Stap | Features |
|
Maak een Claude Project voor je eindproject:
|
||||||
|------|----------|
|
1. Ga naar claude.ai → Projects → New Project
|
||||||
| 1 | Personal info (naam, email) |
|
2. Schrijf project instructions:
|
||||||
| 2 | Preferences (theme, notifications) |
|
- Tech stack
|
||||||
| 3 | Review & confirm |
|
- Coding conventions
|
||||||
| 4 | Success animation |
|
- Project specifieke regels
|
||||||
|
3. Upload relevante files (schema, README)
|
||||||
|
4. Test met 3 verschillende vragen
|
||||||
|
|
||||||
**Requirements:**
|
**Deel 2: Custom GPT (45 min)**
|
||||||
- Progress indicator
|
|
||||||
- Per-stap validatie
|
|
||||||
- localStorage persistence
|
|
||||||
- TypeScript strict
|
|
||||||
- Tailwind styling
|
|
||||||
- Mobile responsive
|
|
||||||
|
|
||||||
**Process:**
|
Maak een Custom GPT voor code review:
|
||||||
|
1. Ga naar chat.openai.com/gpts
|
||||||
|
2. Klik "Create"
|
||||||
|
3. Schrijf instructions voor jouw stack
|
||||||
|
4. Test met code uit je project
|
||||||
|
|
||||||
**Deel 1: Composer Setup (30 min)**
|
**Deel 3: Vergelijking (30 min)**
|
||||||
1. Open Composer (CMD+I)
|
|
||||||
2. Schrijf comprehensive prompt
|
|
||||||
3. Include @ mentions naar relevante files
|
|
||||||
4. Kies Sonnet of Opus
|
|
||||||
|
|
||||||
**Deel 2: Generatie & Review (45 min)**
|
Test dezelfde taak met beide:
|
||||||
1. Laat Composer genereren
|
- "Review deze component op best practices"
|
||||||
2. Review elke file
|
- Noteer verschillen in output
|
||||||
3. Accept wat goed is
|
- Welke is beter voor welk doel?
|
||||||
4. Reject wat niet past
|
|
||||||
|
|
||||||
**Deel 3: Refinement (45 min)**
|
|
||||||
1. Gebruik CMD+K voor kleine fixes
|
|
||||||
2. Chat voor vragen
|
|
||||||
3. Itereer tot het werkt
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende form wizard
|
- Claude Project URL
|
||||||
- Notities: welk model wanneer, hoeveel iteraties
|
- Custom GPT (als je ChatGPT Plus hebt) of instructies doc
|
||||||
|
- Vergelijkingsnotities
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Perfecte .cursorrules
|
### Optimaliseer Je AI Assistants
|
||||||
|
|
||||||
**Deel 1: Research (30 min)**
|
**Deel 1: Iteratie (1 uur)**
|
||||||
- Zoek 3-5 .cursorrules voorbeelden online
|
|
||||||
- Analyseer wat ze effectief maakt
|
|
||||||
|
|
||||||
**Deel 2: Write Comprehensive Rules (1 uur)**
|
Verbeter je Claude Project:
|
||||||
|
1. Test met 5 verschillende taken
|
||||||
|
2. Noteer waar instructies tekortschieten
|
||||||
|
3. Pas instructies aan
|
||||||
|
4. Test opnieuw
|
||||||
|
|
||||||
Maak complete .cursorrules voor je eindproject:
|
Documenteer in `docs/AI-ASSISTANTS.md`:
|
||||||
|
- Originele instructies
|
||||||
|
- Wat niet werkte
|
||||||
|
- Verbeterde instructies
|
||||||
|
- Resultaat verschil
|
||||||
|
|
||||||
|
**Deel 2: Prompt Library (30 min)**
|
||||||
|
|
||||||
|
Maak een persoonlijke prompt library:
|
||||||
```markdown
|
```markdown
|
||||||
# [Project Naam]
|
# Mijn Prompt Templates
|
||||||
|
|
||||||
## Tech Stack
|
## Code Generation
|
||||||
[Jouw stack]
|
[template]
|
||||||
|
|
||||||
## Code Conventions
|
## Debugging
|
||||||
[Jouw conventies]
|
[template]
|
||||||
|
|
||||||
## File Naming
|
## Code Review
|
||||||
[Jouw regels]
|
[template]
|
||||||
|
|
||||||
## Component Structure
|
## Refactoring
|
||||||
[Jouw patterns]
|
[template]
|
||||||
|
|
||||||
## Styling
|
|
||||||
[Tailwind regels]
|
|
||||||
|
|
||||||
## API Routes
|
|
||||||
[Route conventies]
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
[Error patterns]
|
|
||||||
|
|
||||||
## DON'Ts
|
|
||||||
[Wat te vermijden]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Deel 3: Test (30 min)**
|
**Deel 3: Reflectie (30 min)**
|
||||||
1. Start nieuw component
|
|
||||||
2. Vraag Cursor om het te bouwen
|
Schrijf reflectie (300 woorden):
|
||||||
3. Check: volgt Cursor je regels?
|
- Welke AI assistant gebruik je waarvoor?
|
||||||
4. Itereer indien nodig
|
- Wat is het verschil tussen Claude Projects en Custom GPTs?
|
||||||
|
- Hoe heeft dit je workflow verbeterd?
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Complete .cursorrules file
|
- Geoptimaliseerde AI assistant instructies
|
||||||
- Screenshot van Cursor die regels volgt
|
- Prompt library document
|
||||||
- Korte analyse: wat werkt goed, wat niet
|
- Reflectie (300 woorden)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Het juiste Claude model kiezen per taak
|
- Het verschil uitleggen tussen chat en agent
|
||||||
- Composer Mode effectief gebruiken voor multi-file features
|
- Een Claude Project aanmaken en configureren
|
||||||
- @ mentions strategisch inzetten voor context
|
- Een Custom GPT maken met specifieke instructies
|
||||||
- Geavanceerde .cursorrules files schrijven
|
- Effectieve agent instructies schrijven
|
||||||
- Codebase indexing optimaliseren
|
- Prompt templates gebruiken voor consistente resultaten
|
||||||
- Token gebruik monitoren en kosten beheren
|
- De juiste AI assistant kiezen per taak
|
||||||
|
|||||||
@@ -1,211 +1,438 @@
|
|||||||
# Les 14: Debugging & Code Review met AI
|
# Les 14: Project Setup & Repository Structure
|
||||||
|
|
||||||
> 📋 **Lesmateriaal nog niet uitgewerkt**
|
|
||||||
>
|
|
||||||
> De volgende bestanden worden gegenereerd wanneer deze les wordt uitgewerkt:
|
|
||||||
> - Les14-Slide-Overzicht.md
|
|
||||||
> - Les14-Lesplan.md
|
|
||||||
> - Les14-Bijlage-A-Lesopdracht.md
|
|
||||||
> - Les14-Bijlage-B-Huiswerkopdracht.md
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Leer hoe je AI effectief inzet voor debugging en code review. Begrijp foutmeldingen, los problemen op, en verbeter je code kwaliteit.
|
Leer professionele project setup en repository structuur. Begrijp hoe een goed georganiseerd project AI tools effectiever maakt en samenwerking vergemakkelijkt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Waarom AI voor Debugging?
|
### Groepsdiscussie (15 min)
|
||||||
- AI begrijpt error messages vaak beter dan Google
|
Bespreek klassikaal de AI assistant reflecties uit Les 13 - welke instructies werkten goed en welke niet?
|
||||||
- Kan context van jouw code meenemen
|
|
||||||
- Suggereert oplossingen specifiek voor jouw situatie
|
|
||||||
- Leert je patterns herkennen
|
|
||||||
|
|
||||||
### Error Messages Begrijpen
|
### Waarom Project Structuur Belangrijk Is
|
||||||
|
|
||||||
**Typische JavaScript/React errors:**
|
**Voor jezelf:**
|
||||||
- `TypeError: Cannot read properties of undefined`
|
- Sneller code terugvinden
|
||||||
- `ReferenceError: x is not defined`
|
- Makkelijker onderhouden
|
||||||
- `SyntaxError: Unexpected token`
|
- Minder bugs door consistentie
|
||||||
- `Hydration error` (Next.js specifiek)
|
|
||||||
|
|
||||||
**Hoe AI vragen:**
|
**Voor AI tools:**
|
||||||
|
- Betere context understanding
|
||||||
|
- Consistentere code generation
|
||||||
|
- Cursor/Claude begrijpt je project beter
|
||||||
|
|
||||||
|
**Voor samenwerking:**
|
||||||
|
- Anderen begrijpen je code sneller
|
||||||
|
- Standaard conventies = minder discussie
|
||||||
|
- Onboarding nieuwe developers eenvoudiger
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Next.js 14 Project Structuur
|
||||||
|
|
||||||
|
**Aanbevolen structuur:**
|
||||||
```
|
```
|
||||||
Ik krijg deze error:
|
project-root/
|
||||||
[plak error message]
|
├── src/
|
||||||
|
│ ├── app/ # Next.js App Router
|
||||||
In deze code:
|
│ │ ├── (auth)/ # Route group voor auth pagina's
|
||||||
[plak relevante code]
|
│ │ │ ├── login/
|
||||||
|
│ │ │ └── register/
|
||||||
Wat gaat er mis en hoe los ik het op?
|
│ │ ├── api/ # API routes
|
||||||
|
│ │ │ └── chat/
|
||||||
|
│ │ ├── dashboard/
|
||||||
|
│ │ ├── layout.tsx
|
||||||
|
│ │ ├── page.tsx
|
||||||
|
│ │ └── globals.css
|
||||||
|
│ │
|
||||||
|
│ ├── components/ # React components
|
||||||
|
│ │ ├── ui/ # Basis UI components
|
||||||
|
│ │ │ ├── Button.tsx
|
||||||
|
│ │ │ ├── Input.tsx
|
||||||
|
│ │ │ └── Card.tsx
|
||||||
|
│ │ ├── layout/ # Layout components
|
||||||
|
│ │ │ ├── Header.tsx
|
||||||
|
│ │ │ ├── Footer.tsx
|
||||||
|
│ │ │ └── Sidebar.tsx
|
||||||
|
│ │ └── features/ # Feature-specifieke components
|
||||||
|
│ │ ├── auth/
|
||||||
|
│ │ └── dashboard/
|
||||||
|
│ │
|
||||||
|
│ ├── lib/ # Utilities en configuraties
|
||||||
|
│ │ ├── supabase.ts # Supabase client
|
||||||
|
│ │ ├── utils.ts # Helper functies
|
||||||
|
│ │ └── constants.ts # App constanten
|
||||||
|
│ │
|
||||||
|
│ ├── hooks/ # Custom React hooks
|
||||||
|
│ │ ├── useAuth.ts
|
||||||
|
│ │ └── useTodos.ts
|
||||||
|
│ │
|
||||||
|
│ └── types/ # TypeScript types
|
||||||
|
│ ├── database.ts
|
||||||
|
│ └── api.ts
|
||||||
|
│
|
||||||
|
├── public/ # Static assets
|
||||||
|
│ ├── images/
|
||||||
|
│ └── favicon.ico
|
||||||
|
│
|
||||||
|
├── docs/ # Documentatie
|
||||||
|
│ ├── PROMPT-LOG.md
|
||||||
|
│ ├── AI-DECISIONS.md
|
||||||
|
│ └── PROJECT-BRIEF.md
|
||||||
|
│
|
||||||
|
├── .cursorrules # Cursor AI configuratie
|
||||||
|
├── .env.local # Environment variables (niet in git!)
|
||||||
|
├── .env.example # Template voor env vars
|
||||||
|
├── .gitignore
|
||||||
|
├── package.json
|
||||||
|
├── tsconfig.json
|
||||||
|
├── tailwind.config.ts
|
||||||
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
### Debugging Workflow met AI
|
---
|
||||||
|
|
||||||
**Stap 1: Isoleer het probleem**
|
### Component Organisatie
|
||||||
- Waar treedt de error op?
|
|
||||||
- Wat was de laatste wijziging?
|
|
||||||
- Kan je het reproduceren?
|
|
||||||
|
|
||||||
**Stap 2: Verzamel context**
|
**UI Components (src/components/ui/):**
|
||||||
- Error message (volledig!)
|
- Herbruikbare, generieke components
|
||||||
- Relevante code
|
- Geen business logic
|
||||||
- Wat je verwacht vs wat er gebeurt
|
- Props-driven
|
||||||
|
- Voorbeelden: Button, Input, Modal, Card
|
||||||
|
|
||||||
**Stap 3: Vraag AI**
|
**Layout Components (src/components/layout/):**
|
||||||
- Wees specifiek
|
- Structurele components
|
||||||
- Geef context
|
- Meestal één per type
|
||||||
- Vraag om uitleg, niet alleen fix
|
- Voorbeelden: Header, Footer, Sidebar, Navigation
|
||||||
|
|
||||||
**Stap 4: Begrijp de oplossing**
|
**Feature Components (src/components/features/):**
|
||||||
- Vraag door als je het niet snapt
|
- Business logic bevattend
|
||||||
- Leer het pattern voor volgende keer
|
- Specifiek voor één feature
|
||||||
|
- Groepeer per feature/domein
|
||||||
|
|
||||||
### Console.log Debugging
|
---
|
||||||
- Strategisch plaatsen
|
|
||||||
- Variabele waarden checken
|
|
||||||
- Flow van code volgen
|
|
||||||
- AI kan helpen met waar te loggen
|
|
||||||
|
|
||||||
### Browser DevTools Basics
|
### File Naming Conventions
|
||||||
- Console tab: errors en logs
|
|
||||||
- Network tab: API calls checken
|
|
||||||
- Elements tab: HTML/CSS inspecteren
|
|
||||||
- React DevTools: component state bekijken
|
|
||||||
|
|
||||||
### Code Review met AI
|
**Components:**
|
||||||
|
|
||||||
**Wat kan AI reviewen:**
|
|
||||||
- Code kwaliteit en leesbaarheid
|
|
||||||
- Potentiële bugs
|
|
||||||
- Performance issues
|
|
||||||
- Security problemen
|
|
||||||
- Best practices
|
|
||||||
|
|
||||||
**Goede review prompt:**
|
|
||||||
```
|
```
|
||||||
Review deze code op:
|
✅ Button.tsx # PascalCase
|
||||||
1. Bugs of edge cases die ik mis
|
✅ UserProfile.tsx
|
||||||
2. Performance verbeteringen
|
❌ button.tsx
|
||||||
3. Leesbaarheid
|
❌ user-profile.tsx
|
||||||
4. Best practices voor React/Next.js
|
|
||||||
|
|
||||||
[plak code]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Veelvoorkomende Issues die AI Vindt
|
**Hooks:**
|
||||||
- Missing error handling
|
```
|
||||||
- Memory leaks (useEffect cleanup)
|
✅ useAuth.ts # camelCase met 'use' prefix
|
||||||
- Onnodig re-renders
|
✅ useTodos.ts
|
||||||
- Hardcoded values
|
❌ UseAuth.ts
|
||||||
- Missing loading/error states
|
❌ auth-hook.ts
|
||||||
- Accessibility issues
|
```
|
||||||
|
|
||||||
### Refactoring met AI
|
**Utilities:**
|
||||||
- "Hoe kan ik deze code simplificeren?"
|
```
|
||||||
- "Extract dit naar een custom hook"
|
✅ formatDate.ts # camelCase
|
||||||
- "Maak dit component meer herbruikbaar"
|
✅ utils.ts
|
||||||
|
✅ constants.ts
|
||||||
|
```
|
||||||
|
|
||||||
### Wanneer NIET AI Vertrouwen
|
**Types:**
|
||||||
- Als je de oplossing niet begrijpt
|
```
|
||||||
- Bij security-gerelateerde code (dubbel check!)
|
✅ database.ts # camelCase
|
||||||
- Bij verouderde info (check versie docs)
|
✅ User.types.ts # optioneel: .types suffix
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### .cursorrules Setup
|
||||||
|
|
||||||
|
**Maak .cursorrules in project root:**
|
||||||
|
```markdown
|
||||||
|
# Project: [Jouw Project Naam]
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
- Next.js 14 met App Router
|
||||||
|
- TypeScript (strict mode)
|
||||||
|
- Tailwind CSS
|
||||||
|
- Supabase
|
||||||
|
- React Query
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
- Components in src/components/
|
||||||
|
- UI components in src/components/ui/
|
||||||
|
- API routes in src/app/api/
|
||||||
|
|
||||||
|
## Code Conventions
|
||||||
|
- Functional components only
|
||||||
|
- Named exports (geen default exports)
|
||||||
|
- Props interface boven component
|
||||||
|
- Nederlandse comments
|
||||||
|
|
||||||
|
## Naming
|
||||||
|
- Components: PascalCase (Button.tsx)
|
||||||
|
- Hooks: camelCase met use prefix (useAuth.ts)
|
||||||
|
- Utils: camelCase (formatDate.ts)
|
||||||
|
|
||||||
|
## Styling
|
||||||
|
- Tailwind CSS classes
|
||||||
|
- Geen inline styles
|
||||||
|
- Responsive mobile-first
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
- Strict mode
|
||||||
|
- Geen any types
|
||||||
|
- Interfaces voor props
|
||||||
|
- Types voor data
|
||||||
|
|
||||||
|
## Don'ts
|
||||||
|
- Geen console.log in productie
|
||||||
|
- Geen hardcoded strings
|
||||||
|
- Geen unused imports
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Git Best Practices
|
||||||
|
|
||||||
|
**Commit Message Format:**
|
||||||
|
```
|
||||||
|
type: korte beschrijving
|
||||||
|
|
||||||
|
Types:
|
||||||
|
- feat: nieuwe feature
|
||||||
|
- fix: bug fix
|
||||||
|
- refactor: code verbetering
|
||||||
|
- docs: documentatie
|
||||||
|
- style: formatting
|
||||||
|
- test: tests toevoegen
|
||||||
|
```
|
||||||
|
|
||||||
|
**Voorbeelden:**
|
||||||
|
```bash
|
||||||
|
git commit -m "feat: add user authentication with Supabase"
|
||||||
|
git commit -m "fix: resolve hydration error in TodoList"
|
||||||
|
git commit -m "docs: update README with setup instructions"
|
||||||
|
```
|
||||||
|
|
||||||
|
**.gitignore essentials:**
|
||||||
|
```
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# Next.js
|
||||||
|
.next/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
**Structuur:**
|
||||||
|
```bash
|
||||||
|
# .env.local (NOOIT committen!)
|
||||||
|
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
|
||||||
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci...
|
||||||
|
OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
# .env.example (WEL committen)
|
||||||
|
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
|
||||||
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||||
|
OPENAI_API_KEY=your-openai-key
|
||||||
|
```
|
||||||
|
|
||||||
|
**Regels:**
|
||||||
|
- `NEXT_PUBLIC_` prefix = zichtbaar in browser
|
||||||
|
- Zonder prefix = alleen server-side
|
||||||
|
- Nooit secrets in `NEXT_PUBLIC_` vars
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### README.md Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Project Naam
|
||||||
|
|
||||||
|
Korte beschrijving van je project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Feature 1
|
||||||
|
- Feature 2
|
||||||
|
- Feature 3
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
- Next.js 14
|
||||||
|
- TypeScript
|
||||||
|
- Tailwind CSS
|
||||||
|
- Supabase
|
||||||
|
- Vercel AI SDK
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Node.js 18+
|
||||||
|
- npm of yarn
|
||||||
|
- Supabase account
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
1. Clone de repository
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/username/project.git
|
||||||
|
cd project
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Installeer dependencies
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Maak .env.local (zie .env.example)
|
||||||
|
|
||||||
|
4. Start development server
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
Zie `.env.example` voor benodigde variabelen.
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
Deployed op Vercel: [productie-url]
|
||||||
|
|
||||||
|
## Documentatie
|
||||||
|
- [PROMPT-LOG.md](docs/PROMPT-LOG.md)
|
||||||
|
- [AI-DECISIONS.md](docs/AI-DECISIONS.md)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Cursor
|
- Cursor
|
||||||
- Browser DevTools
|
- Git
|
||||||
- React DevTools
|
- GitHub
|
||||||
- Console/Terminal
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Debugging Challenge
|
### Setup Je Eindproject
|
||||||
|
|
||||||
Je krijgt een project met opzettelijke bugs. Los ze op met AI hulp.
|
**Deel 1: Project Structuur (45 min)**
|
||||||
|
|
||||||
**Deel 1: Setup (10 min)**
|
1. Maak nieuw Next.js project:
|
||||||
- Clone het buggy project (wordt gedeeld)
|
```bash
|
||||||
- Run `npm install` en `npm run dev`
|
npx create-next-app@latest mijn-eindproject --typescript --tailwind --app
|
||||||
- Zie alle errors!
|
```
|
||||||
|
|
||||||
**Deel 2: Bug Hunting (1 uur 20 min)**
|
2. Maak de mappenstructuur:
|
||||||
|
- src/components/ui/
|
||||||
|
- src/components/layout/
|
||||||
|
- src/components/features/
|
||||||
|
- src/lib/
|
||||||
|
- src/hooks/
|
||||||
|
- src/types/
|
||||||
|
- docs/
|
||||||
|
|
||||||
Los de volgende bugs op (met AI hulp):
|
3. Maak placeholder files:
|
||||||
|
- src/lib/supabase.ts
|
||||||
|
- src/lib/utils.ts
|
||||||
|
|
||||||
| Bug | Symptoom |
|
**Deel 2: Configuratie (30 min)**
|
||||||
|-----|----------|
|
|
||||||
| 1 | App crashed bij opstarten |
|
|
||||||
| 2 | Data wordt niet geladen |
|
|
||||||
| 3 | Form submit werkt niet |
|
|
||||||
| 4 | Styling is broken op mobile |
|
|
||||||
| 5 | Infinite loop bij useEffect |
|
|
||||||
| 6 | Button click doet niets |
|
|
||||||
|
|
||||||
**Per bug:**
|
1. Maak .cursorrules met jouw conventies
|
||||||
- Identificeer de error message
|
2. Maak .env.example
|
||||||
- Vraag AI om hulp met context
|
3. Update .gitignore
|
||||||
- Implementeer de fix
|
4. Maak README.md met template
|
||||||
- Documenteer wat je geleerd hebt
|
|
||||||
|
|
||||||
**Deel 3: Documentatie (30 min)**
|
**Deel 3: Git Setup (25 min)**
|
||||||
- Voeg toe aan je `PROMPT-LOG.md`:
|
|
||||||
- De prompts die je gebruikte
|
1. git init
|
||||||
- Wat werkte wel/niet
|
2. Initial commit met goede message
|
||||||
|
3. Push naar GitHub
|
||||||
|
4. Check: .env.local NIET gecommit?
|
||||||
|
|
||||||
|
**Deel 4: Documentatie Start (20 min)**
|
||||||
|
|
||||||
|
Maak in docs/:
|
||||||
|
- PROJECT-BRIEF.md (beschrijving eindproject)
|
||||||
|
- PROMPT-LOG.md (leeg template)
|
||||||
|
- AI-DECISIONS.md (leeg template)
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Alle 6 bugs gefixed
|
- GitHub repository met correcte structuur
|
||||||
- PROMPT-LOG.md bijgewerkt
|
- .cursorrules file
|
||||||
- Korte notities per bug: wat was het probleem, hoe opgelost
|
- README.md
|
||||||
|
- docs/ folder met templates
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Code Review Je Eigen Project
|
### Bouw Project Foundation
|
||||||
|
|
||||||
**Deel 1: Self-Review met AI (1 uur)**
|
**Deel 1: Base Components (1 uur)**
|
||||||
- Kies 3 belangrijke files uit je eindproject
|
|
||||||
- Laat AI ze reviewen met een goede prompt
|
|
||||||
- Documenteer bevindingen in `AI-DECISIONS.md`
|
|
||||||
|
|
||||||
**Per file noteer:**
|
Maak basis UI components met AI hulp:
|
||||||
- Welke issues AI vond
|
- src/components/ui/Button.tsx
|
||||||
- Welke je hebt gefixed
|
- src/components/ui/Input.tsx
|
||||||
- Welke je bewust negeert (en waarom)
|
- src/components/ui/Card.tsx
|
||||||
|
- src/components/layout/Header.tsx
|
||||||
|
- src/components/layout/Footer.tsx
|
||||||
|
|
||||||
**Deel 2: Refactoring (45 min)**
|
Requirements:
|
||||||
- Kies 1 component dat te complex is
|
- TypeScript interfaces voor props
|
||||||
- Vraag AI om refactoring suggesties
|
- Tailwind styling
|
||||||
- Implementeer de verbeteringen
|
- Responsive design
|
||||||
- Vergelijk before/after
|
- Volg je .cursorrules
|
||||||
|
|
||||||
**Deel 3: Debugging Checklist (15 min)**
|
**Deel 2: Supabase Setup (30 min)**
|
||||||
- Maak persoonlijke debugging checklist
|
|
||||||
- Wat check je eerst bij errors?
|
1. Maak Supabase project (of hergebruik van Les 9)
|
||||||
- Welke prompts werken goed voor jou?
|
2. Configureer src/lib/supabase.ts
|
||||||
|
3. Voeg env vars toe aan .env.local
|
||||||
|
4. Test connectie
|
||||||
|
|
||||||
|
**Deel 3: Eerste Feature (30 min)**
|
||||||
|
|
||||||
|
Kies je eindproject en implementeer 1 basisfeature:
|
||||||
|
- Recipe Generator: ingredient input form
|
||||||
|
- Budget Buddy: expense entry form
|
||||||
|
- Travel Planner: destination search
|
||||||
|
|
||||||
|
Commit en push!
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- AI-DECISIONS.md met review bevindingen
|
- Werkende UI components
|
||||||
- 1 gerefactored component
|
- Supabase connectie
|
||||||
- Persoonlijke debugging checklist
|
- 1 basic feature
|
||||||
|
- Alle commits met goede messages
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Error messages lezen en begrijpen
|
- Een professionele project structuur opzetten
|
||||||
- Effectieve debugging prompts schrijven voor AI
|
- File naming conventions toepassen
|
||||||
- Browser DevTools gebruiken voor debugging
|
- Een effectieve .cursorrules file schrijven
|
||||||
- Code laten reviewen door AI
|
- Git best practices volgen
|
||||||
- Feedback van AI kritisch evalueren
|
- Environment variables correct beheren
|
||||||
- Refactoring uitvoeren met AI suggesties
|
- Een README.md schrijven
|
||||||
- Documenteren wat geleerd is van debugging sessies
|
- Project documentatie structureren
|
||||||
|
|||||||
@@ -1,329 +1,336 @@
|
|||||||
# Les 15: Vercel AI SDK - AI Features in je App
|
# Les 15: MCP & Context Management
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Bouw AI-powered features in je apps met de Vercel AI SDK. Leer hoe je chat interfaces, streaming responses en AI-gegenereerde content implementeert.
|
Leer werken met Model Context Protocol (MCP) en geavanceerd context management. Begrijp hoe je AI tools maximale context geeft voor betere resultaten.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Waarom Vercel AI SDK?
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de project setup ervaringen uit Les 14 - welke structuur conventies werken goed en welke niet?
|
||||||
|
|
||||||
**Het probleem:** Direct API calls naar OpenAI/Anthropic zijn complex:
|
### Wat is Context?
|
||||||
- Streaming handmatig implementeren
|
|
||||||
- Error handling
|
|
||||||
- State management
|
|
||||||
|
|
||||||
**De oplossing:** Vercel AI SDK
|
**Context = wat de AI weet over jouw situatie**
|
||||||
- Simpele React hooks
|
|
||||||
- Built-in streaming
|
**Soorten context:**
|
||||||
- Provider-agnostic (OpenAI, Anthropic, etc.)
|
- **Code context:** welke files, welke functies
|
||||||
- Edge-ready
|
- **Project context:** tech stack, conventies
|
||||||
|
- **Taak context:** wat je probeert te bereiken
|
||||||
|
- **Historische context:** eerdere conversatie
|
||||||
|
|
||||||
|
**Meer context = betere antwoorden**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Installatie & Setup
|
### Model Context Protocol (MCP)
|
||||||
|
|
||||||
```bash
|
**Wat is MCP?**
|
||||||
npm install ai @ai-sdk/openai
|
- Open protocol van Anthropic
|
||||||
# of voor Anthropic:
|
- Standaard manier om AI models context te geven
|
||||||
npm install ai @ai-sdk/anthropic
|
- Verbindt AI met externe tools en data
|
||||||
|
|
||||||
|
**Waarom MCP?**
|
||||||
|
- AI kan nu "tools gebruiken"
|
||||||
|
- Toegang tot je filesystem
|
||||||
|
- Database queries uitvoeren
|
||||||
|
- Web searches doen
|
||||||
|
- En meer...
|
||||||
|
|
||||||
|
**Hoe werkt het:**
|
||||||
```
|
```
|
||||||
|
Jij → vraag → AI → MCP → Tool → resultaat → AI → antwoord → Jij
|
||||||
**Environment variable:**
|
|
||||||
```bash
|
|
||||||
# .env.local
|
|
||||||
OPENAI_API_KEY=sk-xxxxx
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Core Hooks
|
### MCP in de Praktijk
|
||||||
|
|
||||||
#### useChat - Voor Conversaties
|
**Cursor gebruikt MCP onder de hood:**
|
||||||
|
- `@file` mentions = file context via MCP
|
||||||
|
- `@codebase` = codebase search via MCP
|
||||||
|
- `@Docs` = documentation lookup via MCP
|
||||||
|
- `@Web` = web search via MCP
|
||||||
|
|
||||||
```tsx
|
**Claude Desktop met MCP:**
|
||||||
'use client'
|
- Kan tools uitvoeren
|
||||||
import { useChat } from 'ai/react'
|
- Filesystem access
|
||||||
|
- Terminal commands
|
||||||
|
- Database queries
|
||||||
|
|
||||||
export function ChatComponent() {
|
---
|
||||||
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()
|
|
||||||
|
|
||||||
return (
|
### Context Management Strategieën
|
||||||
<div className="flex flex-col h-screen">
|
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
|
||||||
{messages.map(m => (
|
|
||||||
<div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
|
|
||||||
<span className="inline-block p-2 rounded-lg bg-gray-100">
|
|
||||||
{m.content}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form onSubmit={handleSubmit} className="p-4 border-t">
|
**1. Expliciete Context**
|
||||||
<input
|
Geef context direct in je prompt:
|
||||||
value={input}
|
```
|
||||||
onChange={handleInputChange}
|
Context: Next.js 14 project met TypeScript en Supabase.
|
||||||
placeholder="Type a message..."
|
Dit is een e-commerce app voor verkoop van boeken.
|
||||||
className="w-full p-2 border rounded"
|
|
||||||
/>
|
Vraag: Hoe implementeer ik een winkelwagen?
|
||||||
<button type="submit" disabled={isLoading}>
|
|
||||||
{isLoading ? 'Sending...' : 'Send'}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### useCompletion - Voor Single Completions
|
**2. File Context**
|
||||||
|
Gebruik @ mentions om relevante files toe te voegen:
|
||||||
|
```
|
||||||
|
@src/types/product.ts
|
||||||
|
@src/lib/supabase.ts
|
||||||
|
Hoe maak ik een addToCart functie?
|
||||||
|
```
|
||||||
|
|
||||||
```tsx
|
**3. Project Context**
|
||||||
import { useCompletion } from 'ai/react'
|
Gebruik .cursorrules of Claude Project instructions:
|
||||||
|
```
|
||||||
|
# In .cursorrules
|
||||||
|
Dit project is een e-commerce platform.
|
||||||
|
Alle prices zijn in cents (niet euros).
|
||||||
|
```
|
||||||
|
|
||||||
export function SummaryComponent() {
|
**4. Fresh Context**
|
||||||
const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion()
|
Begin nieuwe chat voor nieuw onderwerp:
|
||||||
|
- Voorkomt context vervuiling
|
||||||
|
- AI raakt niet in de war met oude info
|
||||||
|
|
||||||
return (
|
---
|
||||||
<div>
|
|
||||||
<form onSubmit={handleSubmit}>
|
### @ Mentions Strategisch Gebruiken
|
||||||
<textarea
|
|
||||||
value={input}
|
**Cursor @ mentions:**
|
||||||
onChange={handleInputChange}
|
|
||||||
placeholder="Paste text to summarize..."
|
| Mention | Wanneer | Voorbeeld |
|
||||||
/>
|
|---------|---------|-----------|
|
||||||
<button type="submit">Summarize</button>
|
| `@file.tsx` | Specifieke file context | `@Button.tsx hoe voeg ik loading toe?` |
|
||||||
</form>
|
| `@folder/` | Hele folder context | `@components/ welke patterns gebruik ik?` |
|
||||||
{completion && <p>{completion}</p>}
|
| `@codebase` | Zoeken in project | `@codebase waar handle ik auth?` |
|
||||||
</div>
|
| `@Docs` | Officiële documentatie | `@Docs Next.js App Router` |
|
||||||
)
|
| `@Web` | Live web search | `@Web Supabase RLS policies` |
|
||||||
}
|
|
||||||
|
**Best practice:** Combineer mentions voor rijke context:
|
||||||
|
```
|
||||||
|
@src/components/auth/LoginForm.tsx
|
||||||
|
@src/lib/supabase.ts
|
||||||
|
@Docs Supabase Auth
|
||||||
|
|
||||||
|
Hoe voeg ik Google OAuth toe aan mijn login?
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### API Routes
|
### Claude Projects voor Persistente Context
|
||||||
|
|
||||||
**app/api/chat/route.ts:**
|
**Wat kun je toevoegen aan een Project:**
|
||||||
```typescript
|
- Instructies (system prompt)
|
||||||
import { openai } from '@ai-sdk/openai'
|
- Files (code, docs, schema's)
|
||||||
import { streamText } from 'ai'
|
- Kennis die over sessies heen blijft
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
**Project Instructions Template:**
|
||||||
const { messages } = await req.json()
|
```markdown
|
||||||
|
# Project: [Naam]
|
||||||
|
|
||||||
const result = streamText({
|
## Tech Stack
|
||||||
model: openai('gpt-4o-mini'),
|
- Next.js 14 met App Router
|
||||||
system: 'You are a helpful cooking assistant. Suggest recipes based on ingredients.',
|
- TypeScript strict
|
||||||
messages,
|
- Tailwind CSS
|
||||||
})
|
- Supabase
|
||||||
|
|
||||||
return result.toDataStreamResponse()
|
## Code Conventies
|
||||||
}
|
[jouw conventies]
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
[beschrijf je schema]
|
||||||
|
|
||||||
|
## Current Focus
|
||||||
|
[waar werk je nu aan]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Met custom system prompt:**
|
**Tip:** Upload je database schema, README, en belangrijke types files.
|
||||||
```typescript
|
|
||||||
const result = streamText({
|
|
||||||
model: openai('gpt-4o-mini'),
|
|
||||||
system: `You are a recipe assistant for the AI Recipe Generator app.
|
|
||||||
|
|
||||||
When the user provides ingredients:
|
|
||||||
1. Suggest 2-3 recipes they could make
|
|
||||||
2. List required additional ingredients (if any)
|
|
||||||
3. Provide brief cooking instructions
|
|
||||||
|
|
||||||
Be concise and practical.`,
|
|
||||||
messages,
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Streaming Responses
|
### Context Windows en Limieten
|
||||||
|
|
||||||
**Waarom streaming?**
|
**Wat is een context window?**
|
||||||
- Betere UX (user ziet direct resultaat)
|
- Maximum hoeveelheid tekst die AI kan "zien"
|
||||||
- Snellere perceived performance
|
- Gemeten in tokens (±4 karakters per token)
|
||||||
- Geen wachten op complete response
|
|
||||||
|
|
||||||
**Hoe het werkt:**
|
**Limieten per model:**
|
||||||
1. Server stuurt tokens één voor één
|
| Model | Context Window |
|
||||||
2. Client rendert elke token direct
|
|-------|---------------|
|
||||||
3. User ziet "typing" effect
|
| GPT-4o | 128K tokens |
|
||||||
|
| Claude 3 Sonnet | 200K tokens |
|
||||||
|
| Claude 3 Opus | 200K tokens |
|
||||||
|
|
||||||
**Loading indicator:**
|
**Praktisch:**
|
||||||
```tsx
|
- Lange conversaties → context vol
|
||||||
{isLoading && (
|
- Veel file mentions → context vol
|
||||||
<div className="flex items-center gap-2">
|
- Start fresh chat wanneer nodig
|
||||||
<div className="animate-pulse">●</div>
|
|
||||||
<span>AI is thinking...</span>
|
**Signs van vol context:**
|
||||||
</div>
|
- AI vergeet eerdere instructies
|
||||||
)}
|
- Antwoorden worden minder relevant
|
||||||
```
|
- AI herhaalt zichzelf
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Integratie met Supabase
|
### Context Hygiene
|
||||||
|
|
||||||
**Conversations opslaan:**
|
**Do's:**
|
||||||
|
- Geef alleen relevante context
|
||||||
|
- Wees specifiek in file mentions
|
||||||
|
- Start nieuwe chat voor nieuw onderwerp
|
||||||
|
- Gebruik project-level context voor consistentie
|
||||||
|
|
||||||
```typescript
|
**Don'ts:**
|
||||||
// Maak tabel in Supabase:
|
- Hele codebase als context geven
|
||||||
// conversations: id, user_id, created_at
|
- Oude irrelevante chats voortzetten
|
||||||
// messages: id, conversation_id, role, content, created_at
|
- Te veel files tegelijk mentionen
|
||||||
|
- Context herhalen die AI al heeft
|
||||||
// Na elke message:
|
|
||||||
async function saveMessage(conversationId: string, role: string, content: string) {
|
|
||||||
await supabase.from('messages').insert({
|
|
||||||
conversation_id: conversationId,
|
|
||||||
role,
|
|
||||||
content
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**In je component:**
|
|
||||||
```tsx
|
|
||||||
const { messages, input, handleSubmit } = useChat({
|
|
||||||
onFinish: async (message) => {
|
|
||||||
await saveMessage(conversationId, message.role, message.content)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Error Handling
|
### Debugging met Context
|
||||||
|
|
||||||
```tsx
|
**Wanneer AI verkeerde antwoorden geeft:**
|
||||||
const { messages, error, reload } = useChat()
|
|
||||||
|
|
||||||
{error && (
|
1. **Check context:** Heeft AI de juiste files?
|
||||||
<div className="p-4 bg-red-100 text-red-700 rounded">
|
2. **Check instructies:** Zijn project rules geladen?
|
||||||
<p>Something went wrong. Please try again.</p>
|
3. **Fresh start:** Begin nieuwe chat
|
||||||
<button onClick={reload}>Retry</button>
|
4. **Explicieter:** Voeg meer context toe in prompt
|
||||||
</div>
|
|
||||||
)}
|
**Debug prompt:**
|
||||||
|
```
|
||||||
|
Ik merk dat je antwoord niet klopt.
|
||||||
|
Heb je toegang tot @src/lib/auth.ts?
|
||||||
|
Dit is de huidige implementatie: [plak code]
|
||||||
|
Kun je opnieuw kijken?
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Cost Management
|
|
||||||
|
|
||||||
**Model keuze:**
|
|
||||||
| Model | Kosten | Gebruik voor |
|
|
||||||
|-------|--------|--------------|
|
|
||||||
| gpt-4o-mini | Goedkoop | Meeste taken |
|
|
||||||
| gpt-4o | Duur | Complexe reasoning |
|
|
||||||
| claude-3-haiku | Goedkoop | Simpele taken |
|
|
||||||
| claude-3-sonnet | Medium | Balans |
|
|
||||||
|
|
||||||
**Bespaartips:**
|
|
||||||
1. Gebruik gpt-4o-mini als default
|
|
||||||
2. Korte system prompts
|
|
||||||
3. Beperk conversation history
|
|
||||||
4. Caching waar mogelijk
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Vercel AI SDK (`ai` package)
|
- Cursor (@ mentions)
|
||||||
- Next.js API Routes
|
- Claude Projects
|
||||||
- OpenAI API / Anthropic API
|
- ChatGPT
|
||||||
- Cursor
|
|
||||||
- Supabase
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Bouw een AI Chat Component
|
### Context Management Oefenen
|
||||||
|
|
||||||
**Deel 1: Setup (20 min)**
|
**Deel 1: @ Mentions Mastery (45 min)**
|
||||||
1. `npm install ai @ai-sdk/openai`
|
|
||||||
2. Voeg `OPENAI_API_KEY` toe aan `.env.local`
|
|
||||||
3. Maak `app/api/chat/route.ts`
|
|
||||||
|
|
||||||
**Deel 2: Basic Chat (40 min)**
|
Voer deze taken uit in Cursor:
|
||||||
1. Maak `components/Chat.tsx`
|
|
||||||
2. Implementeer `useChat` hook
|
|
||||||
3. Bouw chat UI met Tailwind
|
|
||||||
4. Test streaming werkt
|
|
||||||
|
|
||||||
**Deel 3: System Prompt (30 min)**
|
1. **Single file context:**
|
||||||
1. Schrijf system prompt voor je eindproject:
|
- Open je TodoList component
|
||||||
- Recipe Generator: cooking assistant
|
- Vraag: "@TodoList.tsx Hoe kan ik infinite scroll toevoegen?"
|
||||||
- Budget Buddy: financial advisor
|
- Noteer kwaliteit antwoord
|
||||||
- Travel Planner: travel expert
|
|
||||||
2. Test met relevante vragen
|
|
||||||
|
|
||||||
**Deel 4: Supabase Integratie (30 min)**
|
2. **Multi-file context:**
|
||||||
1. Maak `messages` tabel
|
- Vraag: "@src/components/ @src/types/ Welke types mis ik?"
|
||||||
2. Sla berichten op met `onFinish`
|
- Noteer hoe context helpt
|
||||||
3. Laad history bij page load
|
|
||||||
|
3. **Docs context:**
|
||||||
|
- Vraag: "@Docs Supabase realtime Hoe voeg ik real-time updates toe aan mijn todo app?"
|
||||||
|
- Noteer of antwoord up-to-date is
|
||||||
|
|
||||||
|
4. **Codebase search:**
|
||||||
|
- Vraag: "@codebase Waar handle ik error states?"
|
||||||
|
- Noteer of het de juiste plekken vindt
|
||||||
|
|
||||||
|
**Deel 2: Claude Project Setup (30 min)**
|
||||||
|
|
||||||
|
1. Maak Claude Project voor je eindproject
|
||||||
|
2. Schrijf comprehensive instructions
|
||||||
|
3. Upload 3-5 belangrijke files:
|
||||||
|
- Database schema/types
|
||||||
|
- Main component
|
||||||
|
- Supabase client
|
||||||
|
4. Test met 3 vragen
|
||||||
|
|
||||||
|
**Deel 3: Context Vergelijking (45 min)**
|
||||||
|
|
||||||
|
Voer dezelfde taak uit met:
|
||||||
|
1. Geen context (nieuwe chat, geen mentions)
|
||||||
|
2. File context (@mentions)
|
||||||
|
3. Project context (Claude Project)
|
||||||
|
|
||||||
|
Taak: "Implementeer een search feature voor todos"
|
||||||
|
|
||||||
|
Noteer:
|
||||||
|
- Kwaliteit code
|
||||||
|
- Relevantie voor jouw project
|
||||||
|
- Hoeveel aanpassing nodig
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende AI chat met streaming
|
- Notities over @ mentions effectiviteit
|
||||||
- Custom system prompt
|
- Claude Project met instructions
|
||||||
- Messages opgeslagen in Supabase
|
- Context vergelijkingsnotities
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Bouw AI Feature voor Eindproject
|
### Optimaliseer Je Context Strategie
|
||||||
|
|
||||||
**Deel 1: Core AI Feature (1 uur)**
|
**Deel 1: .cursorrules Perfectioneren (30 min)**
|
||||||
|
|
||||||
Implementeer de AI chat die past bij je eindproject:
|
Update je .cursorrules met:
|
||||||
|
- Specifieke file structure info
|
||||||
|
- Naming conventions met voorbeelden
|
||||||
|
- Common patterns in je project
|
||||||
|
- DON'Ts specifiek voor jouw situatie
|
||||||
|
|
||||||
| Project | AI Feature |
|
**Deel 2: Claude Project Uitbreiden (45 min)**
|
||||||
|---------|-----------|
|
|
||||||
| Recipe Generator | "Wat kan ik maken met kip en rijst?" |
|
|
||||||
| Budget Buddy | "Analyseer mijn uitgaven deze maand" |
|
|
||||||
| Travel Planner | "Plan een weekend Barcelona" |
|
|
||||||
|
|
||||||
- Custom system prompt
|
1. Upload alle relevante project files
|
||||||
- Context uit je database meegeven
|
2. Test met complexe vragen:
|
||||||
|
- "Hoe implementeer ik feature X?"
|
||||||
|
- "Review mijn auth implementatie"
|
||||||
|
- "Wat ontbreekt er nog?"
|
||||||
|
3. Itereer op instructions
|
||||||
|
|
||||||
**Deel 2: UX Polish (30 min)**
|
**Deel 3: Context Documentation (45 min)**
|
||||||
|
|
||||||
Voeg toe:
|
Maak `docs/CONTEXT-GUIDE.md`:
|
||||||
- Streaming indicator
|
```markdown
|
||||||
- Suggested prompts / quick actions
|
# Context Guide voor [Project]
|
||||||
- Copy response button
|
|
||||||
- Clear chat button
|
|
||||||
- Error handling
|
|
||||||
|
|
||||||
**Deel 3: Documentatie (30 min)**
|
## Cursor @ Mentions
|
||||||
|
- Voor UI changes: @src/components/
|
||||||
|
- Voor data logic: @src/lib/ @src/hooks/
|
||||||
|
- Voor types: @src/types/
|
||||||
|
|
||||||
Maak `docs/AI-FEATURE.md`:
|
## Claude Project
|
||||||
- Welke AI feature heb je gebouwd?
|
- Project URL: [link]
|
||||||
- Wat doet de system prompt?
|
- Uploaded files: [lijst]
|
||||||
- Hoe integreert het met Supabase?
|
- Best practices: [jouw learnings]
|
||||||
- Welke model keuzes heb je gemaakt?
|
|
||||||
|
## Common Prompts
|
||||||
|
[verzameling werkende prompts]
|
||||||
|
```
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- AI feature in eindproject
|
- Geoptimaliseerde .cursorrules
|
||||||
- Deployed preview
|
- Complete Claude Project
|
||||||
- AI-FEATURE.md documentatie
|
- docs/CONTEXT-GUIDE.md
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Vercel AI SDK installeren en configureren
|
- Uitleggen wat context is en waarom het belangrijk is
|
||||||
- `useChat` en `useCompletion` hooks gebruiken
|
- Model Context Protocol (MCP) begrijpen
|
||||||
- Streaming responses implementeren
|
- @ mentions strategisch gebruiken in Cursor
|
||||||
- API routes opzetten voor AI providers
|
- Een Claude Project opzetten met effectieve instructions
|
||||||
- Custom system prompts schrijven
|
- Context windows en limieten begrijpen
|
||||||
- Chat history opslaan in Supabase
|
- Context management best practices toepassen
|
||||||
- Error handling en loading states implementeren
|
- Debuggen wanneer AI verkeerde antwoorden geeft door context issues
|
||||||
- Kostenbewust omgaan met AI APIs
|
|
||||||
|
|||||||
@@ -1,227 +1,340 @@
|
|||||||
# Les 16: Deployment & Production
|
# Les 16: Mastering Cursor
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Deploy je eindproject naar productie. Leer environment variables, Vercel deployment, en basis performance optimalisatie.
|
Verdieping in Cursor's geavanceerde features. Leer model keuze, Composer Mode, @ mentions, en .cursorrules optimaal gebruiken.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Vercel Deployment Flow
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de context management ervaringen uit Les 15 - welke strategieën werkten het beste?
|
||||||
|
|
||||||
**Hoe Vercel werkt:**
|
### Model Keuze
|
||||||
1. Connect GitHub repository
|
|
||||||
2. Push naar main → automatische deploy
|
|
||||||
3. Push naar andere branch → preview URL
|
|
||||||
4. Alles automatisch (build, SSL, CDN)
|
|
||||||
|
|
||||||
**Waarom Vercel voor Next.js:**
|
**Wanneer welk model?**
|
||||||
- Gemaakt door dezelfde makers
|
|
||||||
- Zero-config deployment
|
| Model | Gebruik voor | Kosten |
|
||||||
- Gratis tier ruim voldoende
|
|-------|-------------|--------|
|
||||||
- Automatische HTTPS
|
| **Haiku** | Simpele taken, autocomplete | Goedkoop |
|
||||||
- Global CDN
|
| **Sonnet** | Dagelijks werk, de meeste taken | Medium |
|
||||||
|
| **Opus** | Complexe architectuur, multi-file | Duur |
|
||||||
|
|
||||||
|
**Vuistregels:**
|
||||||
|
- Tab completion: Haiku (automatisch)
|
||||||
|
- CMD+K: Sonnet (default)
|
||||||
|
- Composer: Sonnet of Opus
|
||||||
|
- Complexe debugging: Opus
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Environment Variables in Vercel
|
### Composer Mode Diepgaand
|
||||||
|
|
||||||
**Lokaal (.env.local) vs Productie (Vercel Dashboard):**
|
**Wat is Composer?**
|
||||||
|
Multi-file generatie in één keer. Cursor plant en voert wijzigingen uit over meerdere bestanden.
|
||||||
|
|
||||||
| Waar | Bestand/Locatie | Voorbeeld |
|
**Wanneer Composer gebruiken:**
|
||||||
|------|-----------------|-----------|
|
- Nieuwe feature met meerdere components
|
||||||
| Lokaal | `.env.local` | Development |
|
- Refactoring over meerdere files
|
||||||
| Vercel | Dashboard → Settings → Env Vars | Production |
|
- Boilerplate generatie
|
||||||
|
- Complexe wijzigingen
|
||||||
|
|
||||||
**Stap voor stap:**
|
**Composer Workflow:**
|
||||||
1. Ga naar je Vercel project
|
1. CMD+I opent Composer
|
||||||
2. Settings → Environment Variables
|
2. Beschrijf je doel duidelijk
|
||||||
3. Voeg toe:
|
3. Voeg context toe met @ mentions
|
||||||
- `NEXT_PUBLIC_SUPABASE_URL`
|
4. Laat Cursor plannen
|
||||||
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
5. Review het plan
|
||||||
- `OPENAI_API_KEY`
|
6. Accept of reject per file
|
||||||
4. Selecteer environment (Production, Preview, Development)
|
7. Itereer met feedback
|
||||||
5. Save & Redeploy
|
|
||||||
|
|
||||||
**Let op:**
|
**Voorbeeld prompt:**
|
||||||
- `NEXT_PUBLIC_` prefix = zichtbaar in browser
|
```
|
||||||
- Zonder prefix = alleen server-side (API routes)
|
Create a user profile page with:
|
||||||
|
- @components/ui/ style components
|
||||||
|
- Profile header with avatar
|
||||||
|
- Edit form with validation
|
||||||
|
- Save to @lib/supabase.ts
|
||||||
|
- Loading and error states
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Supabase Productie Setup
|
### @ Mentions Systeem
|
||||||
|
|
||||||
**Redirect URLs configureren:**
|
**Alle types:**
|
||||||
1. Ga naar Supabase → Authentication → URL Configuration
|
|
||||||
2. Voeg toe bij "Redirect URLs":
|
|
||||||
- `https://jouw-app.vercel.app/**`
|
|
||||||
- `https://jouw-app.vercel.app`
|
|
||||||
|
|
||||||
**Waarom:**
|
| Mention | Wat het doet | Voorbeeld |
|
||||||
- Auth redirects werken alleen naar toegestane URLs
|
|---------|--------------|-----------|
|
||||||
- Wildcards (`**`) voor sub-routes
|
| `@file.tsx` | Specifieke file | `@Button.tsx` |
|
||||||
|
| `@folder/` | Hele folder | `@components/` |
|
||||||
|
| `@codebase` | Zoek in codebase | `@codebase auth logic` |
|
||||||
|
| `@Docs` | Officiële docs | `@Docs Next.js routing` |
|
||||||
|
| `@Web` | Web zoeken | `@Web Supabase auth setup` |
|
||||||
|
|
||||||
|
**Best practices:**
|
||||||
|
- Wees specifiek met file mentions
|
||||||
|
- Gebruik folder mentions voor context
|
||||||
|
- @Docs voor up-to-date informatie
|
||||||
|
- Combineer mentions voor betere context
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Deployment Checklist
|
### .cursorrules Advanced
|
||||||
|
|
||||||
**Voor deployment:**
|
**Meerdere rules files:**
|
||||||
- [ ] `npm run build` werkt lokaal
|
|
||||||
- [ ] Geen TypeScript errors
|
|
||||||
- [ ] Environment variables gedocumenteerd in `.env.example`
|
|
||||||
- [ ] `.gitignore` bevat `.env*.local`
|
|
||||||
- [ ] README up-to-date
|
|
||||||
|
|
||||||
**Na deployment:**
|
```
|
||||||
- [ ] App laadt correct
|
.cursor/
|
||||||
- [ ] Auth werkt (login/logout)
|
└── rules/
|
||||||
- [ ] Data wordt opgehaald uit Supabase
|
├── general.mdc # Project-brede regels
|
||||||
- [ ] AI features werken (indien van toepassing)
|
├── components.mdc # Component conventies
|
||||||
- [ ] Geen console errors
|
├── api.mdc # API route regels
|
||||||
|
└── testing.mdc # Test conventies
|
||||||
|
```
|
||||||
|
|
||||||
|
**Effectieve rules schrijven:**
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Component Rules
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
Alle components moeten volgen:
|
||||||
|
1. Props interface bovenaan
|
||||||
|
2. Component function
|
||||||
|
3. Named export onderaan
|
||||||
|
|
||||||
|
## Example
|
||||||
|
\`\`\`tsx
|
||||||
|
interface ButtonProps {
|
||||||
|
label: string
|
||||||
|
onClick: () => void
|
||||||
|
variant?: 'primary' | 'secondary'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button onClick={onClick} className={...}>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## DON'Ts
|
||||||
|
- Geen default exports
|
||||||
|
- Geen inline styles
|
||||||
|
- Geen any types
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Performance Basics
|
### Codebase Indexing
|
||||||
|
|
||||||
**Lighthouse Audit:**
|
**Hoe Cursor indexeert:**
|
||||||
1. Open Chrome DevTools
|
- Scant alle files in je project
|
||||||
2. Tab "Lighthouse"
|
- Bouwt semantic understanding
|
||||||
3. Klik "Analyze page load"
|
- Gebruikt voor autocomplete en context
|
||||||
4. Aim for score >80 in elke categorie
|
|
||||||
|
|
||||||
**Quick wins:**
|
**Optimaliseren:**
|
||||||
- Gebruik Next.js `Image` component (niet `<img>`)
|
1. Goede `.cursorignore` (node_modules, .next, etc.)
|
||||||
- Lazy load components die niet direct nodig zijn
|
2. Semantische naming
|
||||||
- Verwijder ongebruikte dependencies
|
3. Duidelijke file structuur
|
||||||
|
4. Comments waar nodig
|
||||||
|
|
||||||
|
**Re-indexeren:**
|
||||||
|
CMD+Shift+P → "Reindex"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Security Checklist
|
### Cost Management
|
||||||
|
|
||||||
**Belangrijk voor productie:**
|
**Token gebruik monitoren:**
|
||||||
- [ ] API keys nooit in client-side code
|
- Cursor toont token count in chat
|
||||||
- [ ] Supabase RLS enabled (Row Level Security)
|
- Check monthly usage in settings
|
||||||
- [ ] Error messages geven geen gevoelige info
|
|
||||||
- [ ] HTTPS (automatisch via Vercel)
|
**Bespaartips:**
|
||||||
|
1. Gebruik Haiku voor simpele taken
|
||||||
|
2. Beperk context (niet hele codebase)
|
||||||
|
3. Wees specifiek in prompts
|
||||||
|
4. Fresh chat voor nieuwe onderwerpen
|
||||||
|
|
||||||
|
**Free tier strategie:**
|
||||||
|
- Focus op Tab completion (onbeperkt)
|
||||||
|
- Gebruik CMD+K spaarzaam
|
||||||
|
- Composer alleen voor grote taken
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Monitoring Basics
|
### Debugging met Cursor
|
||||||
|
|
||||||
**Vercel Dashboard toont:**
|
**AI-Assisted Debugging:**
|
||||||
- Deployments history
|
|
||||||
- Function logs
|
|
||||||
- Analytics (optioneel)
|
|
||||||
|
|
||||||
**Supabase Dashboard toont:**
|
**Stap 1: Error identificeren**
|
||||||
- Database usage
|
```
|
||||||
- Auth logs
|
@file-met-error.tsx
|
||||||
- API requests
|
Ik krijg deze error: [plak error]
|
||||||
|
Wat gaat er mis?
|
||||||
|
```
|
||||||
|
|
||||||
|
**Stap 2: Context toevoegen**
|
||||||
|
```
|
||||||
|
@file-met-error.tsx
|
||||||
|
@gerelateerde-file.ts
|
||||||
|
De error treedt op wanneer ik X doe.
|
||||||
|
Console log toont: [data]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Stap 3: Fix implementeren**
|
||||||
|
- Selecteer code met error
|
||||||
|
- CMD+K → "Fix this error: [beschrijving]"
|
||||||
|
- Review en test
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Refactoring met Cursor
|
||||||
|
|
||||||
|
**Pattern 1: Extract Component**
|
||||||
|
```
|
||||||
|
Selecteer JSX block → CMD+K
|
||||||
|
"Extract this into a separate component called ProductCard"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pattern 2: Extract Hook**
|
||||||
|
```
|
||||||
|
Selecteer state + useEffect → CMD+K
|
||||||
|
"Extract this into a custom hook called useProductData"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pattern 3: Improve Performance**
|
||||||
|
```
|
||||||
|
@Component.tsx
|
||||||
|
"Optimize this component:
|
||||||
|
- Add memoization waar nodig
|
||||||
|
- Fix unnecessary re-renders
|
||||||
|
- Improve loading performance"
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
- Vercel
|
- Cursor
|
||||||
- GitHub
|
- Claude models (Haiku/Sonnet/Opus)
|
||||||
- Supabase
|
- .cursorrules
|
||||||
- Chrome DevTools (Lighthouse)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Deploy Je Eindproject
|
### Multi-Step Form Wizard
|
||||||
|
|
||||||
**Deel 1: Pre-Deployment Check (30 min)**
|
**Bouw met Composer:**
|
||||||
|
|
||||||
Run door de checklist:
|
| Stap | Features |
|
||||||
1. `npm run build` - fix eventuele errors
|
|------|----------|
|
||||||
2. Check TypeScript errors
|
| 1 | Personal info (naam, email) |
|
||||||
3. Maak/update `.env.example`
|
| 2 | Preferences (theme, notifications) |
|
||||||
4. Update README met project info
|
| 3 | Review & confirm |
|
||||||
|
| 4 | Success animation |
|
||||||
|
|
||||||
**Deel 2: Vercel Deployment (30 min)**
|
**Requirements:**
|
||||||
|
- Progress indicator
|
||||||
|
- Per-stap validatie
|
||||||
|
- localStorage persistence
|
||||||
|
- TypeScript strict
|
||||||
|
- Tailwind styling
|
||||||
|
- Mobile responsive
|
||||||
|
|
||||||
1. Ga naar [vercel.com](https://vercel.com)
|
**Process:**
|
||||||
2. "Add New Project"
|
|
||||||
3. Import je GitHub repository
|
|
||||||
4. Voeg environment variables toe
|
|
||||||
5. Deploy!
|
|
||||||
|
|
||||||
**Deel 3: Supabase Config (20 min)**
|
**Deel 1: Composer Setup (30 min)**
|
||||||
|
1. Open Composer (CMD+I)
|
||||||
|
2. Schrijf comprehensive prompt
|
||||||
|
3. Include @ mentions naar relevante files
|
||||||
|
4. Kies Sonnet of Opus
|
||||||
|
|
||||||
1. Voeg Vercel URL toe aan Supabase redirect URLs
|
**Deel 2: Generatie & Review (45 min)**
|
||||||
2. Test auth in productie
|
1. Laat Composer genereren
|
||||||
3. Verifieer data access
|
2. Review elke file
|
||||||
|
3. Accept wat goed is
|
||||||
|
4. Reject wat niet past
|
||||||
|
|
||||||
**Deel 4: Testing & Lighthouse (40 min)**
|
**Deel 3: Refinement (45 min)**
|
||||||
|
1. Gebruik CMD+K voor kleine fixes
|
||||||
1. Test alle features in productie:
|
2. Chat voor vragen
|
||||||
- Login/logout
|
3. Itereer tot het werkt
|
||||||
- CRUD operaties
|
|
||||||
- AI chat (indien aanwezig)
|
|
||||||
2. Run Lighthouse audit
|
|
||||||
3. Fix issues tot score >80
|
|
||||||
4. Screenshot resultaat
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Werkende productie URL
|
- Werkende form wizard
|
||||||
- Lighthouse screenshot (score >80)
|
- Notities: welk model wanneer, hoeveel iteraties
|
||||||
- Test rapport: wat werkt, wat niet
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk (2 uur)
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Polish & Documentatie
|
### Perfecte .cursorrules
|
||||||
|
|
||||||
**Deel 1: Bug Fixes (1 uur)**
|
**Deel 1: Research (30 min)**
|
||||||
|
- Zoek 3-5 .cursorrules voorbeelden online
|
||||||
|
- Analyseer wat ze effectief maakt
|
||||||
|
|
||||||
1. Test je app grondig in productie
|
**Deel 2: Write Comprehensive Rules (1 uur)**
|
||||||
2. Fix gevonden bugs
|
|
||||||
3. Test edge cases:
|
|
||||||
- Lege states
|
|
||||||
- Error states
|
|
||||||
- Loading states
|
|
||||||
4. Redeploy
|
|
||||||
|
|
||||||
**Deel 2: Performance Optimization (30 min)**
|
Maak complete .cursorrules voor je eindproject:
|
||||||
|
|
||||||
1. Run Lighthouse opnieuw
|
```markdown
|
||||||
2. Fix top 3 performance issues
|
# [Project Naam]
|
||||||
3. Document wat je hebt verbeterd
|
|
||||||
|
|
||||||
**Deel 3: Documentatie Afronden (30 min)**
|
## Tech Stack
|
||||||
|
[Jouw stack]
|
||||||
|
|
||||||
Update je `README.md`:
|
## Code Conventions
|
||||||
- Werkende productie URL
|
[Jouw conventies]
|
||||||
- Features lijst
|
|
||||||
- Tech stack
|
|
||||||
- Setup instructies
|
|
||||||
- Screenshots
|
|
||||||
|
|
||||||
Update `docs/`:
|
## File Naming
|
||||||
- PROMPT-LOG.md (minimaal 10 entries)
|
[Jouw regels]
|
||||||
- AI-DECISIONS.md (minimaal 5 entries)
|
|
||||||
|
## Component Structure
|
||||||
|
[Jouw patterns]
|
||||||
|
|
||||||
|
## Styling
|
||||||
|
[Tailwind regels]
|
||||||
|
|
||||||
|
## API Routes
|
||||||
|
[Route conventies]
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
[Error patterns]
|
||||||
|
|
||||||
|
## DON'Ts
|
||||||
|
[Wat te vermijden]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deel 3: Test (30 min)**
|
||||||
|
1. Start nieuw component
|
||||||
|
2. Vraag Cursor om het te bouwen
|
||||||
|
3. Check: volgt Cursor je regels?
|
||||||
|
4. Itereer indien nodig
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Geoptimaliseerde productie app
|
- Complete .cursorrules file
|
||||||
- Complete documentatie
|
- Screenshot van Cursor die regels volgt
|
||||||
- Lighthouse score >85
|
- Korte analyse: wat werkt goed, wat niet
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Een Next.js app deployen naar Vercel
|
- Het juiste Claude model kiezen per taak
|
||||||
- Environment variables configureren in Vercel
|
- Composer Mode effectief gebruiken voor multi-file features
|
||||||
- Supabase redirect URLs instellen voor productie
|
- @ mentions strategisch inzetten voor context
|
||||||
- Een deployment checklist doorlopen
|
- Geavanceerde .cursorrules files schrijven
|
||||||
- Lighthouse gebruiken voor performance audit
|
- Codebase indexing optimaliseren
|
||||||
- Basis security checks uitvoeren
|
- Token gebruik monitoren en kosten beheren
|
||||||
- Productie monitoring begrijpen
|
- AI-assisted debugging toepassen
|
||||||
|
- Refactoring uitvoeren met Cursor
|
||||||
|
|||||||
@@ -1,187 +1,332 @@
|
|||||||
# Les 17: Eindopdracht Kickoff
|
# Les 17: Vercel AI SDK - AI Features in je App
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Bespreking van de eindopdracht requirements, planning maken, en laatste vragen beantwoorden voordat studenten zelfstandig verder werken.
|
Bouw AI-powered features in je apps met de Vercel AI SDK. Leer hoe je chat interfaces, streaming responses en AI-gegenereerde content implementeert.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Te Behandelen
|
## Te Behandelen
|
||||||
|
|
||||||
### Eindopdracht Overview
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de Cursor .cursorrules ervaringen uit Les 16 - welke regels zorgen voor betere AI output?
|
||||||
|
|
||||||
**Wat is de eindopdracht?**
|
### Waarom Vercel AI SDK?
|
||||||
- Bouw een AI-powered web applicatie
|
|
||||||
- Gebruik alle tools die je hebt geleerd
|
|
||||||
- Vrije keuze in implementatie
|
|
||||||
|
|
||||||
**Drie voorbeeldprojecten:**
|
**Het probleem:** Direct API calls naar OpenAI/Anthropic zijn complex:
|
||||||
1. **AI Recipe Generator** - Recepten op basis van ingrediënten
|
- Streaming handmatig implementeren
|
||||||
2. **Smart Budget Buddy** - Financieel overzicht met AI insights
|
- Error handling
|
||||||
3. **Travel Planner AI** - Reisplanning met AI suggesties
|
- State management
|
||||||
|
|
||||||
**Of:** Eigen idee (met goedkeuring docent)
|
**De oplossing:** Vercel AI SDK
|
||||||
|
- Simpele React hooks
|
||||||
|
- Built-in streaming
|
||||||
|
- Provider-agnostic (OpenAI, Anthropic, etc.)
|
||||||
|
- Edge-ready
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Requirements Doorlopen
|
### Installatie & Setup
|
||||||
|
|
||||||
**Technische vereisten:**
|
```bash
|
||||||
- Next.js 14 met App Router
|
npm install ai @ai-sdk/openai
|
||||||
- TypeScript
|
# of voor Anthropic:
|
||||||
- Tailwind CSS
|
npm install ai @ai-sdk/anthropic
|
||||||
- Supabase (database + auth)
|
```
|
||||||
- Vercel AI SDK (chat of completion feature)
|
|
||||||
- Deployed op Vercel
|
|
||||||
|
|
||||||
**Documentatie vereisten:**
|
**Environment variable:**
|
||||||
- `docs/PROJECT-BRIEF.md` - Project beschrijving
|
```bash
|
||||||
- `docs/PROMPT-LOG.md` - Minimaal 10 prompts
|
# .env.local
|
||||||
- `docs/AI-DECISIONS.md` - Minimaal 5 beslissingen
|
OPENAI_API_KEY=sk-xxxxx
|
||||||
- Complete README met setup instructies
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Beoordelingscriteria
|
### Core Hooks
|
||||||
|
|
||||||
| Criterium | Weging |
|
#### useChat - Voor Conversaties
|
||||||
|-----------|--------|
|
|
||||||
| Technische uitvoering | 40% |
|
|
||||||
| AI integratie | 25% |
|
|
||||||
| Documentatie (PROMPT-LOG, AI-DECISIONS) | 20% |
|
|
||||||
| Code kwaliteit & organisatie | 15% |
|
|
||||||
|
|
||||||
**Minimale vereisten:**
|
```tsx
|
||||||
- App werkt in productie
|
'use client'
|
||||||
- Auth + CRUD werkt
|
import { useChat } from 'ai/react'
|
||||||
- AI feature werkt
|
|
||||||
- Documentatie compleet
|
export function ChatComponent() {
|
||||||
|
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-screen">
|
||||||
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
|
{messages.map(m => (
|
||||||
|
<div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
|
||||||
|
<span className="inline-block p-2 rounded-lg bg-gray-100">
|
||||||
|
{m.content}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit} className="p-4 border-t">
|
||||||
|
<input
|
||||||
|
value={input}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="Type a message..."
|
||||||
|
className="w-full p-2 border rounded"
|
||||||
|
/>
|
||||||
|
<button type="submit" disabled={isLoading}>
|
||||||
|
{isLoading ? 'Sending...' : 'Send'}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### useCompletion - Voor Single Completions
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useCompletion } from 'ai/react'
|
||||||
|
|
||||||
|
export function SummaryComponent() {
|
||||||
|
const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<textarea
|
||||||
|
value={input}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
placeholder="Paste text to summarize..."
|
||||||
|
/>
|
||||||
|
<button type="submit">Summarize</button>
|
||||||
|
</form>
|
||||||
|
{completion && <p>{completion}</p>}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Timeline
|
### API Routes
|
||||||
|
|
||||||
**Nu tot deadline:**
|
**app/api/chat/route.ts:**
|
||||||
- Les 17: Kickoff, planning maken
|
```typescript
|
||||||
- Les 18: Werksessie met docent support
|
import { openai } from '@ai-sdk/openai'
|
||||||
- Daarna: Zelfstandig afronden
|
import { streamText } from 'ai'
|
||||||
|
|
||||||
**Tips:**
|
export async function POST(req: Request) {
|
||||||
- Focus eerst op werkende MVP
|
const { messages } = await req.json()
|
||||||
- Dan pas polish
|
|
||||||
- Documenteer TIJDENS het bouwen
|
const result = streamText({
|
||||||
|
model: openai('gpt-4o-mini'),
|
||||||
|
system: 'You are a helpful cooking assistant. Suggest recipes based on ingredients.',
|
||||||
|
messages,
|
||||||
|
})
|
||||||
|
|
||||||
|
return result.toDataStreamResponse()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Met custom system prompt:**
|
||||||
|
```typescript
|
||||||
|
const result = streamText({
|
||||||
|
model: openai('gpt-4o-mini'),
|
||||||
|
system: `You are a recipe assistant for the AI Recipe Generator app.
|
||||||
|
|
||||||
|
When the user provides ingredients:
|
||||||
|
1. Suggest 2-3 recipes they could make
|
||||||
|
2. List required additional ingredients (if any)
|
||||||
|
3. Provide brief cooking instructions
|
||||||
|
|
||||||
|
Be concise and practical.`,
|
||||||
|
messages,
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Veel Voorkomende Vragen
|
### Streaming Responses
|
||||||
|
|
||||||
**Q: Mag ik een ander project doen dan de voorbeelden?**
|
**Waarom streaming?**
|
||||||
A: Ja, met goedkeuring. Bespreek je idee met de docent.
|
- Betere UX (user ziet direct resultaat)
|
||||||
|
- Snellere perceived performance
|
||||||
|
- Geen wachten op complete response
|
||||||
|
|
||||||
**Q: Moet ik alle AI tools gebruiken?**
|
**Hoe het werkt:**
|
||||||
A: Je moet minimaal Cursor en Vercel AI SDK gebruiken. De rest is optioneel.
|
1. Server stuurt tokens één voor één
|
||||||
|
2. Client rendert elke token direct
|
||||||
|
3. User ziet "typing" effect
|
||||||
|
|
||||||
**Q: Wat als ik vastloop?**
|
**Loading indicator:**
|
||||||
A: Documenteer het probleem in PROMPT-LOG, vraag hulp in Les 18.
|
```tsx
|
||||||
|
{isLoading && (
|
||||||
**Q: Hoeveel prompts moet ik loggen?**
|
<div className="flex items-center gap-2">
|
||||||
A: Minimaal 10, maar meer is beter. Focus op prompts waarvan je iets leerde.
|
<div className="animate-pulse">●</div>
|
||||||
|
<span>AI is thinking...</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Planning Maken
|
### Integratie met Supabase
|
||||||
|
|
||||||
**Wat moet je nog doen?**
|
**Conversations opslaan:**
|
||||||
|
|
||||||
Maak checklist:
|
```typescript
|
||||||
- [ ] Core features compleet
|
// Maak tabel in Supabase:
|
||||||
- [ ] AI feature werkt
|
// conversations: id, user_id, created_at
|
||||||
- [ ] Auth werkt
|
// messages: id, conversation_id, role, content, created_at
|
||||||
- [ ] Design afgewerkt
|
|
||||||
- [ ] Edge cases gehandled
|
|
||||||
- [ ] Documentatie compleet
|
|
||||||
- [ ] Deployed en getest
|
|
||||||
|
|
||||||
**Prioriteer:**
|
// Na elke message:
|
||||||
1. Wat werkt nog niet?
|
async function saveMessage(conversationId: string, role: string, content: string) {
|
||||||
2. Wat is kritiek vs nice-to-have?
|
await supabase.from('messages').insert({
|
||||||
3. Hoeveel tijd heb je?
|
conversation_id: conversationId,
|
||||||
|
role,
|
||||||
|
content
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**In je component:**
|
||||||
|
```tsx
|
||||||
|
const { messages, input, handleSubmit } = useChat({
|
||||||
|
onFinish: async (message) => {
|
||||||
|
await saveMessage(conversationId, message.role, message.content)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const { messages, error, reload } = useChat()
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="p-4 bg-red-100 text-red-700 rounded">
|
||||||
|
<p>Something went wrong. Please try again.</p>
|
||||||
|
<button onClick={reload}>Retry</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Cost Management
|
||||||
|
|
||||||
|
**Model keuze:**
|
||||||
|
| Model | Kosten | Gebruik voor |
|
||||||
|
|-------|--------|--------------|
|
||||||
|
| gpt-4o-mini | Goedkoop | Meeste taken |
|
||||||
|
| gpt-4o | Duur | Complexe reasoning |
|
||||||
|
| claude-3-haiku | Goedkoop | Simpele taken |
|
||||||
|
| claude-3-sonnet | Medium | Balans |
|
||||||
|
|
||||||
|
**Bespaartips:**
|
||||||
|
1. Gebruik gpt-4o-mini als default
|
||||||
|
2. Korte system prompts
|
||||||
|
3. Beperk conversation history
|
||||||
|
4. Caching waar mogelijk
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
- Vercel AI SDK (`ai` package)
|
||||||
|
- Next.js API Routes
|
||||||
|
- OpenAI API / Anthropic API
|
||||||
- Cursor
|
- Cursor
|
||||||
- Alle geleerde tools
|
- Supabase
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Plan Je Afronding
|
### Bouw een AI Chat Component
|
||||||
|
|
||||||
**Deel 1: Status Check (30 min)**
|
**Deel 1: Setup (20 min)**
|
||||||
|
1. `npm install ai @ai-sdk/openai`
|
||||||
|
2. Voeg `OPENAI_API_KEY` toe aan `.env.local`
|
||||||
|
3. Maak `app/api/chat/route.ts`
|
||||||
|
|
||||||
Beantwoord voor jezelf:
|
**Deel 2: Basic Chat (40 min)**
|
||||||
1. Welke features werken al?
|
1. Maak `components/Chat.tsx`
|
||||||
2. Welke features missen nog?
|
2. Implementeer `useChat` hook
|
||||||
3. Wat is je grootste blocker?
|
3. Bouw chat UI met Tailwind
|
||||||
4. Hoe staat je documentatie ervoor?
|
4. Test streaming werkt
|
||||||
|
|
||||||
Maak een eerlijke inschatting.
|
**Deel 3: System Prompt (30 min)**
|
||||||
|
1. Schrijf system prompt voor je eindproject:
|
||||||
|
- Recipe Generator: cooking assistant
|
||||||
|
- Budget Buddy: financial advisor
|
||||||
|
- Travel Planner: travel expert
|
||||||
|
2. Test met relevante vragen
|
||||||
|
|
||||||
**Deel 2: Planning Maken (30 min)**
|
**Deel 4: Supabase Integratie (30 min)**
|
||||||
|
1. Maak `messages` tabel
|
||||||
Maak gedetailleerde planning:
|
2. Sla berichten op met `onFinish`
|
||||||
- Wat doe je vandaag?
|
3. Laad history bij page load
|
||||||
- Wat doe je in Les 18?
|
|
||||||
- Wat doe je thuis?
|
|
||||||
- Wanneer ben je klaar?
|
|
||||||
|
|
||||||
**Deel 3: Begin Met Hoogste Prioriteit (1 uur)**
|
|
||||||
|
|
||||||
Start met de belangrijkste ontbrekende onderdelen:
|
|
||||||
- Werkt je AI feature? → Prioriteit 1
|
|
||||||
- Werkt auth? → Prioriteit 2
|
|
||||||
- Is het deployed? → Prioriteit 3
|
|
||||||
|
|
||||||
Vraag hulp als je vastloopt!
|
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Statusoverzicht: wat werkt, wat niet
|
- Werkende AI chat met streaming
|
||||||
- Planning voor afronden
|
- Custom system prompt
|
||||||
- Voortgang op hoogste prioriteit
|
- Messages opgeslagen in Supabase
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk
|
## Huiswerk (2 uur)
|
||||||
|
|
||||||
### Werk aan je Eindopdracht
|
### Bouw AI Feature voor Eindproject
|
||||||
|
|
||||||
**Dit is geen nieuw huiswerk - gebruik deze tijd om je eindopdracht af te ronden.**
|
**Deel 1: Core AI Feature (1 uur)**
|
||||||
|
|
||||||
Focus op:
|
Implementeer de AI chat die past bij je eindproject:
|
||||||
1. Features compleet maken
|
|
||||||
2. Bugs fixen
|
|
||||||
3. Documentatie bijwerken
|
|
||||||
4. Testen in productie
|
|
||||||
|
|
||||||
**Bereid vragen voor:**
|
| Project | AI Feature |
|
||||||
Schrijf op waar je hulp bij nodig hebt voor Les 18 (werksessie).
|
|---------|-----------|
|
||||||
|
| Recipe Generator | "Wat kan ik maken met kip en rijst?" |
|
||||||
|
| Budget Buddy | "Analyseer mijn uitgaven deze maand" |
|
||||||
|
| Travel Planner | "Plan een weekend Barcelona" |
|
||||||
|
|
||||||
|
- Custom system prompt
|
||||||
|
- Context uit je database meegeven
|
||||||
|
|
||||||
|
**Deel 2: UX Polish (30 min)**
|
||||||
|
|
||||||
|
Voeg toe:
|
||||||
|
- Streaming indicator
|
||||||
|
- Suggested prompts / quick actions
|
||||||
|
- Copy response button
|
||||||
|
- Clear chat button
|
||||||
|
- Error handling
|
||||||
|
|
||||||
|
**Deel 3: Documentatie (30 min)**
|
||||||
|
|
||||||
|
Maak `docs/AI-FEATURE.md`:
|
||||||
|
- Welke AI feature heb je gebouwd?
|
||||||
|
- Wat doet de system prompt?
|
||||||
|
- Hoe integreert het met Supabase?
|
||||||
|
- Welke model keuzes heb je gemaakt?
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Voortgang op eindopdracht
|
- AI feature in eindproject
|
||||||
- Lijst met vragen voor Les 18
|
- Deployed preview
|
||||||
|
- AI-FEATURE.md documentatie
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- De eindopdracht requirements begrijpen
|
- Vercel AI SDK installeren en configureren
|
||||||
- Een realistische planning maken
|
- `useChat` en `useCompletion` hooks gebruiken
|
||||||
- Prioriteiten stellen voor afronden
|
- Streaming responses implementeren
|
||||||
- Eigen voortgang eerlijk inschatten
|
- API routes opzetten voor AI providers
|
||||||
- Hulp vragen waar nodig
|
- Custom system prompts schrijven
|
||||||
|
- Chat history opslaan in Supabase
|
||||||
|
- Error handling en loading states implementeren
|
||||||
|
- Kostenbewust omgaan met AI APIs
|
||||||
|
|||||||
@@ -1,152 +1,276 @@
|
|||||||
# Les 18: Eindproject Werksessie
|
# Les 18: Deployment & Production + Eindopdracht
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Hoofdstuk
|
## Hoofdstuk
|
||||||
**Hoofdstuk 3: Advanced** (Les 10-18)
|
**Deel 4: Advanced AI Features** (Les 13-18)
|
||||||
|
|
||||||
## Beschrijving
|
## Beschrijving
|
||||||
Werksessie voor het afronden van je eindproject. Geen nieuwe theorie - focus op bouwen, vragen stellen, en hulp krijgen.
|
Deploy je eindproject naar productie. Leer environment variables, Vercel deployment, en basis performance optimalisatie. Bespreking van de eindopdracht requirements en afrondende werksessie.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Opzet van de Les
|
## Te Behandelen
|
||||||
|
|
||||||
### Korte Standup (15 min)
|
### Groepsdiscussie (15 min)
|
||||||
|
Bespreek klassikaal de AI feature ervaringen uit Les 17 - welke system prompts werkten goed en welke challenges kwamen jullie tegen?
|
||||||
|
|
||||||
**Elke student deelt (max 1 minuut):**
|
### Vercel Deployment Flow
|
||||||
1. Waar sta ik?
|
|
||||||
2. Wat is mijn grootste blocker?
|
|
||||||
3. Wat wil ik vandaag afronden?
|
|
||||||
|
|
||||||
### Werktijd (1u 45min)
|
**Hoe Vercel werkt:**
|
||||||
|
1. Connect GitHub repository
|
||||||
|
2. Push naar main → automatische deploy
|
||||||
|
3. Push naar andere branch → preview URL
|
||||||
|
4. Alles automatisch (build, SSL, CDN)
|
||||||
|
|
||||||
**Studenten werken zelfstandig:**
|
**Waarom Vercel voor Next.js:**
|
||||||
- Docent loopt rond
|
- Gemaakt door dezelfde makers
|
||||||
- Vraag hulp wanneer nodig
|
- Zero-config deployment
|
||||||
- Peer support aangemoedigd
|
- Gratis tier ruim voldoende
|
||||||
|
- Automatische HTTPS
|
||||||
**Focus gebieden:**
|
- Global CDN
|
||||||
- Features afronden
|
|
||||||
- Bugs fixen
|
|
||||||
- Documentatie completeren
|
|
||||||
- Deployment issues oplossen
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Veelvoorkomende Problemen
|
### Environment Variables in Vercel
|
||||||
|
|
||||||
### AI Chat Werkt Niet
|
**Lokaal (.env.local) vs Productie (Vercel Dashboard):**
|
||||||
|
|
||||||
**Check:**
|
| Waar | Bestand/Locatie | Voorbeeld |
|
||||||
|
|------|-----------------|-----------|
|
||||||
|
| Lokaal | `.env.local` | Development |
|
||||||
|
| Vercel | Dashboard → Settings → Env Vars | Production |
|
||||||
|
|
||||||
|
**Stap voor stap:**
|
||||||
|
1. Ga naar je Vercel project
|
||||||
|
2. Settings → Environment Variables
|
||||||
|
3. Voeg toe:
|
||||||
|
- `NEXT_PUBLIC_SUPABASE_URL`
|
||||||
|
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
||||||
|
- `OPENAI_API_KEY`
|
||||||
|
4. Selecteer environment (Production, Preview, Development)
|
||||||
|
5. Save & Redeploy
|
||||||
|
|
||||||
|
**Let op:**
|
||||||
|
- `NEXT_PUBLIC_` prefix = zichtbaar in browser
|
||||||
|
- Zonder prefix = alleen server-side (API routes)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Supabase Productie Setup
|
||||||
|
|
||||||
|
**Redirect URLs configureren:**
|
||||||
|
1. Ga naar Supabase → Authentication → URL Configuration
|
||||||
|
2. Voeg toe bij "Redirect URLs":
|
||||||
|
- `https://jouw-app.vercel.app/**`
|
||||||
|
- `https://jouw-app.vercel.app`
|
||||||
|
|
||||||
|
**Waarom:**
|
||||||
|
- Auth redirects werken alleen naar toegestane URLs
|
||||||
|
- Wildcards (`**`) voor sub-routes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Deployment Checklist
|
||||||
|
|
||||||
|
**Voor deployment:**
|
||||||
|
- [ ] `npm run build` werkt lokaal
|
||||||
|
- [ ] Geen TypeScript errors
|
||||||
|
- [ ] Environment variables gedocumenteerd in `.env.example`
|
||||||
|
- [ ] `.gitignore` bevat `.env*.local`
|
||||||
|
- [ ] README up-to-date
|
||||||
|
|
||||||
|
**Na deployment:**
|
||||||
|
- [ ] App laadt correct
|
||||||
|
- [ ] Auth werkt (login/logout)
|
||||||
|
- [ ] Data wordt opgehaald uit Supabase
|
||||||
|
- [ ] AI features werken (indien van toepassing)
|
||||||
|
- [ ] Geen console errors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Performance Basics
|
||||||
|
|
||||||
|
**Lighthouse Audit:**
|
||||||
|
1. Open Chrome DevTools
|
||||||
|
2. Tab "Lighthouse"
|
||||||
|
3. Klik "Analyze page load"
|
||||||
|
4. Aim for score >80 in elke categorie
|
||||||
|
|
||||||
|
**Quick wins:**
|
||||||
|
- Gebruik Next.js `Image` component (niet `<img>`)
|
||||||
|
- Lazy load components die niet direct nodig zijn
|
||||||
|
- Verwijder ongebruikte dependencies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Security Checklist
|
||||||
|
|
||||||
|
**Belangrijk voor productie:**
|
||||||
|
- [ ] API keys nooit in client-side code
|
||||||
|
- [ ] Supabase RLS enabled (Row Level Security)
|
||||||
|
- [ ] Error messages geven geen gevoelige info
|
||||||
|
- [ ] HTTPS (automatisch via Vercel)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Eindopdracht Overview
|
||||||
|
|
||||||
|
### Wat is de eindopdracht?
|
||||||
|
- Bouw een AI-powered web applicatie
|
||||||
|
- Gebruik alle tools die je hebt geleerd
|
||||||
|
- Vrije keuze in implementatie
|
||||||
|
|
||||||
|
**Drie voorbeeldprojecten:**
|
||||||
|
1. **AI Recipe Generator** - Recepten op basis van ingrediënten
|
||||||
|
2. **Smart Budget Buddy** - Financieel overzicht met AI insights
|
||||||
|
3. **Travel Planner AI** - Reisplanning met AI suggesties
|
||||||
|
|
||||||
|
**Of:** Eigen idee (met goedkeuring docent)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Technische Vereisten
|
||||||
|
|
||||||
|
**Stack:**
|
||||||
|
- Next.js 14 met App Router
|
||||||
|
- TypeScript
|
||||||
|
- Tailwind CSS
|
||||||
|
- Supabase (database + auth)
|
||||||
|
- Vercel AI SDK (chat of completion feature)
|
||||||
|
- Deployed op Vercel
|
||||||
|
|
||||||
|
**Documentatie vereisten:**
|
||||||
|
- `docs/PROJECT-BRIEF.md` - Project beschrijving
|
||||||
|
- `docs/PROMPT-LOG.md` - Minimaal 10 prompts
|
||||||
|
- `docs/AI-DECISIONS.md` - Minimaal 5 beslissingen
|
||||||
|
- Complete README met setup instructies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Beoordelingscriteria
|
||||||
|
|
||||||
|
| Criterium | Weging |
|
||||||
|
|-----------|--------|
|
||||||
|
| Technische uitvoering | 40% |
|
||||||
|
| AI integratie | 25% |
|
||||||
|
| Documentatie (PROMPT-LOG, AI-DECISIONS) | 20% |
|
||||||
|
| Code kwaliteit & organisatie | 15% |
|
||||||
|
|
||||||
|
**Minimale vereisten:**
|
||||||
|
- App werkt in productie
|
||||||
|
- Auth + CRUD werkt
|
||||||
|
- AI feature werkt
|
||||||
|
- Documentatie compleet
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Veelvoorkomende Problemen
|
||||||
|
|
||||||
|
**AI Chat Werkt Niet:**
|
||||||
1. API key correct in `.env.local`?
|
1. API key correct in `.env.local`?
|
||||||
2. API key ook in Vercel env vars?
|
2. API key ook in Vercel env vars?
|
||||||
3. Correct model gekozen?
|
3. Correct model gekozen?
|
||||||
4. API route syntax correct?
|
4. API route syntax correct?
|
||||||
|
|
||||||
### Auth Werkt Niet in Productie
|
**Auth Werkt Niet in Productie:**
|
||||||
|
|
||||||
**Check:**
|
|
||||||
1. Redirect URLs in Supabase toegevoegd?
|
1. Redirect URLs in Supabase toegevoegd?
|
||||||
2. Beide URLs: met en zonder trailing slash?
|
2. Beide URLs: met en zonder trailing slash?
|
||||||
3. Wildcard (`**`) voor sub-routes?
|
3. Wildcard (`**`) voor sub-routes?
|
||||||
|
|
||||||
### Deployment Faalt
|
**Deployment Faalt:**
|
||||||
|
|
||||||
**Check:**
|
|
||||||
1. `npm run build` lokaal succesvol?
|
1. `npm run build` lokaal succesvol?
|
||||||
2. Alle TypeScript errors gefixed?
|
2. Alle TypeScript errors gefixed?
|
||||||
3. Alle env vars in Vercel?
|
3. Alle env vars in Vercel?
|
||||||
|
|
||||||
### Supabase Data Toont Niet
|
|
||||||
|
|
||||||
**Check:**
|
|
||||||
1. RLS policies correct?
|
|
||||||
2. Correct env vars?
|
|
||||||
3. Supabase client correct geïnitialiseerd?
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentatie Checklist
|
|
||||||
|
|
||||||
**PROMPT-LOG.md (minimaal 10 entries):**
|
|
||||||
- [ ] Prompts die goed werkten
|
|
||||||
- [ ] Prompts die NIET werkten (en wat je leerde)
|
|
||||||
- [ ] Verschillende tools gebruikt
|
|
||||||
|
|
||||||
**AI-DECISIONS.md (minimaal 5 entries):**
|
|
||||||
- [ ] Database schema beslissing
|
|
||||||
- [ ] UI/UX keuzes
|
|
||||||
- [ ] Technische trade-offs
|
|
||||||
- [ ] Problemen en oplossingen
|
|
||||||
|
|
||||||
**README.md:**
|
|
||||||
- [ ] Project beschrijving
|
|
||||||
- [ ] Features lijst
|
|
||||||
- [ ] Tech stack
|
|
||||||
- [ ] Setup instructies
|
|
||||||
- [ ] Productie URL
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Peer Review (optioneel)
|
|
||||||
|
|
||||||
**Als je klaar bent, help een klasgenoot:**
|
|
||||||
1. Test hun app
|
|
||||||
2. Geef feedback
|
|
||||||
3. Help met bugs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Afsluiting (laatste 10 min)
|
|
||||||
|
|
||||||
**Check-out:**
|
|
||||||
- Wie is klaar?
|
|
||||||
- Wie heeft nog vragen?
|
|
||||||
- Deadline reminder
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
- Vercel
|
||||||
|
- GitHub
|
||||||
|
- Supabase
|
||||||
|
- Chrome DevTools (Lighthouse)
|
||||||
- Cursor
|
- Cursor
|
||||||
- Alle geleerde tools
|
|
||||||
- Elkaar!
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lesopdracht (2 uur)
|
## Lesopdracht (2 uur)
|
||||||
|
|
||||||
### Werk aan je Eindproject
|
### Deploy Je Eindproject
|
||||||
|
|
||||||
**Dit is WERKTIJD.**
|
**Deel 1: Pre-Deployment Check (30 min)**
|
||||||
|
|
||||||
Er is geen specifieke opdracht behalve: werk aan je eindproject.
|
Run door de checklist:
|
||||||
|
1. `npm run build` - fix eventuele errors
|
||||||
|
2. Check TypeScript errors
|
||||||
|
3. Maak/update `.env.example`
|
||||||
|
4. Update README met project info
|
||||||
|
|
||||||
**Prioriteiten:**
|
**Deel 2: Vercel Deployment (30 min)**
|
||||||
1. ❌ Wat werkt nog niet? → Fix het
|
|
||||||
2. ✅ Wat werkt al? → Maak het af
|
|
||||||
3. 📝 Documentatie → Vul aan
|
|
||||||
|
|
||||||
**Vraag hulp:**
|
1. Ga naar [vercel.com](https://vercel.com)
|
||||||
- Als je langer dan 15 minuten vastloopt
|
2. "Add New Project"
|
||||||
- Als je niet weet waar te beginnen
|
3. Import je GitHub repository
|
||||||
- Als je feedback wilt op je aanpak
|
4. Voeg environment variables toe
|
||||||
|
5. Deploy!
|
||||||
|
|
||||||
**Aan het eind van de les:**
|
**Deel 3: Supabase Config (20 min)**
|
||||||
- App werkt in productie
|
|
||||||
- Of: je weet precies wat nog moet gebeuren
|
1. Voeg Vercel URL toe aan Supabase redirect URLs
|
||||||
|
2. Test auth in productie
|
||||||
|
3. Verifieer data access
|
||||||
|
|
||||||
|
**Deel 4: Testing & Lighthouse (40 min)**
|
||||||
|
|
||||||
|
1. Test alle features in productie:
|
||||||
|
- Login/logout
|
||||||
|
- CRUD operaties
|
||||||
|
- AI chat (indien aanwezig)
|
||||||
|
2. Run Lighthouse audit
|
||||||
|
3. Fix issues tot score >80
|
||||||
|
4. Screenshot resultaat
|
||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Voortgang op eindproject
|
- Werkende productie URL
|
||||||
- Duidelijk beeld van wat nog moet
|
- Lighthouse screenshot (score >80)
|
||||||
|
- Test rapport: wat werkt, wat niet
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Huiswerk
|
## Huiswerk (Eindopdracht Afronden)
|
||||||
|
|
||||||
### Rond Je Eindproject Af
|
### Rond Je Eindproject Af
|
||||||
|
|
||||||
**Dit is de laatste les. Alles wat nog moet, doe je zelfstandig.**
|
**Dit is de laatste les. Gebruik deze tijd om je eindopdracht af te ronden.**
|
||||||
|
|
||||||
|
**Deel 1: Bug Fixes (1 uur)**
|
||||||
|
|
||||||
|
1. Test je app grondig in productie
|
||||||
|
2. Fix gevonden bugs
|
||||||
|
3. Test edge cases:
|
||||||
|
- Lege states
|
||||||
|
- Error states
|
||||||
|
- Loading states
|
||||||
|
4. Redeploy
|
||||||
|
|
||||||
|
**Deel 2: Performance Optimization (30 min)**
|
||||||
|
|
||||||
|
1. Run Lighthouse opnieuw
|
||||||
|
2. Fix top 3 performance issues
|
||||||
|
3. Document wat je hebt verbeterd
|
||||||
|
|
||||||
|
**Deel 3: Documentatie Afronden (30 min)**
|
||||||
|
|
||||||
|
Update je `README.md`:
|
||||||
|
- Werkende productie URL
|
||||||
|
- Features lijst
|
||||||
|
- Tech stack
|
||||||
|
- Setup instructies
|
||||||
|
- Screenshots
|
||||||
|
|
||||||
|
Complete `docs/`:
|
||||||
|
- PROMPT-LOG.md (minimaal 10 entries)
|
||||||
|
- AI-DECISIONS.md (minimaal 5 entries)
|
||||||
|
|
||||||
**Checklist voor inleveren:**
|
**Checklist voor inleveren:**
|
||||||
- [ ] App werkt op productie URL
|
- [ ] App werkt op productie URL
|
||||||
@@ -165,14 +289,20 @@ Er is geen specifieke opdracht behalve: werk aan je eindproject.
|
|||||||
|
|
||||||
### Deliverable
|
### Deliverable
|
||||||
- Complete eindopdracht
|
- Complete eindopdracht
|
||||||
|
- Deployed en werkend
|
||||||
|
- Alle documentatie compleet
|
||||||
- Ingeleverd voor deadline
|
- Ingeleverd voor deadline
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Leerdoelen
|
## Leerdoelen
|
||||||
Na deze les kan de student:
|
Na deze les kan de student:
|
||||||
- Zelfstandig problemen oplossen
|
- Een Next.js app deployen naar Vercel
|
||||||
- Hulp vragen wanneer nodig
|
- Environment variables configureren in Vercel
|
||||||
|
- Supabase redirect URLs instellen voor productie
|
||||||
|
- Een deployment checklist doorlopen
|
||||||
|
- Lighthouse gebruiken voor performance audit
|
||||||
|
- Basis security checks uitvoeren
|
||||||
|
- De eindopdracht requirements begrijpen
|
||||||
- Een project afronden en inleveren
|
- Een project afronden en inleveren
|
||||||
- Documentatie completeren
|
- Documentatie voltooien volgens de vereisten
|
||||||
- Peer feedback geven en ontvangen
|
|
||||||
|
|||||||
524
readme.md
524
readme.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered developer.
|
Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered developer.
|
||||||
|
|
||||||
**Totaal: 30 EC** verdeeld over 3 delen.
|
**Totaal: 30 EC** verdeeld over 4 delen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -13,39 +13,40 @@ Een 18-weekse cursus die studenten meeneemt van AI-beginner naar AI-powered deve
|
|||||||
| 01 | [Introductie tot AI en Large Language Models](Samenvattingen/Les01-Samenvatting.md) | 1 | ✅ Uitgewerkt |
|
| 01 | [Introductie tot AI en Large Language Models](Samenvattingen/Les01-Samenvatting.md) | 1 | ✅ Uitgewerkt |
|
||||||
| 02 | [AI Code Assistants en OpenCode Desktop App](Samenvattingen/Les02-Samenvatting.md) | 1 | 📋 Samenvatting |
|
| 02 | [AI Code Assistants en OpenCode Desktop App](Samenvattingen/Les02-Samenvatting.md) | 1 | 📋 Samenvatting |
|
||||||
| 03 | [AI Ethics, Privacy & Security + WebStorm](Samenvattingen/Les03-Samenvatting.md) | 1 | 📋 Samenvatting |
|
| 03 | [AI Ethics, Privacy & Security + WebStorm](Samenvattingen/Les03-Samenvatting.md) | 1 | 📋 Samenvatting |
|
||||||
| 04 | [Effectief Prompting, Iteratief Werken & Skills](Samenvattingen/Les04-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 04 | [Effectief Prompting, Iteratief Werken & Skills](Samenvattingen/Les04-Samenvatting.md) | 1 | 📋 Samenvatting |
|
||||||
| 05 | [AI Tool Selection & Workflows](Samenvattingen/Les05-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 05 | [TypeScript Basics](Samenvattingen/Les05-Samenvatting.md) | 2 | 📋 Samenvatting |
|
||||||
| 06 | [Hands-on: Van Idee naar Prototype](Samenvattingen/Les06-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 06 | [Next.js Fundamentals 1: SSR & Routing](Samenvattingen/Les06-Samenvatting.md) | 2 | 📋 Samenvatting |
|
||||||
| 07 | [Next.js Project Setup](Samenvattingen/Les07-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 07 | [Next.js Fundamentals 2: API Routes & Data Fetching](Samenvattingen/Les07-Samenvatting.md) | 2 | 📋 Samenvatting |
|
||||||
| 08 | [Supabase Basics](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 08 | [Database Principles](Samenvattingen/Les08-Samenvatting.md) | 2 | 📋 Samenvatting |
|
||||||
| 09 | [AI Agents - Custom GPTs & Claude Projects](Samenvattingen/Les09-Samenvatting.md) | 2 | 📋 Samenvatting |
|
| 09 | [Supabase Basics](Samenvattingen/Les09-Samenvatting.md) | 2 | 📋 Samenvatting |
|
||||||
| 10 | [Introduction to Cursor](Samenvattingen/Les10-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 10 | [AI Tool Selection & Workflows](Samenvattingen/Les10-Samenvatting.md) | 3 | 📋 Samenvatting |
|
||||||
| 11 | [Project Setup & Repository Structure](Samenvattingen/Les11-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 11 | [Hands-on: Van Idee naar Prototype](Samenvattingen/Les11-Samenvatting.md) | 3 | 📋 Samenvatting |
|
||||||
| 12 | [MCP & Context Management](Samenvattingen/Les12-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 12 | [Introduction to Cursor](Samenvattingen/Les12-Samenvatting.md) | 3 | 📋 Samenvatting |
|
||||||
| 13 | [Mastering Cursor](Samenvattingen/Les13-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 13 | [AI Agents - Custom GPTs & Claude Projects](Samenvattingen/Les13-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
| 14 | [Debugging & Code Review met AI](Samenvattingen/Les14-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 14 | [Project Setup & Repository Structure](Samenvattingen/Les14-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
| 15 | [Vercel AI SDK - AI Features in je App](Samenvattingen/Les15-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 15 | [MCP & Context Management](Samenvattingen/Les15-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
| 16 | [Deployment & Production](Samenvattingen/Les16-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 16 | [Mastering Cursor](Samenvattingen/Les16-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
| 17 | [Eindopdracht Kickoff](Samenvattingen/Les17-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 17 | [Vercel AI SDK - AI Features in je App](Samenvattingen/Les17-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
| 18 | [Eindproject Werksessie](Samenvattingen/Les18-Samenvatting.md) | 3 | 📋 Samenvatting |
|
| 18 | [Deployment & Production](Samenvattingen/Les18-Samenvatting.md) | 4 | 📋 Samenvatting |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tool Progressie
|
## Tool Progressie
|
||||||
|
|
||||||
| Deel | Tools | Kosten |
|
| Deel | Lessen | Tools | Kosten |
|
||||||
|------|-------|--------|
|
|------|--------|-------|--------|
|
||||||
| Deel 1 | ChatGPT, v0.dev, OpenCode, WebStorm | Gratis (WebStorm via school) |
|
| Deel 1: AI Foundations | 1-4 | ChatGPT, v0.dev, OpenCode, WebStorm | Gratis (WebStorm via school) |
|
||||||
| Deel 2 | OpenCode, Claude Desktop, Skills.sh | Gratis |
|
| Deel 2: Technical Foundations | 5-9 | TypeScript, Next.js, React Query, Supabase | Gratis |
|
||||||
| Deel 3 | Cursor | Free tier beschikbaar |
|
| Deel 3: AI Tooling & Prototyping | 10-12 | ChatGPT, Claude, v0.dev, OpenCode, Cursor | Free tier beschikbaar |
|
||||||
|
| Deel 4: Advanced AI Features | 13-18 | Cursor, Claude Projects, Custom GPTs, Vercel AI SDK | Free tier beschikbaar |
|
||||||
|
|
||||||
**Eindopdracht:** Cursor (free tier voldoende)
|
**Eindopdracht:** Cursor (free tier voldoende)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Deel 1: Fundamentals of AI-Driven Development
|
# Deel 1: AI Foundations
|
||||||
|
|
||||||
**3 lessen · 5 EC**
|
**4 lessen · 5 EC**
|
||||||
|
|
||||||
Kennismaking met AI, LLMs en de basis van AI-assisted development.
|
Kennismaking met AI, LLMs en de basis van AI-assisted development.
|
||||||
|
|
||||||
@@ -94,7 +95,10 @@ Kennismaking met AI, LLMs en de basis van AI-assisted development.
|
|||||||
|
|
||||||
**Lesopdracht:** Installeer OpenCode, koppel gratis model, bouw responsive navbar component met AI assistance, experimenteer met verschillende prompts.
|
**Lesopdracht:** Installeer OpenCode, koppel gratis model, bouw responsive navbar component met AI assistance, experimenteer met verschillende prompts.
|
||||||
|
|
||||||
**Huiswerk:** Bouw landing page component library (hero, features, testimonial, CTA, footer), schrijf blog post over ervaring met OpenCode (300 woorden).
|
**Huiswerk:**
|
||||||
|
- Bouw landing page component library (hero, features, testimonial, CTA, footer)
|
||||||
|
- Schrijf blog post over ervaring met OpenCode (300 woorden)
|
||||||
|
- **Optioneel:** Heb je het gevoel dat je React-kennis wat is weggezakt? Gebruik de eerste twee weken ook om React Fundamentals op EdHub te herhalen.
|
||||||
|
|
||||||
[→ Ga naar Les 2](Samenvattingen/Les02-Samenvatting.md)
|
[→ Ga naar Les 2](Samenvattingen/Les02-Samenvatting.md)
|
||||||
|
|
||||||
@@ -112,6 +116,7 @@ Kennismaking met AI, LLMs en de basis van AI-assisted development.
|
|||||||
- WebStorm als professionele IDE
|
- WebStorm als professionele IDE
|
||||||
|
|
||||||
**Studenten doen:**
|
**Studenten doen:**
|
||||||
|
- **Groepsdiscussie:** Bespreek klassikaal de reflecties over AI van Les 1 - wat zijn de voor- en nadelen die jullie zien?
|
||||||
- Security workshop: identificeer problemen in AI-generated code
|
- Security workshop: identificeer problemen in AI-generated code
|
||||||
- Maak persoonlijke "AI Safety Checklist"
|
- Maak persoonlijke "AI Safety Checklist"
|
||||||
- WebStorm installeren met school licentie
|
- WebStorm installeren met school licentie
|
||||||
@@ -125,16 +130,6 @@ Kennismaking met AI, LLMs en de basis van AI-assisted development.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Deel 2: Intermediate AI-Driven Development
|
|
||||||
|
|
||||||
**6 lessen · 10 EC**
|
|
||||||
|
|
||||||
Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase en AI agents.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.1 Prompt Engineering & Consolidatie
|
|
||||||
|
|
||||||
### Les 4: Effectief Prompting, Iteratief Werken & Skills
|
### Les 4: Effectief Prompting, Iteratief Werken & Skills
|
||||||
|
|
||||||
**Tools:** OpenCode/WebStorm, Skills.sh
|
**Tools:** OpenCode/WebStorm, Skills.sh
|
||||||
@@ -147,6 +142,7 @@ Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase e
|
|||||||
- Iteratief werken: start simpel → voeg complexiteit toe
|
- Iteratief werken: start simpel → voeg complexiteit toe
|
||||||
|
|
||||||
**Studenten doen:**
|
**Studenten doen:**
|
||||||
|
- **Groepsdiscussie:** Bespreek klassikaal ervaringen met OpenCode - wat werkte, wat niet?
|
||||||
- Verschillende prompt technieken uitproberen
|
- Verschillende prompt technieken uitproberen
|
||||||
- Skills.sh installeren en eerste skill toevoegen
|
- Skills.sh installeren en eerste skill toevoegen
|
||||||
- Vergelijk output met/zonder skill
|
- Vergelijk output met/zonder skill
|
||||||
@@ -160,7 +156,191 @@ Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase e
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Les 5: AI Tool Selection & Workflows
|
# Deel 2: Technical Foundations
|
||||||
|
|
||||||
|
**5 lessen · 10 EC**
|
||||||
|
|
||||||
|
Stevige technische basis: TypeScript, Next.js, databases en Supabase.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 5: TypeScript Basics
|
||||||
|
|
||||||
|
**Tools:** OpenCode/WebStorm, TypeScript
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Waarom TypeScript? Voordelen boven JavaScript
|
||||||
|
- Basic types: string, number, boolean, array, object
|
||||||
|
- Type inference: wanneer TypeScript types zelf raadt
|
||||||
|
- Interfaces en type aliases
|
||||||
|
- TypeScript met React: Props typen, useState met types
|
||||||
|
- Generics basics (Array<T>, Promise<T>)
|
||||||
|
- Veel voorkomende TypeScript errors en hoe ze op te lossen
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- JavaScript file omzetten naar TypeScript
|
||||||
|
- Interfaces schrijven voor eigen data
|
||||||
|
- React component met typed props maken
|
||||||
|
- TypeScript errors debuggen
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. Zet bestaand JS component om naar TypeScript
|
||||||
|
2. Maak interface voor User en Product data
|
||||||
|
3. Bouw typed React component met props
|
||||||
|
4. Fix 5 TypeScript errors in gegeven code
|
||||||
|
|
||||||
|
**Huiswerk:** Maak 3 nieuwe components volledig in TypeScript, schrijf interfaces voor je eindproject data, maak cheat sheet met TypeScript patterns.
|
||||||
|
|
||||||
|
[→ Ga naar Les 5](Samenvattingen/Les05-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 6: Next.js Fundamentals 1 - SSR & Routing
|
||||||
|
|
||||||
|
**Tools:** Next.js 14, OpenCode/WebStorm, Vercel
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Wat is Next.js? React framework met superpowers
|
||||||
|
- Server-Side Rendering (SSR) vs Client-Side Rendering (CSR)
|
||||||
|
- Waarom SSR? SEO, performance, initial load
|
||||||
|
- App Router: file-based routing uitgelegd
|
||||||
|
- Folder structuur: app/, pages, layouts, loading, error
|
||||||
|
- Dynamic routes: [id], [...slug], [[...optional]]
|
||||||
|
- Link component en navigation
|
||||||
|
- Metadata en SEO basics
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- Next.js project aanmaken met `npx create-next-app@latest`
|
||||||
|
- Pagina's maken met App Router
|
||||||
|
- Layout en nested layouts implementeren
|
||||||
|
- Dynamic routes bouwen
|
||||||
|
- Navigation met Link component
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. `npx create-next-app@latest` met TypeScript + Tailwind + App Router
|
||||||
|
2. Maak 4 pagina's: home, about, products, contact
|
||||||
|
3. Maak root layout met Header en Footer
|
||||||
|
4. Maak `/products/[id]` dynamic route
|
||||||
|
5. Deploy naar Vercel
|
||||||
|
|
||||||
|
**Huiswerk:** Voeg nested layout toe voor products section, maak loading.tsx en error.tsx, experimenteer met metadata.
|
||||||
|
|
||||||
|
[→ Ga naar Les 6](Samenvattingen/Les06-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 7: Next.js Fundamentals 2 - API Routes & Data Fetching
|
||||||
|
|
||||||
|
**Tools:** Next.js 14, React Query (TanStack Query), OpenCode
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Server Components vs Client Components
|
||||||
|
- 'use client' directive: wanneer en waarom
|
||||||
|
- Data fetching in Server Components (async/await)
|
||||||
|
- API Routes: Route Handlers in App Router
|
||||||
|
- GET, POST, PUT, DELETE requests
|
||||||
|
- React Query: waarom, installatie, basics
|
||||||
|
- useQuery en useMutation hooks
|
||||||
|
- Caching en revalidation basics
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- Server Component met data fetching maken
|
||||||
|
- API route schrijven
|
||||||
|
- Client Component met React Query
|
||||||
|
- CRUD operations via API routes
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. Maak `/api/products` route met GET en POST
|
||||||
|
2. Bouw Server Component die products fetcht
|
||||||
|
3. Installeer React Query, maak QueryClientProvider
|
||||||
|
4. Bouw Client Component met useQuery
|
||||||
|
5. Implementeer useMutation voor product toevoegen
|
||||||
|
|
||||||
|
**Huiswerk:** Voeg PUT en DELETE toe aan API, implementeer optimistic updates met React Query, bouw complete CRUD interface.
|
||||||
|
|
||||||
|
[→ Ga naar Les 7](Samenvattingen/Les07-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 8: Database Principles
|
||||||
|
|
||||||
|
**Tools:** Diagramming tool (draw.io/Excalidraw), Supabase (ter voorbereiding)
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Wat is een relationele database?
|
||||||
|
- Tabellen, rijen (records), kolommen (fields)
|
||||||
|
- Primary Keys: unieke identificatie
|
||||||
|
- Foreign Keys: relaties tussen tabellen
|
||||||
|
- Relatie types: one-to-one, one-to-many, many-to-many
|
||||||
|
- Normalisatie basics: waarom data niet dupliceren
|
||||||
|
- Data types: text, integer, boolean, timestamp, uuid
|
||||||
|
- NULL values en defaults
|
||||||
|
- Indexen: waarom en wanneer
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- Database schema tekenen voor simpel project
|
||||||
|
- Relaties identificeren en documenteren
|
||||||
|
- Normalisatie oefening: slechte structuur verbeteren
|
||||||
|
- Primary en Foreign Keys bepalen
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. Teken database schema voor "Blog met Comments" (users, posts, comments)
|
||||||
|
2. Identificeer alle relaties en key types
|
||||||
|
3. Normaliseer een "slechte" database structuur (gegeven)
|
||||||
|
4. Schrijf data types en constraints op
|
||||||
|
5. Bereid voor: welke tabellen heeft jouw eindproject nodig?
|
||||||
|
|
||||||
|
**Huiswerk:** Maak volledig database schema voor je eindproject, documenteer alle relaties, bereid Supabase account aan voor volgende les.
|
||||||
|
|
||||||
|
[→ Ga naar Les 8](Samenvattingen/Les08-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 9: Supabase Basics
|
||||||
|
|
||||||
|
**Tools:** Supabase, Next.js, OpenCode
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Wat is Supabase? (database + auth in één)
|
||||||
|
- Supabase project aanmaken (live demo)
|
||||||
|
- Table Editor: tabellen maken zonder SQL
|
||||||
|
- Je database schema van vorige les implementeren
|
||||||
|
- Environment variables: wat, waarom, hoe
|
||||||
|
- Supabase client setup
|
||||||
|
- CRUD operaties uitgelegd
|
||||||
|
- Auth UI component (plug & play login)
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- **Groepsdiscussie:** Bespreek database schemas - wie heeft welke structuur gekozen en waarom?
|
||||||
|
- Supabase account en project aanmaken
|
||||||
|
- Tabellen maken via UI (gebaseerd op Les 8 schema)
|
||||||
|
- `.env.local` configureren
|
||||||
|
- Supabase client maken
|
||||||
|
- Data ophalen en tonen
|
||||||
|
- Auth toevoegen
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. Maak Supabase project
|
||||||
|
2. Maak je tabellen via Table Editor (uit Les 8)
|
||||||
|
3. Configureer `.env.local`
|
||||||
|
4. Bouw Todo app: lijst tonen, toevoegen, afvinken, verwijderen
|
||||||
|
5. Voeg login toe met Auth UI
|
||||||
|
|
||||||
|
**Huiswerk:** Extend Todo app (filtering, user-specifieke todos), deploy naar Vercel met env vars, test in productie.
|
||||||
|
|
||||||
|
[→ Ga naar Les 9](Samenvattingen/Les09-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deel 3: AI Tooling & Prototyping
|
||||||
|
|
||||||
|
**3 lessen · 5 EC**
|
||||||
|
|
||||||
|
AI tools effectief inzetten voor professionele development.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 10: AI Tool Selection & Workflows
|
||||||
|
|
||||||
**Tools:** ChatGPT, Claude, v0.dev, OpenCode
|
**Tools:** ChatGPT, Claude, v0.dev, OpenCode
|
||||||
|
|
||||||
@@ -188,11 +368,11 @@ Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase e
|
|||||||
|
|
||||||
**Huiswerk:** Maak je eigen "Tool Selection Cheat Sheet", test het op 2 nieuwe taken, reflecteer op je workflow (400 woorden).
|
**Huiswerk:** Maak je eigen "Tool Selection Cheat Sheet", test het op 2 nieuwe taken, reflecteer op je workflow (400 woorden).
|
||||||
|
|
||||||
[→ Ga naar Les 5](Samenvattingen/Les05-Samenvatting.md)
|
[→ Ga naar Les 10](Samenvattingen/Les10-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Les 6: Hands-on: Van Idee naar Prototype
|
### Les 11: Hands-on: Van Idee naar Prototype
|
||||||
|
|
||||||
**Tools:** OpenCode/WebStorm, ChatGPT (voor planning)
|
**Tools:** OpenCode/WebStorm, ChatGPT (voor planning)
|
||||||
|
|
||||||
@@ -204,6 +384,7 @@ Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase e
|
|||||||
- Korte demo van het proces
|
- Korte demo van het proces
|
||||||
|
|
||||||
**Studenten doen:**
|
**Studenten doen:**
|
||||||
|
- **Groepsdiscussie:** Bespreek Tool Selection reflecties - welke workflows werken het beste?
|
||||||
- Kiezen van een simpel project idee
|
- Kiezen van een simpel project idee
|
||||||
- Met AI features breakdown maken
|
- Met AI features breakdown maken
|
||||||
- Component structuur bedenken
|
- Component structuur bedenken
|
||||||
@@ -217,122 +398,13 @@ Verdieping in prompt engineering, hands-on bouwen, en introductie tot Supabase e
|
|||||||
|
|
||||||
**Lesopdracht:** Kies een mini-project, maak feature breakdown met AI, bouw werkend prototype. Documenteer je proces: welke prompts werkten, waar liep je vast, hoe loste je het op.
|
**Lesopdracht:** Kies een mini-project, maak feature breakdown met AI, bouw werkend prototype. Documenteer je proces: welke prompts werkten, waar liep je vast, hoe loste je het op.
|
||||||
|
|
||||||
**Huiswerk:** Verbeter je prototype (styling, edge cases), schrijf "Lessons Learned" document (300 woorden), bereid je voor op Les 7 (Next.js).
|
**Huiswerk:** Verbeter je prototype (styling, edge cases), schrijf "Lessons Learned" document (300 woorden).
|
||||||
|
|
||||||
[→ Ga naar Les 6](Samenvattingen/Les06-Samenvatting.md)
|
[→ Ga naar Les 11](Samenvattingen/Les11-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2.2 Next.js & Supabase
|
### Les 12: Introduction to Cursor
|
||||||
|
|
||||||
### Les 7: Next.js Project Setup
|
|
||||||
|
|
||||||
**Tools:** Next.js, OpenCode/WebStorm, Git, Vercel
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Wat is Next.js en waarom gebruiken we het?
|
|
||||||
- `npx create-next-app` stap voor stap
|
|
||||||
- Project structuur uitgelegd (app/, components/, lib/)
|
|
||||||
- TypeScript basics voor React
|
|
||||||
- Tailwind CSS in Next.js
|
|
||||||
- Git basics: commits, push, .gitignore
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Eerste Next.js project aanmaken
|
|
||||||
- Project structuur verkennen
|
|
||||||
- Simpele pagina's maken
|
|
||||||
- Components maken en importeren
|
|
||||||
- Deployen naar Vercel
|
|
||||||
|
|
||||||
**Lesopdracht:**
|
|
||||||
1. Run `npx create-next-app@latest` met TypeScript + Tailwind
|
|
||||||
2. Maak 3 pagina's (home, about, contact)
|
|
||||||
3. Maak 2 herbruikbare components (Header, Footer)
|
|
||||||
4. Style met Tailwind
|
|
||||||
5. Deploy naar Vercel
|
|
||||||
|
|
||||||
**Huiswerk:** Voeg 2 extra pagina's toe, maak 3 extra components, experimenteer met Tailwind, push alles naar GitHub.
|
|
||||||
|
|
||||||
[→ Ga naar Les 7](Samenvattingen/Les07-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Les 8: Supabase Basics
|
|
||||||
|
|
||||||
**Tools:** Supabase, Next.js, OpenCode
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Wat is Supabase? (database + auth in één)
|
|
||||||
- Supabase project aanmaken (live demo)
|
|
||||||
- Table Editor: tabellen maken zonder SQL
|
|
||||||
- Environment variables: wat, waarom, hoe
|
|
||||||
- Supabase client setup
|
|
||||||
- CRUD operaties uitgelegd
|
|
||||||
- Auth UI component (plug & play login)
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Supabase account en project aanmaken
|
|
||||||
- Eerste tabel maken via UI
|
|
||||||
- `.env.local` configureren
|
|
||||||
- Supabase client maken
|
|
||||||
- Data ophalen en tonen
|
|
||||||
- Auth toevoegen
|
|
||||||
|
|
||||||
**Lesopdracht:**
|
|
||||||
1. Maak Supabase project
|
|
||||||
2. Maak `todos` tabel via Table Editor
|
|
||||||
3. Configureer `.env.local`
|
|
||||||
4. Bouw Todo app: lijst tonen, toevoegen, afvinken, verwijderen
|
|
||||||
5. Voeg login toe met Auth UI
|
|
||||||
|
|
||||||
**Huiswerk:** Extend Todo app (filtering, user-specifieke todos), deploy naar Vercel met env vars, test in productie.
|
|
||||||
|
|
||||||
[→ Ga naar Les 8](Samenvattingen/Les08-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.3 AI Agents
|
|
||||||
|
|
||||||
### Les 9: AI Agents - Custom GPTs & Claude Projects
|
|
||||||
|
|
||||||
**Tools:** ChatGPT (Custom GPTs), Claude Desktop (Projects)
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Wat zijn AI Agents? Verschil chatbot vs agent
|
|
||||||
- Custom GPTs: hoe maak je ze, wat kun je ermee
|
|
||||||
- Claude Projects: custom instructions + project knowledge
|
|
||||||
- Wanneer een agent vs gewoon chatten
|
|
||||||
- Best practices voor agent instructions
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Custom GPT maken voor code review
|
|
||||||
- Claude Project opzetten voor eigen project
|
|
||||||
- Agents testen en vergelijken
|
|
||||||
- Instructions itereren en verbeteren
|
|
||||||
|
|
||||||
**Lesopdracht:**
|
|
||||||
1. Maak Custom GPT "Code Reviewer" met specifieke checklist
|
|
||||||
2. Maak Claude Project voor je Todo app met project context
|
|
||||||
3. Test beide met dezelfde code
|
|
||||||
4. Documenteer: welke geeft betere feedback?
|
|
||||||
|
|
||||||
**Huiswerk:** Maak "Personal Dev Assistant" agent afgestemd op jouw workflow, test in echt werk, deel je beste agent config met de klas.
|
|
||||||
|
|
||||||
[→ Ga naar Les 9](Samenvattingen/Les09-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Deel 3: Advanced AI-Driven Development
|
|
||||||
|
|
||||||
**9 lessen · 15 EC**
|
|
||||||
|
|
||||||
Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindproject.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.1 Cursor & Professional Workflow
|
|
||||||
|
|
||||||
### Les 10: Introduction to Cursor
|
|
||||||
|
|
||||||
**Tools:** Cursor
|
**Tools:** Cursor
|
||||||
|
|
||||||
@@ -360,11 +432,49 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
**Huiswerk:** Bouw complete mini-feature met Cursor, vergelijk ervaring met OpenCode, schrijf reflectie (400 woorden).
|
**Huiswerk:** Bouw complete mini-feature met Cursor, vergelijk ervaring met OpenCode, schrijf reflectie (400 woorden).
|
||||||
|
|
||||||
[→ Ga naar Les 10](Samenvattingen/Les10-Samenvatting.md)
|
[→ Ga naar Les 12](Samenvattingen/Les12-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Les 11: Project Setup & Repository Structure
|
### Les 13: AI Agents - Custom GPTs & Claude Projects
|
||||||
|
|
||||||
|
**Tools:** ChatGPT (Custom GPTs), Claude Desktop (Projects)
|
||||||
|
|
||||||
|
**Docent vertelt:**
|
||||||
|
- Wat zijn AI Agents? Verschil chatbot vs agent
|
||||||
|
- Custom GPTs: hoe maak je ze, wat kun je ermee
|
||||||
|
- Claude Projects: custom instructions + project knowledge
|
||||||
|
- Wanneer een agent vs gewoon chatten
|
||||||
|
- Best practices voor agent instructions
|
||||||
|
|
||||||
|
**Studenten doen:**
|
||||||
|
- **Groepsdiscussie:** Bespreek Cursor reflecties - hoe verschilt het van OpenCode?
|
||||||
|
- Custom GPT maken voor code review
|
||||||
|
- Claude Project opzetten voor eigen project
|
||||||
|
- Agents testen en vergelijken
|
||||||
|
- Instructions itereren en verbeteren
|
||||||
|
|
||||||
|
**Lesopdracht:**
|
||||||
|
1. Maak Custom GPT "Code Reviewer" met specifieke checklist
|
||||||
|
2. Maak Claude Project voor je Todo app met project context
|
||||||
|
3. Test beide met dezelfde code
|
||||||
|
4. Documenteer: welke geeft betere feedback?
|
||||||
|
|
||||||
|
**Huiswerk:** Maak "Personal Dev Assistant" agent afgestemd op jouw workflow, test in echt werk, deel je beste agent config met de klas.
|
||||||
|
|
||||||
|
[→ Ga naar Les 13](Samenvattingen/Les13-Samenvatting.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deel 4: Advanced AI Features
|
||||||
|
|
||||||
|
**6 lessen · 10 EC**
|
||||||
|
|
||||||
|
Professionele workflows, advanced Cursor, AI features bouwen en deployment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les 14: Project Setup & Repository Structure
|
||||||
|
|
||||||
**Tools:** Cursor, Git, GitHub
|
**Tools:** Cursor, Git, GitHub
|
||||||
|
|
||||||
@@ -392,11 +502,11 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
**Huiswerk:** Voeg extra .cursorrules files toe, start PROMPT-LOG.md, maak eerste components met Cursor.
|
**Huiswerk:** Voeg extra .cursorrules files toe, start PROMPT-LOG.md, maak eerste components met Cursor.
|
||||||
|
|
||||||
[→ Ga naar Les 11](Samenvattingen/Les11-Samenvatting.md)
|
[→ Ga naar Les 14](Samenvattingen/Les14-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Les 12: MCP & Context Management
|
### Les 15: MCP & Context Management
|
||||||
|
|
||||||
**Tools:** Cursor, Claude Desktop, MCP servers
|
**Tools:** Cursor, Claude Desktop, MCP servers
|
||||||
|
|
||||||
@@ -424,11 +534,11 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
**Huiswerk:** Voeg extra MCP server toe (naar keuze), optimaliseer je project voor AI context, documenteer in AI-DECISIONS.md.
|
**Huiswerk:** Voeg extra MCP server toe (naar keuze), optimaliseer je project voor AI context, documenteer in AI-DECISIONS.md.
|
||||||
|
|
||||||
[→ Ga naar Les 12](Samenvattingen/Les12-Samenvatting.md)
|
[→ Ga naar Les 15](Samenvattingen/Les15-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Les 13: Mastering Cursor
|
### Les 16: Mastering Cursor
|
||||||
|
|
||||||
**Tools:** Cursor, Claude models
|
**Tools:** Cursor, Claude models
|
||||||
|
|
||||||
@@ -450,39 +560,11 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
**Huiswerk:** Research .cursorrules voorbeelden online, schrijf uitgebreide .cursorrules voor jouw eindproject, test en itereer.
|
**Huiswerk:** Research .cursorrules voorbeelden online, schrijf uitgebreide .cursorrules voor jouw eindproject, test en itereer.
|
||||||
|
|
||||||
[→ Ga naar Les 13](Samenvattingen/Les13-Samenvatting.md)
|
[→ Ga naar Les 16](Samenvattingen/Les16-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3.2 Quality & AI Features
|
### Les 17: Vercel AI SDK - AI Features in je App
|
||||||
|
|
||||||
### Les 14: Debugging & Code Review met AI
|
|
||||||
|
|
||||||
**Tools:** Cursor, Browser DevTools, React DevTools
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Waarom AI goed is in debugging
|
|
||||||
- Error messages lezen en begrijpen
|
|
||||||
- Debugging workflow: isoleer → context → vraag AI → begrijp
|
|
||||||
- Browser DevTools basics (Console, Network, Elements)
|
|
||||||
- Code review met AI: wat kun je vragen?
|
|
||||||
- Wanneer AI NIET te vertrouwen
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Debugging challenge: 6 bugs fixen met AI hulp
|
|
||||||
- Browser DevTools gebruiken
|
|
||||||
- Code review van eigen code met AI
|
|
||||||
- Refactoring met AI suggesties
|
|
||||||
|
|
||||||
**Lesopdracht:** Los 6 opzettelijke bugs op in gegeven project, documenteer per bug: error message, prompt aan AI, oplossing, wat je leerde.
|
|
||||||
|
|
||||||
**Huiswerk:** Code review 3 files uit je eindproject met AI, fix gevonden issues, maak persoonlijke debugging checklist.
|
|
||||||
|
|
||||||
[→ Ga naar Les 14](Samenvattingen/Les14-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Les 15: Vercel AI SDK - AI Features in je App
|
|
||||||
|
|
||||||
**Tools:** Vercel AI SDK, Cursor, OpenAI/Anthropic API
|
**Tools:** Vercel AI SDK, Cursor, OpenAI/Anthropic API
|
||||||
|
|
||||||
@@ -512,23 +594,26 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
**Huiswerk:** Integreer AI feature in je eindproject (Recipe chat / Budget advisor / Travel planner), sla conversations op in Supabase.
|
**Huiswerk:** Integreer AI feature in je eindproject (Recipe chat / Budget advisor / Travel planner), sla conversations op in Supabase.
|
||||||
|
|
||||||
[→ Ga naar Les 15](Samenvattingen/Les15-Samenvatting.md)
|
[→ Ga naar Les 17](Samenvattingen/Les17-Samenvatting.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3.3 Deployment & Eindproject
|
### Les 18: Deployment & Production
|
||||||
|
|
||||||
### Les 16: Deployment & Production
|
|
||||||
|
|
||||||
**Tools:** Vercel, GitHub, Supabase
|
**Tools:** Vercel, GitHub, Supabase
|
||||||
|
|
||||||
|
**Eindopdracht kickoff (15 min):**
|
||||||
|
- Eindopdracht requirements doornemen
|
||||||
|
- Beoordelingscriteria uitleggen
|
||||||
|
- Timeline en deadlines
|
||||||
|
- Vragen beantwoorden
|
||||||
|
|
||||||
**Docent vertelt:**
|
**Docent vertelt:**
|
||||||
- Vercel deployment flow
|
- Vercel deployment flow
|
||||||
- Environment variables in Vercel
|
- Environment variables in Vercel
|
||||||
- Supabase productie setup
|
- Supabase productie setup
|
||||||
- Custom domains
|
- Custom domains
|
||||||
- Performance basics (Lighthouse)
|
- Performance basics (Lighthouse)
|
||||||
- Monitoring en error tracking
|
|
||||||
- Security checklist voor productie
|
- Security checklist voor productie
|
||||||
|
|
||||||
**Studenten doen:**
|
**Studenten doen:**
|
||||||
@@ -545,61 +630,7 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
4. Run Lighthouse, fix issues tot score >80
|
4. Run Lighthouse, fix issues tot score >80
|
||||||
5. Doorloop security checklist
|
5. Doorloop security checklist
|
||||||
|
|
||||||
**Huiswerk:** Custom domain toevoegen (optioneel), performance optimaliseren, documentatie updaten met productie URL.
|
**Huiswerk:** Custom domain toevoegen (optioneel), performance optimaliseren, documentatie updaten met productie URL, werk aan eindopdracht.
|
||||||
|
|
||||||
[→ Ga naar Les 16](Samenvattingen/Les16-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Les 17: Eindopdracht Kickoff
|
|
||||||
|
|
||||||
**Tools:** Cursor, alle geleerde tools
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Eindopdracht requirements doorlopen
|
|
||||||
- Beoordelingscriteria uitleggen
|
|
||||||
- Timeline en deadlines
|
|
||||||
- Tips voor succesvol afronden
|
|
||||||
- Q&A over onduidelijkheden
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Eindopdracht document lezen
|
|
||||||
- Vragen stellen
|
|
||||||
- Planning maken voor komende weken
|
|
||||||
- Beginnen aan ontbrekende features
|
|
||||||
- Peer review setup
|
|
||||||
|
|
||||||
**Lesopdracht:** Maak gedetailleerde planning voor afronden eindproject, identificeer wat nog moet gebeuren, begin met hoogste prioriteit items.
|
|
||||||
|
|
||||||
**Huiswerk:** Werk aan eindproject volgens planning, documenteer voortgang, bereid vragen voor voor werksessie.
|
|
||||||
|
|
||||||
[→ Ga naar Les 17](Samenvattingen/Les17-Samenvatting.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Les 18: Eindproject Werksessie
|
|
||||||
|
|
||||||
**Tools:** Cursor, alle geleerde tools
|
|
||||||
|
|
||||||
**Docent vertelt:**
|
|
||||||
- Korte standup: waar staat iedereen?
|
|
||||||
- Beschikbaar voor vragen en hulp
|
|
||||||
- Geen nieuwe theorie
|
|
||||||
|
|
||||||
**Studenten doen:**
|
|
||||||
- Werken aan eindproject
|
|
||||||
- Hulp vragen waar nodig
|
|
||||||
- Peer feedback geven
|
|
||||||
- Laatste features afronden
|
|
||||||
- Documentatie completeren
|
|
||||||
- PROMPT-LOG en AI-DECISIONS afronden
|
|
||||||
|
|
||||||
**Focus:** Dit is werktijd. De docent loopt rond, beantwoordt vragen, helpt bij problemen. Studenten werken zelfstandig aan hun eindproject.
|
|
||||||
|
|
||||||
**Deliverable eind van de les:**
|
|
||||||
- Werkende app deployed
|
|
||||||
- Documentatie compleet
|
|
||||||
- Klaar voor inleveren (of bijna)
|
|
||||||
|
|
||||||
[→ Ga naar Les 18](Samenvattingen/Les18-Samenvatting.md)
|
[→ Ga naar Les 18](Samenvattingen/Les18-Samenvatting.md)
|
||||||
|
|
||||||
@@ -607,8 +638,9 @@ Cursor als professionele tool, MCP, debugging, AI features bouwen, en het eindpr
|
|||||||
|
|
||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
- **Frontend:** React, Next.js, Tailwind CSS
|
- **Frontend:** React, Next.js, TypeScript, Tailwind CSS
|
||||||
- **Backend:** Supabase (Postgres database, Auth)
|
- **Backend:** Supabase (Postgres database, Auth)
|
||||||
|
- **Data Fetching:** React Query (TanStack Query)
|
||||||
- **AI Tools:** ChatGPT, Claude Desktop, v0.dev, OpenCode, Cursor
|
- **AI Tools:** ChatGPT, Claude Desktop, v0.dev, OpenCode, Cursor
|
||||||
- **AI SDK:** Vercel AI SDK voor AI features in apps
|
- **AI SDK:** Vercel AI SDK voor AI features in apps
|
||||||
- **Deployment:** Vercel, GitHub
|
- **Deployment:** Vercel, GitHub
|
||||||
|
|||||||
Reference in New Issue
Block a user