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
|
||||
|
||||
- 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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user