docs: add development prompts and vibe coding checklist

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 19:04:19 +02:00
parent 11e379a5b9
commit ea159a34fe
3 changed files with 619 additions and 0 deletions

View File

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