175 lines
8.0 KiB
Markdown
175 lines
8.0 KiB
Markdown
|
|
---
|
||
|
|
project_name: "l'ami fiduciaire"
|
||
|
|
user_name: 'Saad'
|
||
|
|
date: '2026-03-08'
|
||
|
|
sections_completed: ['technology_stack', 'language_rules', 'framework_rules', 'testing_rules', 'code_quality', 'workflow_rules', 'critical_rules']
|
||
|
|
status: 'complete'
|
||
|
|
rule_count: 52
|
||
|
|
optimized_for_llm: true
|
||
|
|
---
|
||
|
|
|
||
|
|
# Project Context for AI Agents
|
||
|
|
|
||
|
|
_This file contains critical rules and patterns that AI agents must follow when implementing code in this project. Focus on unobvious details that agents might otherwise miss._
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Technology Stack & Versions
|
||
|
|
|
||
|
|
- **Backend:** PHP ^8.2, Laravel 12
|
||
|
|
- **Frontend:** Vue 3.5 (`<script setup lang="ts">`), TypeScript 5.2 (strict mode)
|
||
|
|
- **Bridge:** Inertia.js 2.0 (`@inertiajs/vue3` ^2.3.7)
|
||
|
|
- **Build:** Vite 7.0, `laravel-vite-plugin` 2.0
|
||
|
|
- **Styling:** Tailwind CSS 4.1 (`@tailwindcss/vite`), shadcn-vue (reka-ui)
|
||
|
|
- **Auth:** Laravel Fortify ^1.30
|
||
|
|
- **Media:** spatie/laravel-medialibrary ^11.21
|
||
|
|
- **Logging:** spatie/laravel-activitylog ^4.12
|
||
|
|
- **Enums:** bensampo/laravel-enum ^6.12
|
||
|
|
- **Routes:** laravel/wayfinder ^0.1.9 (type-safe frontend routes)
|
||
|
|
- **Icons:** lucide-vue-next
|
||
|
|
- **CSS Utils:** clsx + tailwind-merge + CVA via `cn()` helper
|
||
|
|
- **Testing:** Pest 4.4, Laravel Pint (PHP formatting)
|
||
|
|
- **JS Tooling:** ESLint 9, Prettier 3.4 (with tailwindcss plugin)
|
||
|
|
|
||
|
|
## Critical Implementation Rules
|
||
|
|
|
||
|
|
### Language-Specific Rules
|
||
|
|
|
||
|
|
**TypeScript:**
|
||
|
|
- Strict mode enabled — never use `any` implicitly (explicit `any` allowed per ESLint config)
|
||
|
|
- MUST use `import type { ... }` for type-only imports (separate statements, not inline `type` specifier)
|
||
|
|
- Import order enforced: builtin → external → internal → parent → sibling → index (alphabetical within groups)
|
||
|
|
- Path alias `@/` maps to `resources/js/` — always use it, never relative paths like `../../`
|
||
|
|
- `isolatedModules: true` — no `const enum`, no namespace merging
|
||
|
|
|
||
|
|
**PHP:**
|
||
|
|
- Model casts: use `protected function casts(): array` method, NOT the `$casts` property
|
||
|
|
- Model mass assignment: always use explicit `$fillable`, never `$guarded = []`
|
||
|
|
- Relationship return types: always add PHPDoc generics `/** @return BelongsTo<Model, $this> */`
|
||
|
|
- Enums: use `bensampo/laravel-enum` — serialize with `->value`, cast in models with Enum class
|
||
|
|
- All controller methods must have explicit return type annotations (`Response`, `RedirectResponse`)
|
||
|
|
- PHP formatting via Laravel Pint — run `composer lint` before committing
|
||
|
|
|
||
|
|
### Framework-Specific Rules
|
||
|
|
|
||
|
|
**Vue 3 + Composition API:**
|
||
|
|
- Always use `<script setup lang="ts">` — never Options API
|
||
|
|
- Define props: `type Props = { ... }` + `defineProps<Props>()`; use `withDefaults()` for defaults
|
||
|
|
- Export form data types from form components for reuse in page components
|
||
|
|
- Composables follow `use` prefix convention (`useCurrentUrl`, `useInitials`)
|
||
|
|
|
||
|
|
**Inertia.js:**
|
||
|
|
- ALL URLs must be passed as props from PHP controllers — never hardcode routes in Vue
|
||
|
|
- Standard forms: `useForm<T>()` with `form.post(props.storeUrl)`
|
||
|
|
- File uploads: use `<Form>` component with `enctype="multipart/form-data"`, NOT `useForm`
|
||
|
|
- Navigation: `router.delete()`, `router.get()`, `router.post()` for programmatic actions
|
||
|
|
- Page titles: always use `<Head title="..." />` component
|
||
|
|
- Shared props accessed via `usePage()` (e.g., `page.props.auth`)
|
||
|
|
|
||
|
|
**Layout System:**
|
||
|
|
- Pages wrap content in `<AppLayout :breadcrumbs="[...]">` — breadcrumbs are required
|
||
|
|
- Auth pages use `<AuthLayout>` wrapper
|
||
|
|
- Settings pages use `settings/Layout.vue` with its own sidebar navigation
|
||
|
|
|
||
|
|
**Laravel Controllers:**
|
||
|
|
- Workspace: resolve from session (`current_workspace_id`), never from URL params
|
||
|
|
- Authorization: custom `authorizeXxx()` protected methods with `abort(404)`, no Gates/Policies
|
||
|
|
- Validation: dedicated Form Request classes, never inline `$request->validate()`
|
||
|
|
- Data shaping: manually build arrays in controllers, no API Resources
|
||
|
|
- Always pass URLs as props via `route()` helper (e.g., `'showUrl' => route('clients.show', $client)`)
|
||
|
|
- Single-action controllers use `__invoke()` method
|
||
|
|
- Enum labels: protected methods on controllers returning label arrays
|
||
|
|
|
||
|
|
### Testing Rules
|
||
|
|
|
||
|
|
- Use Pest syntax (`test()` closures), never PHPUnit class-based tests
|
||
|
|
- Feature tests: `RefreshDatabase` is auto-applied via `Pest.php` — don't add it manually
|
||
|
|
- Test descriptions: lowercase, descriptive strings (`'authenticated users can visit the dashboard'`)
|
||
|
|
- Assertions: prefer Pest's `expect()` chaining over PHPUnit `assert*()` methods
|
||
|
|
- Use `route()` helper for URLs in tests, never hardcoded paths
|
||
|
|
- Feature tests grouped by domain subdirectory mirroring controller structure
|
||
|
|
- Factory states for user roles: `User::factory()->admin()->create()`
|
||
|
|
- Run tests: `composer test` (clears config, runs Pint lint check, then `php artisan test`)
|
||
|
|
- No frontend JS tests configured — testing is PHP-only
|
||
|
|
|
||
|
|
### Code Quality & Style Rules
|
||
|
|
|
||
|
|
**Prettier (enforced):**
|
||
|
|
- Semicolons, single quotes, 4-space indentation, 80 char print width
|
||
|
|
- Tailwind plugin sorts classes in `clsx`, `cn`, `cva` calls
|
||
|
|
- YAML files use 2-space indentation (override)
|
||
|
|
|
||
|
|
**ESLint:**
|
||
|
|
- `vue/multi-word-component-names` is OFF — single-word names allowed
|
||
|
|
- `resources/js/components/ui/*` is ignored — never lint or modify shadcn-vue components
|
||
|
|
- Run `npm run lint` to fix, `npm run format` to format
|
||
|
|
|
||
|
|
**File Naming:**
|
||
|
|
- Vue pages/components: PascalCase (`ClientForm.vue`, `Index.vue`)
|
||
|
|
- Vue page subdirectories: lowercase by domain (`clients/`, `folders/`, `auth/`)
|
||
|
|
- UI component subdirectories: kebab-case (`dropdown-menu/`, `input-otp/`)
|
||
|
|
- TypeScript type files: lowercase (`auth.ts`, `navigation.ts`)
|
||
|
|
- Composables: `use` prefix camelCase (`useCurrentUrl.ts`)
|
||
|
|
- Each UI component group has an `index.ts` barrel file
|
||
|
|
|
||
|
|
**Code Organization:**
|
||
|
|
- Pages: `resources/js/pages/{domain}/{Action}.vue`
|
||
|
|
- Components: `resources/js/components/` (app-level) and `components/ui/` (shadcn-vue)
|
||
|
|
- Types: `resources/js/types/` with barrel `index.ts`
|
||
|
|
- Composables: `resources/js/composables/`
|
||
|
|
- Lib utilities: `resources/js/lib/utils.ts` (`cn()` helper)
|
||
|
|
|
||
|
|
### Development Workflow Rules
|
||
|
|
|
||
|
|
**Local Development:**
|
||
|
|
- Start all services: `composer dev` (runs server + queue + logs + Vite concurrently)
|
||
|
|
- SSR mode: `composer dev:ssr`
|
||
|
|
- Initial setup: `composer setup`
|
||
|
|
|
||
|
|
**CI/CD (GitHub Actions):**
|
||
|
|
- `lint` workflow: Pint + Prettier + ESLint on push/PR to `develop`, `main`, `master`
|
||
|
|
- `tests` workflow: Pest on PHP 8.4/8.5 matrix with Node 22
|
||
|
|
- All code must pass both workflows before merging
|
||
|
|
|
||
|
|
**Before Committing:**
|
||
|
|
- PHP: `composer lint` (Pint)
|
||
|
|
- JS/Vue: `npm run format` then `npm run lint`
|
||
|
|
- Tests: `composer test`
|
||
|
|
|
||
|
|
### Critical Don't-Miss Rules
|
||
|
|
|
||
|
|
**Never Do:**
|
||
|
|
- Never modify `resources/js/components/ui/*` — shadcn-vue auto-generated, use `npx shadcn-vue` to update
|
||
|
|
- Never hardcode routes in Vue — all URLs come from PHP controller props
|
||
|
|
- Never use `$guarded = []` — always explicit `$fillable`
|
||
|
|
- Never use inline `$request->validate()` — always Form Request classes
|
||
|
|
- Never use Gates/Policies — use custom `authorizeXxx()` protected methods with `abort(404)`
|
||
|
|
- Never add `RefreshDatabase` in tests — auto-applied via `Pest.php`
|
||
|
|
|
||
|
|
**Gotchas:**
|
||
|
|
- Workspace is session-based (`current_workspace_id`) — not in URL, not route-model-bound
|
||
|
|
- Nullable enums: use `$model->field?->value` (null-safe) when serializing
|
||
|
|
- Authorization returns `404` not `403` for workspace boundary violations (intentional)
|
||
|
|
- Client-facing routes (`/c/*`) use token-based `folder.invitation` middleware, not `auth`
|
||
|
|
- New business models must add Spatie `LogsActivity` trait + `getActivitylogOptions()` returning `logFillable()->logOnlyDirty()->dontSubmitEmptyLogs()`
|
||
|
|
- New models with files must add Spatie `InteractsWithMedia` trait and implement `HasMedia`
|
||
|
|
- Inertia render paths use lowercase subdirectory: `'clients/Index'`, not `'Clients/Index'`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Usage Guidelines
|
||
|
|
|
||
|
|
**For AI Agents:**
|
||
|
|
- Read this file before implementing any code
|
||
|
|
- Follow ALL rules exactly as documented
|
||
|
|
- When in doubt, prefer the more restrictive option
|
||
|
|
- Update this file if new patterns emerge
|
||
|
|
|
||
|
|
**For Humans:**
|
||
|
|
- Keep this file lean and focused on agent needs
|
||
|
|
- Update when technology stack changes
|
||
|
|
- Review quarterly for outdated rules
|
||
|
|
- Remove rules that become obvious over time
|
||
|
|
|
||
|
|
Last Updated: 2026-03-08
|