feat: L'Ami Fiduciaire V1.0.0 — full codebase with Story 0.1 complete
Initial commit of the L'Ami Fiduciaire SaaS platform built on Laravel 12, Vue 3, Inertia.js 2, and Tailwind CSS 4. Story 0.1 (rename folders to declarations in database) is implemented and code-reviewed: migration, rollback, and 6 Pest tests all passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
174
_bmad-output/project-context.md
Normal file
174
_bmad-output/project-context.md
Normal file
@@ -0,0 +1,174 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user