760 lines
29 KiB
Markdown
760 lines
29 KiB
Markdown
# Crewli Development Guide
|
|
|
|
Cursor & Claude Code — Van Leeg Project naar Productie
|
|
|
|
**Versie:** 1.0 | **Datum:** Maart 2026 | **Stack:** Laravel 12 + Vue 3 | **AI Tools:** Cursor + Claude Code
|
|
|
|
## 1. Strategie & Mindset
|
|
|
|
Cursor vs Claude Code — wanneer gebruik je wat?
|
|
|
|
Voordat je begint met ontwikkelen is het belangrijk te begrijpen hoe Cursor en Claude Code zich tot elkaar verhouden. Ze zijn complementair — niet concurrerend.
|
|
|
|
| **Tool** | **Wanneer inzetten** |
|
|
|----|----|
|
|
| Cursor (IDE) | Dagelijks coderen. Inline autocomplete, context-aware suggesties, kleine refactors, code reviews, directe file-edits. Beste voor: een specifiek component bouwen, een bug fixen, een test schrijven. |
|
|
| Claude Code (Terminal) | Grote, multi-file taken. Scaffolding van een volledig module (migrations + model + controller + tests + Vue-pagina). Autonome agent die zelfstandig werkt, tests uitvoert en fouten corrigeert. Beste voor: 'Bouw het volledige shift-module end-to-end.' |
|
|
| Samen | Aanbevolen workflow: Claude Code genereert het skelet en alle bestanden. Cursor verfijnt, debugt en voegt details toe. Claude Code draait de test-suite. Cursor doet code review en stijlcorrecties. |
|
|
|
|
> **KERNPRINCIPE**
|
|
>
|
|
> Claude Code is je senior developer die grote blokken werk autonoom uitvoert.
|
|
>
|
|
> Cursor is je pair programmer die naast je zit terwijl jij zelf ook werkt.
|
|
>
|
|
> Jij bent de architect en product owner: jij beslist, zij bouwen.
|
|
|
|
## 2. De Eerste Stappen
|
|
|
|
Wat je vandaag doet voordat je één regel code schrijft
|
|
|
|
### 2.1 Repository structuur definitief maken
|
|
|
|
Controleer en bevestig de folderstructuur
|
|
|
|
Jouw huidige setup heeft al een goede basis. Bevestig of maak de volgende structuur:
|
|
|
|
```
|
|
crewli/ # Monorepo root
|
|
├── api/ # Laravel 12 backend
|
|
│ ├── app/
|
|
│ │ ├── Http/
|
|
│ │ │ ├── Controllers/Api/V1/
|
|
│ │ │ ├── Middleware/
|
|
│ │ │ └── Requests/ # Form Requests per endpoint
|
|
│ │ ├── Models/
|
|
│ │ ├── Policies/ # Laravel Policies per model
|
|
│ │ ├── Services/ # Business logic buiten controllers
|
|
│ │ ├── Events/ + Listeners/
|
|
│ │ └── Jobs/ # Queue jobs (briefings, PDF, notifs)
|
|
│ ├── database/
|
|
│ │ ├── migrations/
|
|
│ │ ├── factories/
|
|
│ │ └── seeders/
|
|
│ └── tests/Feature/Api/V1/ # PHPUnit feature tests per controller
|
|
├── apps/
|
|
│ ├── admin/ # Super Admin SPA (Vuexy)
|
|
│ ├── app/ # Organizer SPA (Vuexy) -- HOOFDAPP
|
|
│ └── portal/ # Externe portals (vrijwilliger, artiest, leverancier)
|
|
├── docs/ # Design document, API docs, ERD
|
|
│ ├── design-document.md
|
|
│ └── dev-guide.md
|
|
└── .cursorrules # Cursor workspace rules
|
|
```
|
|
|
|
### 2.2 Dependencies installeren
|
|
|
|
Backend en frontend klaarstomen
|
|
|
|
**Backend (api/)**
|
|
|
|
```bash
|
|
cd api
|
|
|
|
# Spatie permissions (rollen/permissies)
|
|
composer require spatie/laravel-permission
|
|
|
|
# Audit log
|
|
composer require spatie/laravel-activitylog
|
|
|
|
# Media library (bestandsbeheer)
|
|
composer require spatie/laravel-medialibrary
|
|
|
|
# PDF generatie
|
|
composer require barryvdh/laravel-dompdf
|
|
|
|
# QR codes
|
|
composer require endroid/qr-code
|
|
|
|
# Publiceer Spatie configs
|
|
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
|
|
php artisan vendor:publish --provider="Spatie\LaravelActivitylog\ActivitylogServiceProvider"
|
|
```
|
|
|
|
**Frontend — alle apps (apps/app/, apps/admin/, apps/portal/)**
|
|
|
|
```bash
|
|
# TanStack Query voor API state management
|
|
npm install @tanstack/vue-query
|
|
|
|
# Formuliervalidatie
|
|
npm install vee-validate zod @vee-validate/zod
|
|
|
|
# Drag-and-drop (form builder, timetable, prioriteitsranking)
|
|
npm install vuedraggable@next
|
|
|
|
# In apps/app/ en apps/admin/ ook:
|
|
npm install @fullcalendar/vue3 @fullcalendar/timeline @fullcalendar/resource-timeline
|
|
```
|
|
|
|
### 2.3 CLAUDE.md aanmaken
|
|
|
|
Het belangrijkste bestand in je hele repo
|
|
|
|
CLAUDE.md is de instructieset voor Claude Code. Het wordt automatisch geladen bij elke sessie. Dit bestand is de meest impactvolle investering die je doet — een uur hieraan besteden bespaart honderden uren aan correcties.
|
|
|
|
Maak aan: /crewli/CLAUDE.md (root niveau, zodat het voor alle sub-projecten geldt)
|
|
|
|
## 3. Helper Files — Volledige Inhoud
|
|
|
|
De exacte bestanden die je aanmaakt voor de eerste prompt
|
|
|
|
### 3.1 CLAUDE.md — Root niveau
|
|
|
|
Dit is de volledige, aanbevolen inhoud voor je CLAUDE.md. Kopieer dit letterlijk en pas aan waar nodig.
|
|
|
|
```
|
|
# Crewli — Claude Code Instructies
|
|
|
|
## Project Context
|
|
Crewli is een multi-tenant SaaS platform voor event- en festivalbeheer.
|
|
Gebouwd voor een professionele vrijwilligersorganisatie, met SaaS-uitbreidingspotentieel.
|
|
Design Document: /resources/design/design-document.md
|
|
|
|
## Tech Stack
|
|
- Backend: PHP 8.2+, Laravel 12, Sanctum, Spatie Permission, MySQL 8, Redis
|
|
- Frontend: TypeScript, Vue 3 (Composition API), Vuexy/Vuetify, Pinia, TanStack Query
|
|
- Testing: PHPUnit (backend), Vitest (frontend)
|
|
|
|
## Repository Structuur
|
|
- api/ Laravel backend
|
|
- apps/app/ Organizer SPA (hoofdapp)
|
|
- apps/admin/ Super Admin SPA
|
|
- apps/portal/ Externe portals (vrijwilliger, artiest, leverancier)
|
|
|
|
## Backend Regels (STRIKT VOLGEN)
|
|
|
|
### Multi-tenancy
|
|
- ELKE query op event-data MOET scoperen op organisation_id
|
|
- Gebruik OrganisationScope als Eloquent Global Scope op alle event-gerelateerde modellen
|
|
- Nooit directe id-checks in controllers — gebruik altijd Policies
|
|
|
|
### Controllers
|
|
- Gebruik Resource Controllers (index/show/store/update/destroy)
|
|
- Namespace: App\Http\Controllers\Api\V1\
|
|
- Alle responses via API Resources (nooit model-attributen direct teruggeven)
|
|
- Validatie via Form Requests (nooit inline validate())
|
|
|
|
### Modellen
|
|
- Gebruik HasUlids trait op alle business-modellen (GEEN UUID v4)
|
|
- Soft deletes op: Organisation, Event, FestivalSection, Shift, ShiftAssignment, Person, Artist
|
|
- GEEN soft deletes op: CheckIn, BriefingSend, MessageReply, ShiftWaitlist (audit-records)
|
|
- JSON kolommen ALLEEN voor opaque configuratie — nooit voor queryable data
|
|
|
|
### Database
|
|
- Primaire sleutels: ULID via HasUlids (niet UUID v4, niet auto-increment voor business tables)
|
|
- Elke migratie in volgorde aanmaken: eerst foundation, dan afhankelijke tabellen
|
|
- ALTIJD composite indexes toevoegen zoals gedocumenteerd in het design document sectie 3.5
|
|
|
|
### Rollen & Permissies
|
|
- Gebruik Spatie laravel-permission
|
|
- Check rollen via $user->hasRole() en Policies — nooit hardcoded role strings in controllers
|
|
- Drie niveaus: app (super_admin), organisatie (org_admin/org_member), event (event_manager etc.)
|
|
|
|
### Testing
|
|
- Schrijf PHPUnit Feature Tests per controller
|
|
- Minimaal per endpoint: happy path + unauthenticated (401) + wrong organisation (403)
|
|
- Gebruik factories voor alle test-data
|
|
- Draai tests NA elke module: php artisan test --filter=ModuleNaam
|
|
|
|
## Frontend Regels (STRIKT VOLGEN)
|
|
|
|
### Vue Componenten
|
|
- Altijd <script setup lang='ts'> — nooit Options API
|
|
- Props altijd getypeerd met defineProps<{...}>()
|
|
- Emits altijd gedeclareerd met defineEmits<{...}>()
|
|
|
|
### API Calls
|
|
- Gebruik TanStack Query (useQuery / useMutation) voor ALLE API calls
|
|
- Nooit direct axios in een component — altijd via een composable in composables/api/
|
|
- Pinia stores voor cross-component state — nooit prop drilling
|
|
|
|
### Naamgeving
|
|
- DB kolommen: snake_case
|
|
- TypeScript/JS variabelen: camelCase
|
|
- Vue componenten: PascalCase (bijv. ShiftAssignPanel.vue)
|
|
- Composables: use-prefix (bijv. useShifts.ts)
|
|
- Pinia stores: use-suffix store (bijv. useEventStore.ts)
|
|
|
|
### UI
|
|
- Gebruik ALTIJD Vuexy/Vuetify componenten voor layout, forms, tabellen, dialogen
|
|
- Nooit custom CSS schrijven als een Vuetify klasse bestaat
|
|
- Responsief: mobile-first, minimaal werkend op 375px breedte
|
|
|
|
## Verboden Patronen
|
|
- NOOIT: $user->role === 'admin' (gebruik policies)
|
|
- NOOIT: Model::all() zonder where-clausule (altijd scopen)
|
|
- NOOIT: dd() of var_dump() achterlaten in code
|
|
- NOOIT: .env waarden hardcoden in code
|
|
- NOOIT: JSON kolommen gebruiken voor data waarop gefilterd wordt
|
|
- NOOIT: UUID v4 als primaire sleutel (gebruik HasUlids)
|
|
|
|
## Volgorde bij elke nieuwe module
|
|
1. Migratie(s) aanmaken en draaien
|
|
2. Eloquent Model met relaties, scopes en HasUlids
|
|
3. Factory voor test-data
|
|
4. Policy voor autorisatie
|
|
5. Form Request(s) voor validatie
|
|
6. API Resource voor response transformatie
|
|
7. Resource Controller
|
|
8. Routes registreren in api.php
|
|
9. PHPUnit Feature Test schrijven en draaien
|
|
10. Vue composable voor API calls (useModuleNaam.ts)
|
|
11. Pinia store indien cross-component state nodig
|
|
12. Vue pagina component
|
|
13. Route toevoegen in Vue Router
|
|
```
|
|
|
|
### 3.2 .cursorrules — Root niveau
|
|
|
|
Dit is het equivalent van CLAUDE.md maar voor Cursor's autocomplete en inline AI. Korter en meer gefocust op directe code-stijl.
|
|
|
|
```
|
|
# Crewli Cursor Rules
|
|
|
|
## Stack
|
|
PHP 8.2 + Laravel 12 | TypeScript + Vue 3 + Vuexy/Vuetify | Pinia + TanStack Query
|
|
|
|
## Laravel
|
|
- Resource Controllers, Form Requests, API Resources — altijd
|
|
- HasUlids op business modellen, HasFactory, SoftDeletes waar gedocumenteerd
|
|
- Global Scope OrganisationScope op event-gerelateerde modellen
|
|
- Policies voor autorisatie, nooit inline role checks
|
|
|
|
## Vue 3
|
|
- <script setup lang='ts'> altijd
|
|
- TanStack Query voor API state, Pinia voor UI state
|
|
- Vuetify componenten eerst, custom CSS als laatste redmiddel
|
|
|
|
## Naamgeving
|
|
- snake_case DB | camelCase JS | PascalCase Vue | use* composables | use*Store Pinia
|
|
|
|
## Tests
|
|
- PHPUnit Feature Test per controller, minimaal: 200 + 401 + 403
|
|
```
|
|
|
|
### 3.3 docs/SCHEMA.md — Levend schema-document
|
|
|
|
Maak een Markdown bestand aan in /docs/ dat de tabel-definitie bevat als platte tekst. Claude Code gebruikt dit als primaire referentie bij het genereren van migraties.
|
|
|
|
```
|
|
# Crewli Database Schema
|
|
# Versie: 1.3 | Gegenereerd vanuit Design Document
|
|
|
|
## Regels
|
|
- Primaire sleutels: ULID via HasUlids (nooit UUID v4)
|
|
- Soft delete: zie lijst per tabel hieronder
|
|
- JSON kolommen: alleen voor opaque config
|
|
|
|
## Tabellen
|
|
|
|
### users
|
|
- id (ulid, PK)
|
|
- name (string)
|
|
- email (string, unique)
|
|
- password (string)
|
|
- timezone (string, default: Europe/Amsterdam)
|
|
- locale (string, default: nl)
|
|
- avatar (string, nullable)
|
|
- email_verified_at (timestamp, nullable)
|
|
- deleted_at (timestamp, nullable) -- soft delete
|
|
|
|
### organisations
|
|
- id (ulid, PK)
|
|
- name (string)
|
|
- slug (string, unique)
|
|
- billing_status (enum: trial|active|suspended|cancelled, default: trial)
|
|
- settings (json, nullable) -- UI display prefs only
|
|
- deleted_at (timestamp, nullable)
|
|
|
|
# ... (volledig schema uit Design Document sectie 3.5)
|
|
```
|
|
|
|
### 3.4 docs/API.md — API contract
|
|
|
|
Een simpele route-lijst die Claude Code gebruikt als referentie bij het genereren van controllers en Vue composables.
|
|
|
|
```
|
|
# Crewli API Contract
|
|
# Base: /api/v1/
|
|
# Auth: Bearer token (Sanctum)
|
|
|
|
## Auth
|
|
POST /auth/login
|
|
POST /auth/logout
|
|
GET /auth/me
|
|
|
|
## Organisations
|
|
GET /organisations -- lijst (super admin)
|
|
POST /organisations -- aanmaken
|
|
GET /organisations/{org} -- detail
|
|
PUT /organisations/{org} -- bijwerken
|
|
GET /organisations/{org}/members -- leden
|
|
POST /organisations/{org}/invite -- uitnodigen
|
|
|
|
## Events
|
|
GET /organisations/{org}/events
|
|
POST /organisations/{org}/events
|
|
GET /organisations/{org}/events/{event}
|
|
PUT /organisations/{org}/events/{event}
|
|
|
|
## Festival Sections
|
|
GET /events/{event}/sections
|
|
POST /events/{event}/sections
|
|
GET /events/{event}/sections/{section}
|
|
|
|
## Time Slots
|
|
GET /events/{event}/time-slots
|
|
POST /events/{event}/time-slots
|
|
|
|
## Shifts
|
|
GET /events/{event}/sections/{section}/shifts
|
|
POST /events/{event}/sections/{section}/shifts
|
|
PUT /events/{event}/sections/{section}/shifts/{shift}
|
|
POST /events/{event}/sections/{section}/shifts/{shift}/assign
|
|
POST /events/{event}/sections/{section}/shifts/{shift}/claim
|
|
|
|
## Persons
|
|
GET /events/{event}/persons
|
|
POST /events/{event}/persons
|
|
GET /events/{event}/persons/{person}
|
|
PUT /events/{event}/persons/{person}
|
|
POST /events/{event}/persons/{person}/approve
|
|
|
|
# ... (volledig API contract uitbreiden per module)
|
|
```
|
|
|
|
## 4. Development Workflow
|
|
|
|
Hoe je van leeg project naar werkende feature gaat
|
|
|
|
Elke feature volgt dezelfde drielaagse workflow. Commit altijd per voltooide laag — nooit halfafgebouwde code in main.
|
|
|
|
| **Laag** | **Wat je doet en met welk tool** |
|
|
|----|----|
|
|
| Laag 1 — Backend (API) | Claude Code genereert: migratie + model + factory + policy + form request + resource + controller + test. Jij reviewt en draait tests. |
|
|
| Laag 2 — Frontend (Vue) | Claude Code genereert: composable + Pinia store + Vue pagina + router entry. Cursor verfijnt de UI met Vuexy componenten. |
|
|
| Laag 3 — Integration | Cursor: verbind frontend met backend. Test end-to-end. Fix type-errors. Review mobile weergave. |
|
|
|
|
### 4.1 De Module-generatie volgorde
|
|
|
|
Altijd in deze volgorde. Nooit stappen overslaan — later toevoegen kost meer tijd dan nu correct doen.
|
|
|
|
| **Stap** | **Commando / Actie** |
|
|
|----|----|
|
|
| 1. Migratie | php artisan make:migration create_shifts_table |
|
|
| 2. Model | php artisan make:model Shift -mfp (migration + factory + policy) |
|
|
| 3. Form Request | php artisan make:request StoreShiftRequest + UpdateShiftRequest |
|
|
| 4. API Resource | php artisan make:resource ShiftResource + ShiftCollection |
|
|
| 5. Controller | php artisan make:controller Api/V1/ShiftController --api |
|
|
| 6. Registreer routes | In api/routes/api.php toevoegen |
|
|
| 7. Test | php artisan make:test ShiftControllerTest + draaien |
|
|
| 8. Composable | apps/app/src/composables/api/useShifts.ts aanmaken |
|
|
| 9. Store (indien nodig) | apps/app/src/stores/useShiftStore.ts |
|
|
| 10. Vue pagina | apps/app/src/pages/sections/[id]/shifts.vue |
|
|
| 11. Route | apps/app/src/router/index.ts |
|
|
|
|
### 4.2 Fase-planning: wat bouw je wanneer
|
|
|
|
| **Fase** | **Inhoud** |
|
|
|----|----|
|
|
| Fase 1 — Foundation (nu) | Auth (login/logout/me), Organisations CRUD, Events CRUD, User invitations, Multi-tenant scope, Roles & permissions setup, Basis dashboard shell |
|
|
| Fase 2 — Core Operations | Persons & Crowd Types, Festival Sections + Time Slots + Shifts, Shift claiming + goedkeuring, Vrijwilligers registratie + portaal, Accreditatie engine, Basis briefings |
|
|
| Fase 3 — Advancing & Show Day | Artist advancing + portaal, Timetable, Mission Control, Formulierbouwer, Post-festival evaluatie, PDF allocatiesheet, Campagnes (email + WhatsApp via Zender) |
|
|
| Fase 4 — Differentiators | Real-time WebSockets, Show Day Mode, Vrijwilligersprofiel + festival-paspoort, Shift swap & wachtlijst, Retrospectief rapport, Leveranciersportaal uitgebreid |
|
|
|
|
## 5. Prompt Bibliotheek
|
|
|
|
Kant-en-klare prompts voor elke ontwikkelstap
|
|
|
|
Gebruik deze prompts letterlijk of als basis. De meest effectieve prompts zijn: specifiek, contextueel en taak-gebaseerd. Verwijs altijd naar de docs/ bestanden die je hebt aangemaakt.
|
|
|
|
### 5.1 Kickstart prompts
|
|
|
|
> **Fase 1 kickstart — Alles genereren in een sweep**
|
|
>
|
|
> Lees /resources/design/design-document.md sectie 3.5 (schema) en /CLAUDE.md.
|
|
>
|
|
> Genereer alle Fase 1 componenten in de juiste volgorde:
|
|
>
|
|
> 1. Migrations voor: users (update), organisations, organisation_user, user_invitations, events, event_user_roles
|
|
> 2. Eloquent modellen met HasUlids, relaties, OrganisationScope global scope waar van toepassing
|
|
> 3. Factories met realistic test data
|
|
> 4. Spatie Permission seeder: maak rollen aan (super_admin, org_admin, org_member, event_manager, staff_coordinator, volunteer_coordinator)
|
|
> 5. Auth controller (login/logout/me) met Sanctum
|
|
> 6. Organisations controller (CRUD) met Policy en Feature Test
|
|
> 7. Events controller (CRUD) met Policy en Feature Test
|
|
>
|
|
> Draai na elke stap: php artisan test. Los fouten op voor je verder gaat.
|
|
|
|
> **Module genereren — Shifts als voorbeeld**
|
|
>
|
|
> Lees /CLAUDE.md en /docs/SCHEMA.md voor de shifts tabel definitie.
|
|
>
|
|
> Bouw het volledige Shifts module in de volgorde uit CLAUDE.md sectie 'Volgorde bij elke nieuwe module'.
|
|
>
|
|
> Specifieke eisen voor Shifts:
|
|
>
|
|
> - time_slot_id MOET gedenormaliseerd worden in shift_assignments voor de UNIQUE(person_id, time_slot_id) constraint
|
|
> - ShiftAssignment heeft een status machine: pending_approval > approved/rejected/cancelled/completed
|
|
> - Auto-approve is configureerbaar per shift (auto_approved bool op shift niveau)
|
|
> - Bij approve: stuur notificatie naar vrijwilliger (queued job, gebruik ZenderService voor WhatsApp)
|
|
> - ShiftResource moet slots_filled (count van approved assignments) en fill_rate (percentage) berekend teruggeven
|
|
>
|
|
> Eindig met: php artisan test --filter=Shift
|
|
|
|
### 5.2 Backend prompts
|
|
|
|
> **Migration genereren**
|
|
>
|
|
> Genereer een Laravel migratie voor de tabel [TABELNAAM] op basis van /docs/SCHEMA.md.
|
|
>
|
|
> Gebruik $table->ulid('id')->primary() als PK.
|
|
>
|
|
> Voeg alle indexes toe zoals gedocumenteerd (composite indexes, unique constraints).
|
|
>
|
|
> Voeg timestamps() en softDeletes() toe indien van toepassing per CLAUDE.md.
|
|
>
|
|
> Gebruik constrained() op alle foreign keys voor cascade-gedrag.
|
|
|
|
> **Model met alle features**
|
|
>
|
|
> Genereer het Eloquent model voor [MODELNAAM].
|
|
>
|
|
> Gebruik: HasUlids, HasFactory, SoftDeletes (indien van toepassing).
|
|
>
|
|
> Voeg toe: OrganisationScope global scope, alle relaties (hasMany, belongsTo, belongsToMany),
|
|
> computed accessors (fill_rate, available_slots), status-gerelateerde scopes (scopePending, scopeApproved),
|
|
> en $fillable of $guarded array.
|
|
>
|
|
> Schrijf ook de factory met realistic Nederlandse testdata.
|
|
|
|
> **API Resource met computed velden**
|
|
>
|
|
> Genereer een Laravel API Resource voor [MODELNAAM].
|
|
>
|
|
> Voeg toe: alle relevante velden, computed velden (fill_rate, status_label),
|
|
> conditioneel geladen relaties (whenLoaded), en wanneer van toepassing: when() voor permissie-afhankelijke velden.
|
|
>
|
|
> De Resource mag NOOIT model-attributen direct weggeven zonder transformatie.
|
|
|
|
> **Feature test schrijven**
|
|
>
|
|
> Schrijf een PHPUnit Feature Test voor [CONTROLLERNAAM].
|
|
>
|
|
> Dek minimaal af: index (200), show (200), store (201), update (200), destroy (204),
|
|
> unauthenticated (401 op alle routes), wrong organisation (403), validatiefouten (422).
|
|
>
|
|
> Gebruik RefreshDatabase, ActingAs met correcte rol via Spatie Permission.
|
|
>
|
|
> Maak test data via factories — nooit hardcoded IDs.
|
|
|
|
> **ZenderService aanmaken (WhatsApp/SMS)**
|
|
>
|
|
> Maak app/Services/ZenderService.php aan.
|
|
>
|
|
> Zender is een self-hosted SMS/WhatsApp gateway (CodeCanyon product).
|
|
>
|
|
> Config: ZENDER_API_URL en ZENDER_API_KEY uit .env.
|
|
>
|
|
> Methoden: sendSms(string $to, string $message): bool
|
|
> sendWhatsApp(string $to, string $message): bool
|
|
> sendByUrgency(string $to, string $message, string $urgency): bool
|
|
>
|
|
> urgency: normal=email only, urgent=whatsapp, emergency=sms+whatsapp parallel
|
|
>
|
|
> Gebruik Laravel HTTP Client (Http::). Log alle sends via activitylog.
|
|
>
|
|
> Schrijf ook een ZenderServiceTest met HTTP fake.
|
|
|
|
### 5.3 Frontend prompts
|
|
|
|
> **Vue pagina voor een lijst-overzicht**
|
|
>
|
|
> Maak apps/app/src/pages/[module]/index.vue.
|
|
>
|
|
> Gebruik \<script setup lang='ts'\>.
|
|
>
|
|
> API calls via useQuery() uit TanStack Query — niet direct axios.
|
|
>
|
|
> Tabel via VDataTable van Vuetify — niet custom HTML.
|
|
>
|
|
> Bovenaan: status KPI-tiles (totaal, goedgekeurd, pending) als klikbare VCard componenten.
|
|
>
|
|
> Rij klik: opent een side panel (niet navigeert naar nieuwe pagina) met detail-informatie.
|
|
>
|
|
> Loading state: VSkeleton loader. Error state: VAlert met retry knop.
|
|
>
|
|
> Mobiel: tabel collapst naar een VList op viewport < 768px.
|
|
|
|
> **Composable voor API calls**
|
|
>
|
|
> Maak apps/app/src/composables/api/use[Module].ts.
|
|
>
|
|
> Exporteer: use[Module]List (useQuery), use[Module]Detail (useQuery met id param),
|
|
> useCreate[Module] (useMutation), useUpdate[Module] (useMutation), useDelete[Module] (useMutation).
|
|
>
|
|
> Gebruik axios via de centrale api.ts instance (met Sanctum CSRF en auth header).
|
|
>
|
|
> Mutations invalideren automatisch de relevante query keys na succes.
|
|
>
|
|
> Alle response types volledig getypeerd via TypeScript interfaces in types/[module].ts.
|
|
|
|
> **Pinia store aanmaken**
|
|
>
|
|
> Maak apps/app/src/stores/use[Module]Store.ts.
|
|
>
|
|
> Gebruik defineStore met Setup syntax (niet Options syntax).
|
|
>
|
|
> Sla op: geselecteerde IDs, UI state (open sidepanel, actief tab), filters.
|
|
>
|
|
> NIET in Pinia: server data (dat zit in TanStack Query). Pinia is alleen voor UI state.
|
|
>
|
|
> Exporteer: alle state als readonly via storeToRefs.
|
|
|
|
> **Shift claim workflow — volledig end-to-end**
|
|
>
|
|
> Bouw de volledige shift claim workflow:
|
|
>
|
|
> Backend: POST /shifts/{shift}/claim endpoint in ShiftController.
|
|
>
|
|
> - Valideer: shift heeft slots_open_for_claiming beschikbaar
|
|
> - Valideer: geen bestaande approved assignment voor zelfde time_slot_id voor deze person
|
|
> - Maak ShiftAssignment aan met status=pending_approval
|
|
> - Dispatch NotifyCoordinatorOfClaimJob (queued)
|
|
> - Return ShiftAssignmentResource
|
|
>
|
|
> Frontend: 'Claim' knop in portal/shifts/index.vue.
|
|
>
|
|
> - Disable knop als conflict of geen slots beschikbaar
|
|
> - Na claim: toon 'Wachten op goedkeuring' badge
|
|
> - Optioneel: 'Op wachtlijst' knop als shift vol is
|
|
|
|
### 5.4 Agent-aanstuurprompts
|
|
|
|
> **Grote module — een prompt voor alles**
|
|
>
|
|
> Je bent een senior fullstack developer die werkt aan Crewli. Lees /CLAUDE.md volledig.
|
|
>
|
|
> Bouw het volledige [MODULE] module:
|
|
>
|
|
> Backend (in volgorde):
|
|
>
|
|
> 1. Migrations voor alle tabellen uit /docs/SCHEMA.md sectie [X.X]
|
|
> 2. Models met alle relaties, scopes en accessors
|
|
> 3. Factories
|
|
> 4. Policies
|
|
> 5. Form Requests
|
|
> 6. API Resources
|
|
> 7. Controllers
|
|
> 8. Routes
|
|
> 9. Feature tests — draai ze, los fouten op
|
|
>
|
|
> Frontend:
|
|
>
|
|
> 10. TypeScript types in apps/app/src/types/[module].ts
|
|
> 11. Composables in apps/app/src/composables/api/
|
|
> 12. Vue pagina's (lijst + detail side panel)
|
|
> 13. Router entries
|
|
>
|
|
> Stop na elke laag en vraag bevestiging voor je doorgaat.
|
|
>
|
|
> Als een test faalt: los het op voor je verdergaat — nooit overslaan.
|
|
|
|
> **Bug fix prompt**
|
|
>
|
|
> Er is een probleem met [BESCHRIJVING VAN HET PROBLEEM].
|
|
>
|
|
> Relevante bestanden: [BESTANDSPADEN].
|
|
>
|
|
> Foutmelding: [PLAK EXACTE ERROR].
|
|
>
|
|
> Verwacht gedrag: [WAT ZOU ER MOETEN GEBEUREN].
|
|
>
|
|
> Analyseer de oorzaak, schrijf een failing test die het probleem reproduceert,
|
|
> fix het probleem, en bevestig dat de test slaagt.
|
|
|
|
> **Code review prompt**
|
|
>
|
|
> Review de code in [BESTANDSPAD] als senior Laravel/Vue developer.
|
|
>
|
|
> Check specifiek op:
|
|
>
|
|
> - Multi-tenancy: wordt organisation_id correct gescopeerd?
|
|
> - Security: worden Policies gebruikt? Geen directe role-checks?
|
|
> - Performance: ontbrekende eager loading (N+1), ontbrekende indexes?
|
|
> - Conventies: volgt het CLAUDE.md regels?
|
|
> - Types: zijn alle TypeScript types volledig (geen any)?
|
|
>
|
|
> Geef concrete verbeterpunten met codevoorbeelden.
|
|
|
|
## 6. Agents — Autonome Ontwikkeling
|
|
|
|
Hoe je Claude Code en Cursor agents effectief inzet
|
|
|
|
### 6.1 Claude Code als Agent
|
|
|
|
Claude Code kan volledig autonoom werken: bestanden lezen, aanmaken, aanpassen, tests draaien en fouten corrigeren — zonder dat jij elke stap bevestigt. Dit is het krachtigste en snelste werkmode.
|
|
|
|
| **Mode** | **Wanneer gebruiken** |
|
|
|----|----|
|
|
| Interactief (standaard) | Als je wil meekijken en goedkeuren. Claude Code stelt elke actie voor en wacht. Gebruik voor: eerste keer een module bouwen, complexe refactors. |
|
|
| Autonoom (--dangerously-skip-permissions) | Als je een grote taak wil delegeren en wegloopt. Claude Code werkt door tot klaar. Gebruik voor: routine-modules die je eerder hebt gebouwd, test-driven fixes. |
|
|
| Aanbevolen aanpak | Start autonoom voor scaffolding. Schakel naar interactief bij UI-componenten of business-logica die project-specifieke kennis vereist. |
|
|
|
|
**Claude Code opstarten**
|
|
|
|
```bash
|
|
# Installeer Claude Code (eenmalig)
|
|
npm install -g @anthropic-ai/claude-code
|
|
|
|
# Start in je project root
|
|
cd /pad/naar/crewli
|
|
claude
|
|
|
|
# Of: direct met een taak
|
|
claude --print 'Genereer de Shift migration op basis van CLAUDE.md'
|
|
|
|
# Autonoom mode (voorzichtig gebruiken)
|
|
claude --dangerously-skip-permissions
|
|
```
|
|
|
|
### 6.2 Cursor Agent Mode
|
|
|
|
Cursor heeft een ingebouwde Agent mode die vergelijkbaar is met Claude Code maar geintegreerd in de IDE. Activeer via Cmd+Shift+P > 'Cursor: Open Agent'.
|
|
|
|
| **Feature** | **Gebruik** |
|
|
|----|----|
|
|
| @workspace | Geeft de agent toegang tot je hele codebase als context. Altijd meegeven bij module-niveau taken. |
|
|
| @file | Verwijs naar een specifiek bestand. Bijv: @CLAUDE.md @api/app/Models/Shift.php |
|
|
| @docs | Verwijs naar externe documentatie (Laravel docs, Vuetify docs). Cursor indexeert deze. |
|
|
| Composer mode | Meerdere bestanden tegelijk bewerken. Ideaal voor: tegelijk model + controller + test aanpassen. |
|
|
|
|
### 6.3 De optimale agent-workflow per dag
|
|
|
|
> **DAGELIJKSE ROUTINE**
|
|
>
|
|
> Ochtend: Open Claude Code. Geef de taak voor die dag: 'Bouw het volledig Persons module op basis van CLAUDE.md en SCHEMA.md.' Laat autonoom draaien.
|
|
>
|
|
> Middag: Review de gegenereerde code in Cursor. Check: volgt het de conventies? Zijn de tests groen? Zijn de TypeScript types compleet?
|
|
>
|
|
> Namiddag: Cursor voor UI fijnafstelling, Vuexy componenten integratie, visuele correcties.
|
|
>
|
|
> Einde dag: php artisan test (alle tests groen). Commit alles met duidelijke commit messages.
|
|
|
|
### 6.4 Context window management
|
|
|
|
Claude Code heeft een beperkt context window. Bij grote taken verliest het de context van eerdere bestanden. Beheer dit proactief:
|
|
|
|
- Begin elke nieuwe sessie met: 'Lees /CLAUDE.md voor je begint.'
|
|
|
|
- Verwijs expliciet naar relevante bestanden: 'Zie /docs/SCHEMA.md voor de tabel definitie.'
|
|
|
|
- Splits grote modules: 'Bouw eerst alleen de backend (stappen 1-9). Stop dan.'
|
|
|
|
- Na een context-verlies: geef een samenvatting: 'We bouwen Crewli. Tot nu toe klaar: auth, organisations, events. Nu: Shifts module backend.'
|
|
|
|
- Gebruik /docs/API.md als levend document — houd bij wat er al gebouwd is.
|
|
|
|
## 7. Tips, Valkuilen & Best Practices
|
|
|
|
Geleerd van ervaring — lees dit voordat je begint
|
|
|
|
### 7.1 De grootste tijdverspillers
|
|
|
|
| **Valkuil** | **Oplossing** |
|
|
|----|----|
|
|
| Te brede prompts: 'Bouw de hele app' | Altijd per module. Per module maximaal 1 laag tegelijk. Breed = vaag = slechte output. |
|
|
| CLAUDE.md niet up-to-date houden | Na elke architectuurbeslissing: update CLAUDE.md. Dit is je bron van waarheid. Verouderde regels leiden tot inconsistente code. |
|
|
| Tests overslaan 'want het werkt toch' | Schrijf tests altijd. AI-gegenereerde code heeft subtiele bugs die pas later opduiken. Tests vangen dit vroeg. |
|
|
| Alle gegenereerde code blindelings accepteren | Review altijd: check multi-tenancy scoping, check indexes, check error handling. AI mist soms subtiele business logica. |
|
|
| Frontend en backend tegelijk bouwen | Backend eerst, compleet en getest. Dan frontend. Nooit parallel — je verliest overzicht. |
|
|
| Geen versiecontrole per module | Commit na elke voltooide module (backend + frontend + tests). Kleine commits = makkelijk terugdraaien. |
|
|
|
|
### 7.2 Prompts die altijd goed werken
|
|
|
|
- **Geef altijd context: 'Crewli is een multi-tenant SaaS voor festival-organisatie...'**
|
|
|
|
- **Verwijs naar bestanden: 'Op basis van CLAUDE.md en SCHEMA.md...'**
|
|
|
|
- **Specificeer de output: 'Genereer X, Y en Z. Niets anders.'**
|
|
|
|
- **Vraag om uitleg: 'Leg uit waarom je deze aanpak kiest voor de shift conflict-check.'**
|
|
|
|
- **Gebruik iteratief: 'Dit klopt niet omdat... Pas aan en draai tests opnieuw.'**
|
|
|
|
### 7.3 Kwaliteitscontrole checklist
|
|
|
|
Gebruik dit als checklist voor elke voltooide module voordat je verder gaat:
|
|
|
|
| **Check** | **Wat je controleert** |
|
|
|----|----|
|
|
| Tests | php artisan test draait groen. Minimaal: 200, 401, 403 per endpoint. |
|
|
| Multi-tenancy | Elke query heeft organisation_id scope. Controleer via tinker. |
|
|
| N+1 queries | Gebruik Laravel Debugbar of query logging. Geen N+1 in lijst-endpoints. |
|
|
| TypeScript | Geen 'any' types in Vue composables en components. npx tsc --noEmit groen. |
|
|
| Mobile | Pagina is bruikbaar op 375px. Open Chrome DevTools en check. |
|
|
| Error states | Wat ziet een gebruiker bij: lege lijst, API fout, netwerk timeout? |
|
|
| CLAUDE.md | Geen verboden patronen (Model::all, hardcoded roles, UUID v4). |
|
|
|
|
### 7.4 Handige Laravel commando's
|
|
|
|
```bash
|
|
# Alles in een keer voor een nieuwe model
|
|
php artisan make:model Shift -a # model + migration + factory + seeder + policy + controller + resource
|
|
|
|
# Tests draaien
|
|
php artisan test # alle tests
|
|
php artisan test --filter=ShiftTest # specifieke test class
|
|
php artisan test --coverage # met coverage rapport
|
|
|
|
# Database
|
|
php artisan migrate:fresh --seed # reset + migreer + seed
|
|
php artisan tinker # REPL voor quick checks
|
|
|
|
# Routes inspecteren
|
|
php artisan route:list --path=api/v1 # alle API routes
|
|
|
|
# Queue (voor briefings, notificaties)
|
|
php artisan queue:work --queue=notifications,briefings,default
|
|
```
|
|
|
|
### 7.5 Eerste dag: exacte volgorde
|
|
|
|
| **#** | **Actie** |
|
|
|----|----|
|
|
| 1 | Repository structuur controleren (sectie 2, stap 01) |
|
|
| 2 | Dependencies installeren (sectie 2, stap 02) |
|
|
| 3 | CLAUDE.md aanmaken en invullen (sectie 3.1) |
|
|
| 4 | .cursorrules aanmaken (sectie 3.2) |
|
|
| 5 | docs/SCHEMA.md aanmaken met volledig schema uit design document |
|
|
| 6 | docs/API.md aanmaken met initiiele routes |
|
|
| 7 | Claude Code starten: 'Lees CLAUDE.md. Daarna: genereer Fase 1 — auth, organisations, events.' |
|
|
| 8 | Tests draaien: php artisan test — los fouten op |
|
|
| 9 | Commit: 'feat: fase 1 foundation — auth, organisations, events' |
|
|
| 10 | Morgen: Fase 2 starten met Persons & Crowd Types |
|
|
|
|
---
|
|
|
|
Crewli Development Guide v1.0 — Maart 2026
|