docs: migrate frontend conventions from .cursorrules to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 01:07:23 +02:00
parent ef195a6777
commit da2b9ee9e7

View File

@@ -89,9 +89,26 @@ Configure three frontend origins in both Laravel (`config/cors.php` via env) and
### API calls
- Use TanStack Query (`useQuery` / `useMutation`) for **all** API calls
- Never call axios directly from a component — always via a composable under `composables/`
- Never call axios directly from a component — always via a composable under `composables/api/use[Module].ts`
- `src/lib/axios.ts` is the canonical axios instance — the only place axios is imported directly
- Use Pinia stores for cross-component state — no prop drilling
### TypeScript
- No `any` types — ever. Every variable, prop, emit, return type, ref, computed must be fully typed
- Types first: create `src/types/[module].ts` before composables or components
- Mirror backend PHP Enums as `as const` objects in `src/types/`:
```typescript
export const ShiftStatus = { PENDING: 'pending', APPROVED: 'approved' } as const
export type ShiftStatus = typeof ShiftStatus[keyof typeof ShiftStatus]
```
### Forms
- VeeValidate for form state + Zod for schema validation — always together
- Zod schemas must mirror the backend Form Request rules (field names, required/optional, types)
- No inline validation logic in components
### Naming
- DB columns: `snake_case`
@@ -105,6 +122,9 @@ Configure three frontend origins in both Laravel (`config/cors.php` via env) and
- Always use Vuexy/Vuetify for layout, forms, tables, dialogs
- Do not write custom CSS when a Vuetify utility class exists
- Responsive: mobile-first, usable from 375px width
- **Three states per page:** every data-driven view must handle loading (skeleton/spinner), error (`v-alert` with retry button), and empty (helpful message with action button)
- Use Vuetify responsive props (`cols`, `sm`, `md`, `lg`) — no fixed pixel widths
- Custom CSS via `<style scoped>` only as last resort when no Vuetify utility exists
## Forbidden patterns
@@ -114,6 +134,8 @@ Configure three frontend origins in both Laravel (`config/cors.php` via env) and
- Never: hard-code `.env` values in code
- Never: use JSON columns for data you need to filter on
- Never: UUID v4 as primary key (use `HasUlids`)
- Never: TypeScript `any` type (use proper types, generics, or `unknown` with type guards)
- Never: import axios directly in a component (use `src/lib/axios.ts` via a composable)
## Order of work for each new module
@@ -126,10 +148,11 @@ Configure three frontend origins in both Laravel (`config/cors.php` via env) and
7. Resource controller
8. Register routes in `api.php`
9. Write and run PHPUnit feature tests
10. Vue composable for API calls (e.g. `useShifts.ts`)
11. Pinia store if cross-component state is needed
12. Vue page component
13. Add route in Vue Router
10. TypeScript types in `src/types/[module].ts`
11. API composable in `src/composables/api/use[Module].ts`
12. Pinia store in `src/stores/use[Module]Store.ts` (only if cross-component state is needed)
13. Vue page component in `src/pages/[module]/`
14. Add route in Vue Router
## User Documentation (VitePress)