From ea159a34fe3fdb2960c3fd10f2fd1ee45892fe28 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Tue, 14 Apr 2026 19:04:19 +0200 Subject: [PATCH] docs: add development prompts and vibe coding checklist Co-Authored-By: Claude Opus 4.6 (1M context) --- dev-docs/MASTER_PROMPT_CC.md | 296 ++++++++++++++++++++++++++++++ dev-docs/MASTER_PROMPT_CURSOR.md | 177 ++++++++++++++++++ dev-docs/VIBE_CODING_CHECKLIST.md | 146 +++++++++++++++ 3 files changed, 619 insertions(+) create mode 100644 dev-docs/MASTER_PROMPT_CC.md create mode 100644 dev-docs/MASTER_PROMPT_CURSOR.md create mode 100644 dev-docs/VIBE_CODING_CHECKLIST.md diff --git a/dev-docs/MASTER_PROMPT_CC.md b/dev-docs/MASTER_PROMPT_CC.md new file mode 100644 index 00000000..8a0f940e --- /dev/null +++ b/dev-docs/MASTER_PROMPT_CC.md @@ -0,0 +1,296 @@ +# Crewli — Claude Code Master Prompt +# Plak dit BOVEN elke task. Vervang [TASK] onderaan. + +## MANDATORY PREAMBLE — READ BEFORE DOING ANYTHING + +Read `/CLAUDE.md` and `/dev-docs/SCHEMA.md` in full before starting. These are +your single source of truth. Do not deviate from them. Do not make assumptions +about the database schema — always verify against SCHEMA.md. Also read +`/dev-docs/API.md` for the existing API contract. + +If the task involves a module that already has existing code, read that code +first. Understand the current state before making changes. + +## PROJECT CONTEXT + +Crewli is a multi-tenant SaaS platform for event and festival management. + +- **Backend:** Laravel 12 REST API (no Blade views, no Inertia), Sanctum auth, + Spatie Permission, MySQL 8, Redis +- **Frontend:** Three standalone Vue 3 + TypeScript SPAs on Vuexy 9.5 / + Vuetify 3.10 — `apps/admin/` (port 5173), `apps/app/` (port 5174), + `apps/portal/` (port 5175) +- **State:** Pinia + TanStack Vue Query +- **Forms:** VeeValidate + Zod +- **API base path:** `/api/v1/` +- **Testing:** PHPUnit (backend), Vitest (frontend) + +### Repository structure + +``` +crewli/ +├── api/ # Laravel 12 backend +│ ├── app/ +│ │ ├── Http/ +│ │ │ ├── Controllers/Api/V1/ +│ │ │ ├── Middleware/ +│ │ │ └── Requests/ # Form Requests per endpoint +│ │ ├── Models/ +│ │ ├── Policies/ +│ │ ├── Services/ # Business logic (NOT in controllers) +│ │ ├── Enums/ # PHP Enums for all status/type fields +│ │ ├── Events/ + Listeners/ +│ │ └── Jobs/ # Queued jobs (briefings, notifications) +│ ├── database/ +│ │ ├── migrations/ +│ │ ├── factories/ +│ │ └── seeders/ +│ └── tests/Feature/Api/V1/ +├── apps/ +│ ├── admin/ # Super Admin SPA +│ ├── app/ # Organizer SPA (main app) +│ │ └── src/ +│ │ ├── lib/axios.ts # THE ONLY axios instance +│ │ ├── composables/api/ # TanStack Query composables +│ │ ├── stores/ # Pinia stores +│ │ ├── types/ # TypeScript interfaces +│ │ └── pages/ +│ └── portal/ # Dual-mode portal +├── dev-docs/ # Developer documentation (source of truth) +│ ├── SCHEMA.md +│ ├── API.md +│ ├── BACKLOG.md +│ ├── design-document.md +│ ├── dev-guide.md +│ └── start-guide.md +├── docs/ # VitePress end-user documentation (Dutch) +├── CLAUDE.md # This file's companion — workspace rules +└── .cursorrules +``` + +### Key architectural decisions (final, non-negotiable) + +- **ULID** primary keys on all business tables via `HasUlids` — NEVER UUID v4 +- **Integer auto-increment** on pure pivot tables only +- **JSON columns** exclusively for opaque config (settings, blocks) — never + for queryable data +- **Multi-tenancy** via `OrganisationScope` Eloquent Global Scope on all + event-related models +- **Soft delete** per table type as documented in SCHEMA.md — immutable audit + records (check_ins, form_submissions, briefing_sends) do NOT get soft delete +- **Portal dual-mode:** Sanctum session for volunteers/crew (persistent + identity), `portal.token` middleware for artists/suppliers/press + (event-specific, no account) + +--- + +## ZERO-COMPROMISE RULES — VIOLATIONS ARE BLOCKERS + +These rules are absolute. No workarounds. No "we'll fix it later". No partial +implementations. If something cannot be done properly, STOP and report it. + +### Architecture & design + +1. **ARCHITECTURE FIRST.** If the task requires a new pattern, data structure, + or integration that isn't documented in CLAUDE.md or SCHEMA.md — stop and + ask. Do not invent architecture. Write an Architecture Decision Record (ADR) + in `/dev-docs/decisions/` if a significant design choice is needed. + +2. **DELETE OVER ADAPT.** If you find duplicate logic, conflicting patterns, or + legacy code that does the same thing differently: delete the worse version. + Do not build alongside it. Do not "wrap" it. If two implementations exist, + one must die. Consolidate to one source of truth. + +3. **STRICT LAYERING.** Business logic belongs in `app/Services/`, NEVER in + controllers. Controllers handle HTTP concerns only: receive request, call + service, return resource. Data access patterns go through Eloquent models + with proper scopes. No "quick fixes" in the wrong layer. + - Controller → receives FormRequest, calls Service, returns API Resource + - Service → contains business logic, validation beyond FormRequest, + orchestration + - Model → relationships, scopes, accessors, mutators + - Job → async work dispatched by Service + +4. **CONTRACT-FIRST.** Before implementing any module: + - Define the PHP Enum(s) in `app/Enums/` for all status/type fields + - Define the API Resource (response shape) first + - Define the Form Request (input validation) first + - Then implement the Service and Controller + Types and contracts define behaviour. Implementation follows. + +5. **CONSISTENCY OVER CLEVERNESS.** Use the same pattern for every similar + problem. If existing modules use a specific approach for pagination, error + handling, or resource loading — use that exact same approach. Never + introduce a "better" alternative pattern without refactoring ALL existing + code to match. One pattern per problem type, across the entire codebase. + +6. **SINGLE SOURCE OF TRUTH.** Every piece of information exists in exactly + one place: + - Enum values → PHP Enum class (not string literals) + - Validation rules → Form Request (not duplicated in frontend) + - Response shape → API Resource (not ad-hoc arrays) + - Config values → .env / config files (not hardcoded) + - Schema definition → SCHEMA.md (not guessed) + +### Code quality + +7. **NO TODO / FIXME / HACK.** Zero tolerance. If you cannot complete + something, stop and report it. Do not leave stubs, placeholders, or + "implement later" comments. Every file you touch must be production-ready. + +8. **NO UNTYPED CODE.** PHP: `declare(strict_types=1)` on every file. Return + types on all methods. Typed properties. Use PHP Enums (not string literals) + for all status, type, and role fields. No `mixed` where a concrete type + or union type would work. + +9. **NO GENERIC NAMES.** Names must be specific and self-documenting: + - ❌ `DataService`, `Helper`, `Manager`, `handleData()`, `processItem()` + - ✅ `ShiftAssignmentService`, `VolunteerAvailabilityChecker`, + `resolveShiftConflict()`, `calculateFillRate()` + +10. **NO SILENT ERROR HANDLING.** No empty catch blocks. No `catch { return + null; }`. Every error must be: logged (via `Log::error()` with context), + or rethrown, or handled with a proper API error response. Use + `report($e)` for unexpected errors. + +### Testing + +11. **TESTS ARE DESIGN, NOT AFTERTHOUGHT.** Tests define expected behaviour. + Every controller needs feature tests covering: + - 200/201 (happy path for each action) + - 401 (unauthenticated access) + - 403 (wrong organisation — cross-tenant access attempt) + - 403 (insufficient role/permission) + - 422 (validation errors with specific field assertions) + - Edge cases specific to the module (e.g., shift conflict, capacity full) + Run `php artisan test` after EVERY module. Fix failures before proceeding. + Never skip, comment out, or mark tests as incomplete. + +12. **FACTORIES ARE REALISTIC.** Use realistic Dutch test data (names, + addresses, company names) that reflects actual usage. Factories must create + valid, complete records — no missing required fields or placeholder values. + +### Data & persistence + +13. **DATA MODEL IS SACRED.** Never deviate from SCHEMA.md. Every column, + every constraint, every index documented there must be in the migration. + If SCHEMA.md is unclear, ask — do not guess. + +14. **EVERY MIGRATION HAS down().** The `down()` method must cleanly reverse + the `up()`. Drop tables, remove columns, restore previous state. No + `down()` methods that throw or do nothing. + +15. **INDEXES ARE MANDATORY.** Every foreign key column, every column used in + WHERE/ORDER BY clauses, every unique constraint from SCHEMA.md must have + an explicit index. Verify composite indexes match the documented patterns. + +### Security & multi-tenancy + +16. **NO UNSCOPED QUERIES.** Every query on event-related models must be + scoped to `organisation_id` via `OrganisationScope`. Mental test: can + User A from Org 1 ever see, modify, or infer the existence of data from + Org 2? If yes → security bug → fix immediately. + +17. **POLICIES ARE COMPLETE.** Every policy method checks: + - Does the user belong to the correct organisation? + - Does the user have the required Spatie role/permission for this action? + - No `return true` placeholders. No missing methods. + +18. **FORM REQUESTS ARE COMPLETE.** Every store/update has a Form Request + with full validation matching SCHEMA.md constraints: required, nullable, + max length, enum values (referencing the PHP Enum), exists rules with + proper scoping (e.g., `exists:events,id` scoped to organisation). + +### API responses + +19. **NO BARE MODEL RETURNS.** Every API response goes through an API + Resource. Never `return $model`, `$model->toArray()`, or raw arrays. + Resources define the public contract. Computed fields (fill_rate, + status_label, slot counts) belong in the Resource. + +20. **CONSISTENT RESPONSE STRUCTURE.** Follow the existing pattern: + `{ data: {...}, meta: {...} }` for paginated lists. Consistent error + format with `{ message: "...", errors: {...} }` for validation failures. + +### Resilience & operations + +21. **IDEMPOTENT OPERATIONS.** Every queued job must be safe to retry. + Check-before-act: verify state hasn't changed. Use database transactions + for multi-step mutations. Queued notifications and external API calls + (Zender SMS/WhatsApp) must handle duplicates gracefully. + +22. **OBSERVABILITY.** Log significant business events using + `spatie/laravel-activitylog` (already installed). Every create, update, + delete, and status change on business entities must be logged with: + - `causedBy($user)` — who did it + - `performedOn($model)` — what was affected + - `withProperties([...])` — relevant context (old values, new values) + +23. **API VERSIONING.** All routes under `/api/v1/`. Controllers in + `App\Http\Controllers\Api\V1\`. Never introduce breaking changes to + existing endpoints — add new fields, don't rename or remove. + +### Process + +24. **MODULE GENERATION ORDER.** Always follow this sequence. No skipping. + 1. PHP Enum(s) for status/type fields (`app/Enums/`) + 2. Migration(s) — verify against SCHEMA.md + 3. Eloquent Model with: HasUlids, HasFactory, SoftDeletes (if documented), + OrganisationScope (if event-related), relationships, scopes, accessors + 4. Factory with realistic Dutch test data + 5. Service class for business logic (`app/Services/`) + 6. Policy for authorisation + 7. Form Request(s) for validation + 8. API Resource for response transformation + 9. Resource Controller (thin — delegates to Service) + 10. Routes in `api/routes/api.php` + 11. Feature tests — run them, fix failures + 12. Activity log integration in Service methods + 13. Update `/dev-docs/API.md` with new routes + +25. **GIT.** Auto-commit after each completed module: + `feat(module-name): add backend scaffold with tests` + +--- + +## VERIFICATION CHECKLIST (run before reporting "done") + +```bash +# All tests pass +php artisan test + +# Database rebuilds cleanly +php artisan migrate:fresh --seed + +# New routes are visible +php artisan route:list --path=api/v1 + +# No forbidden patterns +grep -rn "TODO\|FIXME\|HACK\|dd(\|dump(\|var_dump\|Model::all()" \ + api/app/ api/tests/ --include="*.php" + +# No UUID v4 in migrations +grep -rn "uuid(" api/database/migrations/ --include="*.php" + +# Static analysis (if configured) +./vendor/bin/phpstan analyse +``` + +Manual verification: +- [ ] Every new model has: HasUlids, HasFactory, correct SoftDeletes, complete + $fillable, all relationships from SCHEMA.md +- [ ] Every new model with event data has OrganisationScope +- [ ] Every controller action is covered by a Policy method +- [ ] Every Service method logs activity via spatie/laravel-activitylog +- [ ] Every Form Request references PHP Enums (not string literals) for + enum validation +- [ ] Business logic is in Service classes, not in Controllers +- [ ] API Resource includes computed fields where applicable +- [ ] No N+1: index actions use `with()` for all accessed relationships +- [ ] `/dev-docs/API.md` updated with new routes + +--- + +## TASK + +[INSERT SPECIFIC TASK HERE] diff --git a/dev-docs/MASTER_PROMPT_CURSOR.md b/dev-docs/MASTER_PROMPT_CURSOR.md new file mode 100644 index 00000000..2a72168b --- /dev/null +++ b/dev-docs/MASTER_PROMPT_CURSOR.md @@ -0,0 +1,177 @@ +# Crewli — Cursor Master Prompt +# Plak dit BOVEN elke task. Vervang [TASK] onderaan. + +## MANDATORY PREAMBLE + +Read `@CLAUDE.md` and `@dev-docs/SCHEMA.md` before starting. Use `@workspace` +for full codebase context. These documents are your source of truth. + +If modifying existing code, read the current implementation first. Understand +the patterns already in use before writing anything new. + +## PROJECT CONTEXT + +Crewli — multi-tenant SaaS for event/festival management. + +- **Frontend:** Vue 3 + TypeScript + Vuexy 9.5 (Vuetify 3.10) + Pinia + + TanStack Vue Query + VeeValidate + Zod +- **Three SPAs:** + - `apps/admin/` — Super Admin (port 5173) + - `apps/app/` — Organizer main app (port 5174) + - `apps/portal/` — Dual-mode portal (port 5175) +- **API base:** `VITE_API_URL` from `.env.local` (default `http://localhost:8000`) +- **Axios instance:** `src/lib/axios.ts` — this is the ONLY axios instance. + Never create another. Never import axios directly in components. +- **Backend Enums:** PHP Enums in `api/app/Enums/` define all valid status/type + values. TypeScript equivalents must mirror these exactly in `src/types/`. + +### Frontend file structure (per app) + +``` +src/ +├── lib/axios.ts # Singleton axios instance (DO NOT DUPLICATE) +├── types/ # TypeScript interfaces per module +│ └── [module].ts +├── composables/api/ # TanStack Query composables per module +│ └── use[Module].ts +├── stores/ # Pinia stores (cross-component state only) +│ └── use[Module]Store.ts +├── pages/ # Page components +│ └── [module]/ +│ ├── index.vue # List view +│ └── [id].vue # Detail view (or side panel) +└── router/ # Vue Router config +``` + +--- + +## ZERO-COMPROMISE RULES — VIOLATIONS ARE BLOCKERS + +### TypeScript & typing + +1. **NO `any` TYPES. EVER.** Every variable, prop, emit, return type, ref, + reactive, computed, and API response is fully typed. If you don't know the + type, check the backend API Resource in `api/app/Http/Resources/` — that + defines the contract. Create matching interfaces in `src/types/[module].ts`. + +2. **TYPES FIRST.** Before writing any composable or component for a new + module, create the TypeScript interfaces in `src/types/[module].ts`. These + mirror the backend API Resource shape. Include: + - Entity interface (e.g., `Shift`, `Person`, `Event`) + - Create/Update DTOs (matching backend Form Request fields) + - Enum-like union types or const objects matching backend PHP Enums + - Paginated response wrapper if applicable + +3. **ENUMS AS CONST OBJECTS.** Mirror backend PHP Enums as TypeScript const + objects with `as const`, not as loose string unions scattered across files: + ```typescript + // src/types/shift.ts + export const ShiftAssignmentStatus = { + PENDING_APPROVAL: 'pending_approval', + APPROVED: 'approved', + REJECTED: 'rejected', + CANCELLED: 'cancelled', + COMPLETED: 'completed', + } as const + export type ShiftAssignmentStatus = typeof ShiftAssignmentStatus[keyof typeof ShiftAssignmentStatus] + ``` + +### Architecture & patterns + +4. **NO DIRECT AXIOS IN COMPONENTS.** All API calls go through composables in + `composables/api/use[Module].ts` using TanStack Query (`useQuery` / + `useMutation`). Components never import axios or `src/lib/axios.ts`. + The composable is the only layer that knows about HTTP. + +5. **NO OPTIONS API.** Always `