Architecture doc fixes:
- Replace `deadline` → `due_date` in all code examples (5 occurrences)
- Replace `Declaration::workspace($workspace)` → `Declaration::where('workspace_id', ...)`
(no such query scope exists; workspace() is a BelongsTo relationship)
- Add missing `mise_en_demeure` status to transition table and flow diagram
- Update transition rules: en_attente_client can transition to mise_en_demeure
Project context additions:
- Document WorkspaceUser pivot fields and withPivot requirement
- Document correct column name (due_date not deadline)
- Document Declaration scoping pattern (no workspace scope)
- Document all 6 declaration statuses including mise_en_demeure
Resolves Epic 2 retro action items A3, A4 (carried since Epic 1).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9.1 KiB
9.1 KiB
project_name, user_name, date, sections_completed, status, rule_count, optimized_for_llm
| project_name | user_name | date | sections_completed | status | rule_count | optimized_for_llm | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| l'ami fiduciaire | Saad | 2026-03-08 |
|
complete | 52 | 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-plugin2.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
anyimplicitly (explicitanyallowed per ESLint config) - MUST use
import type { ... }for type-only imports (separate statements, not inlinetypespecifier) - Import order enforced: builtin → external → internal → parent → sibling → index (alphabetical within groups)
- Path alias
@/maps toresources/js/— always use it, never relative paths like../../ isolatedModules: true— noconst enum, no namespace merging
PHP:
- Model casts: use
protected function casts(): arraymethod, NOT the$castsproperty - 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 lintbefore committing
Framework-Specific Rules
Vue 3 + Composition API:
- Always use
<script setup lang="ts">— never Options API - Define props:
type Props = { ... }+defineProps<Props>(); usewithDefaults()for defaults - Export form data types from form components for reuse in page components
- Composables follow
useprefix convention (useCurrentUrl,useInitials)
Inertia.js:
- ALL URLs must be passed as props from PHP controllers — never hardcode routes in Vue
- Standard forms:
useForm<T>()withform.post(props.storeUrl) - File uploads: use
<Form>component withenctype="multipart/form-data", NOTuseForm - 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.vuewith its own sidebar navigation
Laravel Controllers:
- Workspace: resolve from session (
current_workspace_id), never from URL params - Authorization: custom
authorizeXxx()protected methods withabort(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:
RefreshDatabaseis auto-applied viaPest.php— don't add it manually - Test descriptions: lowercase, descriptive strings (
'authenticated users can visit the dashboard') - Assertions: prefer Pest's
expect()chaining over PHPUnitassert*()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, thenphp 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,cvacalls - YAML files use 2-space indentation (override)
ESLint:
vue/multi-word-component-namesis OFF — single-word names allowedresources/js/components/ui/*is ignored — never lint or modify shadcn-vue components- Run
npm run lintto fix,npm run formatto 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:
useprefix camelCase (useCurrentUrl.ts) - Each UI component group has an
index.tsbarrel file
Code Organization:
- Pages:
resources/js/pages/{domain}/{Action}.vue - Components:
resources/js/components/(app-level) andcomponents/ui/(shadcn-vue) - Types:
resources/js/types/with barrelindex.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):
lintworkflow: Pint + Prettier + ESLint on push/PR todevelop,main,mastertestsworkflow: 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 formatthennpm run lint - Tests:
composer test
Critical Don't-Miss Rules
Never Do:
- Never modify
resources/js/components/ui/*— shadcn-vue auto-generated, usenpx shadcn-vueto 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 withabort(404) - Never add
RefreshDatabasein tests — auto-applied viaPest.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
404not403for workspace boundary violations (intentional) - Client-facing routes (
/c/*) use token-basedfolder.invitationmiddleware, notauth - New business models must add Spatie
LogsActivitytrait +getActivitylogOptions()returninglogFillable()->logOnlyDirty()->dontSubmitEmptyLogs() - New models with files must add Spatie
InteractsWithMediatrait and implementHasMedia - Inertia render paths use lowercase subdirectory:
'clients/Index', not'Clients/Index' - WorkspaceUser pivot fields: The
workspace_userpivot table hasrole(cast toWorkspaceUserRoleenum) andpermissions(cast to array). BothUser::workspaces()andWorkspace::users()use->withPivot('role', 'permissions'). Access via$user->workspaces()->first()->pivot->role. TheWorkspaceUsermodel extendsPivot(notModel) — usePivot::query()for direct queries, notWorkspaceUser::find(). When eager-loading workspace members for controllers, always chain->withPivot('role', 'permissions')or the pivot data will be silently null. - Declaration column name: The date column is
due_date, NOTdeadline— some older docs may referencedeadlineincorrectly - Declaration scoping: There is no
Declaration::workspace()query scope. UseDeclaration::where('workspace_id', $workspace->id)instead. The model hasactive(),archived(), andforUser()scopes. - Declaration statuses: 6 values —
created,en_cours,en_attente_client,mise_en_demeure,termine,ferme. Themise_en_demeurestatus is a formal notice branch fromen_attente_client.
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-24