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:
33
CLAUDE.md
33
CLAUDE.md
@@ -89,9 +89,26 @@ Configure three frontend origins in both Laravel (`config/cors.php` via env) and
|
|||||||
### API calls
|
### API calls
|
||||||
|
|
||||||
- Use TanStack Query (`useQuery` / `useMutation`) for **all** 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
|
- 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
|
### Naming
|
||||||
|
|
||||||
- DB columns: `snake_case`
|
- 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
|
- Always use Vuexy/Vuetify for layout, forms, tables, dialogs
|
||||||
- Do not write custom CSS when a Vuetify utility class exists
|
- Do not write custom CSS when a Vuetify utility class exists
|
||||||
- Responsive: mobile-first, usable from 375px width
|
- 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
|
## 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: hard-code `.env` values in code
|
||||||
- Never: use JSON columns for data you need to filter on
|
- Never: use JSON columns for data you need to filter on
|
||||||
- Never: UUID v4 as primary key (use `HasUlids`)
|
- 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
|
## 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
|
7. Resource controller
|
||||||
8. Register routes in `api.php`
|
8. Register routes in `api.php`
|
||||||
9. Write and run PHPUnit feature tests
|
9. Write and run PHPUnit feature tests
|
||||||
10. Vue composable for API calls (e.g. `useShifts.ts`)
|
10. TypeScript types in `src/types/[module].ts`
|
||||||
11. Pinia store if cross-component state is needed
|
11. API composable in `src/composables/api/use[Module].ts`
|
||||||
12. Vue page component
|
12. Pinia store in `src/stores/use[Module]Store.ts` (only if cross-component state is needed)
|
||||||
13. Add route in Vue Router
|
13. Vue page component in `src/pages/[module]/`
|
||||||
|
14. Add route in Vue Router
|
||||||
|
|
||||||
## User Documentation (VitePress)
|
## User Documentation (VitePress)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user