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:
296
dev-docs/MASTER_PROMPT_CC.md
Normal file
296
dev-docs/MASTER_PROMPT_CC.md
Normal 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]
|
||||
177
dev-docs/MASTER_PROMPT_CURSOR.md
Normal file
177
dev-docs/MASTER_PROMPT_CURSOR.md
Normal file
@@ -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 `<script setup lang="ts">`. Props via
|
||||
`defineProps<{...}>()`, emits via `defineEmits<{...}>()`, expose via
|
||||
`defineExpose()`. No `export default { ... }`.
|
||||
|
||||
6. **NO PROP DRILLING.** If state needs to cross more than one component
|
||||
boundary, use a Pinia store (`src/stores/use[Module]Store.ts`). Access
|
||||
reactive state via `storeToRefs()`. Mutations only through store actions.
|
||||
|
||||
7. **DELETE OVER ADAPT.** If you find duplicate composables, overlapping
|
||||
stores, or conflicting patterns: delete the worse version. Do not build
|
||||
alongside existing code that does the same thing. One implementation per
|
||||
concern.
|
||||
|
||||
8. **CONSISTENCY OVER CLEVERNESS.** Look at how existing modules handle the
|
||||
same pattern (table views, form dialogs, detail panels, error handling).
|
||||
Use the exact same approach. Never introduce a "better" alternative without
|
||||
refactoring ALL existing modules to match.
|
||||
|
||||
9. **SINGLE SOURCE OF TRUTH.** Don't duplicate:
|
||||
- Validation logic → Zod schema mirrors backend Form Request. One schema
|
||||
per form, referenced by VeeValidate.
|
||||
- Enum values → const objects in `src/types/`, matching backend Enums.
|
||||
Never use raw string literals like `'approved'` in templates or logic.
|
||||
- API URLs → constructed in composable from module prefix, never
|
||||
hardcoded in components.
|
||||
|
||||
### UI & UX
|
||||
|
||||
10. **NO CUSTOM CSS WHERE VUETIFY HAS A SOLUTION.** Before writing any CSS:
|
||||
check if a Vuetify utility class, component prop, or slot achieves the
|
||||
result. Custom CSS is a last resort, must be `<style scoped>`, and must
|
||||
have a comment explaining why Vuetify couldn't handle it.
|
||||
|
||||
11. **EVERY PAGE HAS THREE STATES:**
|
||||
- **Loading:** Vuetify skeleton loader or progress indicator
|
||||
- **Error:** User-facing message with retry action (`v-alert` with retry
|
||||
button). Show what went wrong in user terms, not technical jargon.
|
||||
- **Empty:** Helpful message explaining why the list is empty and what
|
||||
action to take (not a blank white screen).
|
||||
Never show only the happy path.
|
||||
|
||||
12. **MOBILE-FIRST.** Every component must be usable at 375px width. Use
|
||||
Vuetify's responsive props (`cols`, `sm`, `md`, `lg` on `v-col`). Never
|
||||
use fixed pixel widths for layout. Tables on mobile → card views or
|
||||
horizontal scroll with visual indicator.
|
||||
|
||||
13. **FORMS USE VEEVALIDATE + ZOD.** Define the Zod schema matching the
|
||||
backend Form Request rules. No inline validation logic in templates. Use
|
||||
`useForm()` and `useField()` from VeeValidate with the Zod resolver.
|
||||
|
||||
### Code quality
|
||||
|
||||
14. **NO TODO / FIXME / HACK.** Complete the implementation or report the
|
||||
blocker. No stubs, no "implement later", no placeholder components.
|
||||
|
||||
15. **NO ORPHANED IMPORTS OR UNUSED VARIABLES.** Run `npx tsc --noEmit`
|
||||
after every change. Zero errors, zero warnings. Dead code is deleted
|
||||
immediately, not commented out.
|
||||
|
||||
16. **NO GENERIC NAMES.** Component and composable names must be specific:
|
||||
- ❌ `DataTable.vue`, `useApi.ts`, `helpers.ts`, `utils.ts`
|
||||
- ✅ `ShiftAssignmentTable.vue`, `useShifts.ts`,
|
||||
`formatShiftTimeRange.ts`
|
||||
|
||||
### Routing & auth
|
||||
|
||||
17. **ROUTER GUARDS.** Protected routes check auth state via navigation
|
||||
guard. Portal routes validate token. No unguarded routes to
|
||||
authenticated content. Redirect to login on 401.
|
||||
|
||||
### Process
|
||||
|
||||
18. **COMPONENT CREATION ORDER.** For every new page/feature:
|
||||
1. TypeScript types in `src/types/[module].ts`
|
||||
2. API composable in `src/composables/api/use[Module].ts`
|
||||
3. Pinia store in `src/stores/use[Module]Store.ts` (if cross-component)
|
||||
4. Vue page component in `src/pages/[module]/`
|
||||
5. Router entry in `src/router/`
|
||||
|
||||
19. **VERIFY BEFORE DONE:**
|
||||
- `npx tsc --noEmit` — zero errors
|
||||
- No `any` types anywhere (search: `grep -rn ": any\|as any" src/`)
|
||||
- No TODO/FIXME/HACK
|
||||
- All three states (loading, error, empty) implemented
|
||||
- Mobile responsive at 375px
|
||||
- Consistent with existing module patterns
|
||||
|
||||
---
|
||||
|
||||
## TASK
|
||||
|
||||
[INSERT SPECIFIC TASK HERE]
|
||||
146
dev-docs/VIBE_CODING_CHECKLIST.md
Normal file
146
dev-docs/VIBE_CODING_CHECKLIST.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Crewli — Zero-Compromise Vibe Coding Aandachtspunten
|
||||
|
||||
Referentiedocument voor het aansturen van AI agents (Claude Code & Cursor).
|
||||
Alle 18 principes zijn verwerkt in de master prompts. Dit document dient als
|
||||
overzicht en review-checklist.
|
||||
|
||||
---
|
||||
|
||||
## De 18 principes — waar ze landen
|
||||
|
||||
| # | Principe | Master Prompt CC | Master Prompt Cursor | Sectie |
|
||||
|---|----------|:---:|:---:|--------|
|
||||
| 1 | Architectuur eerst | ✅ Regel 1 | — | Architecture & design |
|
||||
| 2 | Delete > Adapt | ✅ Regel 2 | ✅ Regel 7 | Architecture & design |
|
||||
| 3 | Strict layering | ✅ Regel 3 | ✅ Regel 4, 6 | Architecture & design |
|
||||
| 4 | Contract-first | ✅ Regel 4 | ✅ Regel 2, 3 | Architecture & design |
|
||||
| 5 | Tests als design | ✅ Regel 11, 12 | — | Testing |
|
||||
| 6 | Idempotency & resilience | ✅ Regel 21 | — | Resilience & operations |
|
||||
| 7 | Naming is architecture | ✅ Regel 9 | ✅ Regel 16 | Code quality |
|
||||
| 8 | Security & auth direct goed | ✅ Regel 16, 17 | ✅ Regel 17 | Security & multi-tenancy |
|
||||
| 9 | Performance by design | ✅ Checklist | ✅ (via composable pattern) | Verification |
|
||||
| 10 | Consistency > cleverness | ✅ Regel 5 | ✅ Regel 8 | Architecture & design |
|
||||
| 11 | Observability dag 1 | ✅ Regel 22 | — | Resilience & operations |
|
||||
| 12 | Versioning & backward compat | ✅ Regel 23 | — | Resilience & operations |
|
||||
| 13 | Data model = heilig | ✅ Regel 13, 14, 15 | — | Data & persistence |
|
||||
| 14 | Prompt discipline | ✅ Hele structuur | ✅ Hele structuur | (Meta) |
|
||||
| 15 | Perfectie vs. pragmatiek | ✅ Regel 3 + 5 | ✅ Regel 8 | Architecture & design |
|
||||
| 16 | Zero TODO | ✅ Regel 7 | ✅ Regel 14 | Code quality |
|
||||
| 17 | Single Source of Truth | ✅ Regel 6 | ✅ Regel 9 | Architecture & design |
|
||||
| 18 | Definition of Done | ✅ Checklist | ✅ Regel 19 | Verification |
|
||||
|
||||
---
|
||||
|
||||
## Projectspecifieke aandachtspunten (bovenop de 18)
|
||||
|
||||
### Bestandspaden — correcte referenties
|
||||
|
||||
| Wat | Correct pad | Fout (oude pad) |
|
||||
|-----|-------------|-----------------|
|
||||
| Schema definitie | `/dev-docs/SCHEMA.md` | `/docs/SCHEMA.md` |
|
||||
| API contract | `/dev-docs/API.md` | `/docs/API.md` |
|
||||
| Design document | `/dev-docs/design-document.md` | `/docs/design-document.md` |
|
||||
| Dev guide | `/dev-docs/dev-guide.md` | `/docs/dev-guide.md` |
|
||||
| User docs (VitePress) | `/docs/` | — |
|
||||
| Workspace rules | `/CLAUDE.md` (root) | — |
|
||||
| Axios instance (app) | `apps/app/src/lib/axios.ts` | `src/utils/api.ts` etc. |
|
||||
|
||||
### PHP Enums — verplicht voor alle status/type velden
|
||||
|
||||
Agents gebruiken graag string literals. Dwing af:
|
||||
|
||||
```php
|
||||
// ❌ VERBODEN
|
||||
$assignment->status = 'approved';
|
||||
Rule::in(['pending_approval', 'approved', 'rejected'])
|
||||
|
||||
// ✅ VERPLICHT
|
||||
$assignment->status = ShiftAssignmentStatus::APPROVED;
|
||||
Rule::enum(ShiftAssignmentStatus::class)
|
||||
```
|
||||
|
||||
Alle bestaande/verwachte Enums (uit SCHEMA.md):
|
||||
- `BillingStatus` — trial|active|suspended|cancelled
|
||||
- `EventStatus` — draft|published|active|completed|archived
|
||||
- `PersonStatus` — invited|applied|pending|approved|rejected|no_show
|
||||
- `ShiftAssignmentStatus` — pending_approval|approved|rejected|cancelled|completed
|
||||
- `InvitationStatus` — pending|accepted|expired|revoked
|
||||
- `CrowdListType` — internal|external
|
||||
- `BookingStatus` — pending|offer_sent|confirmed|cancelled|declined
|
||||
- `AdvanceSectionStatus` — not_started|in_progress|submitted|approved
|
||||
|
||||
### Service Layer — wanneer wel/niet
|
||||
|
||||
**Gebruik een Service class wanneer:**
|
||||
- Business logic meer is dan "opslaan wat de FormRequest valideert"
|
||||
- Meerdere modellen gewijzigd worden in één actie
|
||||
- Side effects nodig zijn (notifications, activity log, queue jobs)
|
||||
- Dezelfde logica vanuit meerdere controllers aangeroepen kan worden
|
||||
|
||||
**Voorbeelden in Crewli:**
|
||||
- `ShiftAssignmentService` — assign, claim, approve, reject (status machine + notifications)
|
||||
- `PersonIdentityService` — deduplicatie, user_id matching
|
||||
- `AccreditationService` — toekennen, intrekken, budget checks
|
||||
- `ZenderService` — SMS/WhatsApp via externe API
|
||||
|
||||
**Geen Service nodig voor:**
|
||||
- Simpele CRUD zonder business logic (locations, crowd_types, accreditation_categories)
|
||||
- Hier volstaat de controller direct
|
||||
|
||||
### Spatie Activity Log — verplicht gebruik
|
||||
|
||||
```php
|
||||
// In elke Service method die state wijzigt:
|
||||
activity()
|
||||
->causedBy($user)
|
||||
->performedOn($shift)
|
||||
->withProperties([
|
||||
'old' => ['status' => $oldStatus->value],
|
||||
'new' => ['status' => $newStatus->value],
|
||||
])
|
||||
->log('shift.assignment.approved');
|
||||
```
|
||||
|
||||
### Multi-tenancy mentale test
|
||||
|
||||
Bij elke nieuwe controller, voer deze test uit:
|
||||
1. Maak in je hoofd twee organisaties: Org A en Org B
|
||||
2. Gebruiker X hoort bij Org A
|
||||
3. Kan X via de API data van Org B zien? → BUG
|
||||
4. Kan X via de API data van Org B wijzigen? → CRITICAL BUG
|
||||
5. Kan X via de API afleiden dat data van Org B bestaat? → SECURITY ISSUE
|
||||
|
||||
### Idempotency checklist voor queued jobs
|
||||
|
||||
Elke Job moet deze vragen beantwoorden:
|
||||
- Wat gebeurt er als deze job 2x draait? → Geen dubbele side effects
|
||||
- Wat als het model intussen verwijderd is? → Graceful exit, geen crash
|
||||
- Wat als de externe API (Zender) een timeout geeft? → Retry met backoff
|
||||
- Wat als de status intussen veranderd is? → Check-before-act
|
||||
|
||||
---
|
||||
|
||||
## Review checklist — na elke Claude Code / Cursor sessie
|
||||
|
||||
### Backend (Claude Code output)
|
||||
- [ ] Geen TODO/FIXME/HACK (`grep -rn "TODO\|FIXME\|HACK" api/app/`)
|
||||
- [ ] Geen UUID v4 (`grep -rn "uuid(" api/database/migrations/`)
|
||||
- [ ] Geen `Model::all()` zonder scope
|
||||
- [ ] Geen business logic in controllers (alleen HTTP + delegate to Service)
|
||||
- [ ] PHP Enums gebruikt (niet string literals)
|
||||
- [ ] Activity log in Service methods
|
||||
- [ ] Tests draaien groen (`php artisan test`)
|
||||
- [ ] Migratie heeft `down()` method
|
||||
- [ ] Policies compleet (geen `return true` placeholders)
|
||||
- [ ] N+1 check: `with()` in index/show actions
|
||||
- [ ] `/dev-docs/API.md` bijgewerkt
|
||||
|
||||
### Frontend (Cursor output)
|
||||
- [ ] Geen `any` types (`grep -rn ": any\|as any" apps/*/src/`)
|
||||
- [ ] Geen directe axios imports in components
|
||||
- [ ] Types gedefinieerd in `src/types/`
|
||||
- [ ] Drie states: loading, error, empty
|
||||
- [ ] Zod schema voor formulieren
|
||||
- [ ] Vuetify componenten (geen onnodige custom CSS)
|
||||
- [ ] Mobile responsive op 375px
|
||||
- [ ] `npx tsc --noEmit` groen
|
||||
Reference in New Issue
Block a user