# Architecture — L'Ami Fiduciaire

> Generated: 2026-03-08 | Scan Level: Quick

## Executive Summary

L'Ami Fiduciaire is a full-stack web application built for fiduciary/accounting firm client management. It provides a multi-tenant workspace system where firms can manage clients, folders (dossiers), and document exchanges with external clients via email-based invitation links.

The application follows a **server-driven SPA** architecture using Laravel 12 as the backend with Inertia.js v2 bridging to a Vue 3 frontend. This eliminates the need for a separate API layer — controllers render Vue pages directly via Inertia, while Wayfinder generates TypeScript route functions for type-safe navigation.

## Architecture Pattern

**Pattern:** Full-Stack Monolith with Server-Driven SPA (Inertia.js)

```
┌─────────────────────────────────────────────────────┐
│                    Browser (SPA)                     │
│  Vue 3 + TypeScript + Tailwind CSS 4 + shadcn-vue   │
│         Inertia.js Client → Page Components          │
└──────────────────────┬──────────────────────────────┘
                       │  XHR / Inertia Protocol
┌──────────────────────▼──────────────────────────────┐
│               Laravel 12 (PHP 8.4)                   │
│  ┌─────────────────────────────────────────────┐    │
│  │  Middleware Pipeline                         │    │
│  │  (Auth, Workspace, Admin, Inertia, etc.)     │    │
│  └──────────────────┬──────────────────────────┘    │
│  ┌──────────────────▼──────────────────────────┐    │
│  │  Controllers → Inertia::render('Page', props)│    │
│  └──────────────────┬──────────────────────────┘    │
│  ┌──────────────────▼──────────────────────────┐    │
│  │  Eloquent ORM → Models + Relationships       │    │
│  └──────────────────┬──────────────────────────┘    │
└──────────────────────┼──────────────────────────────┘
                       │
┌──────────────────────▼──────────────────────────────┐
│              MySQL 8.4 (via Docker/Sail)             │
└─────────────────────────────────────────────────────┘
```

## Technology Stack

| Category | Technology | Version |
|----------|-----------|---------|
| Backend Framework | Laravel | 12.x |
| Backend Language | PHP | 8.2+ (8.4 runtime) |
| Frontend Framework | Vue.js | 3.5+ |
| Frontend Language | TypeScript | 5.2+ |
| SPA Bridge | Inertia.js | v2 |
| CSS Framework | Tailwind CSS | 4.x |
| UI Components | shadcn-vue (reka-ui) | 2.4+ |
| Build Tool | Vite | 7.x |
| Database | MySQL | 8.4 |
| Authentication | Laravel Fortify | v1 |
| Route Generation | Laravel Wayfinder | 0.1.x |
| File Management | Spatie Media Library | 11.x |
| Activity Logging | Spatie Activity Log | 4.x |
| Enums | bensampo/laravel-enum | 6.x |
| Testing | Pest | 4.x |
| Code Style (PHP) | Laravel Pint | 1.x |
| Code Style (JS) | ESLint 9 + Prettier 3 | - |
| Containerization | Docker / Laravel Sail | - |
| WebSockets | Soketi | latest |
| Mail Testing | Mailpit | latest |

## Data Architecture

### Eloquent Models

| Model | Table | Key Relationships |
|-------|-------|-------------------|
| User | users | belongsToMany(Workspace), hasMany(Client) |
| Workspace | workspaces | belongsToMany(User) via WorkspaceUser |
| WorkspaceUser | workspace_user | Pivot: user_id, workspace_id, role |
| Client | clients | belongsTo(Workspace), hasMany(Folder) |
| Folder | folders | belongsTo(Client), hasMany(Message), hasMany(FolderInvitation), media |
| FolderInvitation | folder_invitations | belongsTo(Folder) — token-based access |
| Message | messages | belongsTo(Folder) |

### Business Enums

| Enum | Purpose |
|------|---------|
| ActorType | Distinguishes user types in activity logs |
| ClientStatus | Client lifecycle status |
| FolderPriority | Folder urgency level |
| FolderStatus | Folder workflow status |
| FolderType | Category of folder/dossier |
| LegalForm | Legal entity type for clients |
| MessageType | Type of message in folder |
| UserGroup | User permission group |
| WorkspaceUserRole | Role within a workspace |

### Database Migrations (16 files)

- Core: users, cache, jobs tables
- Auth: two-factor columns on users
- Multi-tenant: workspaces, workspace_user
- Business: clients, folders, folder_invitations, messages
- Packages: activity_log, media tables
- Extensions: confirmation fields on folders, responsable/suivi fields on clients

## Authentication & Authorization

- **Laravel Fortify** provides headless auth: login, registration, password reset, email verification, two-factor authentication (TOTP)
- **Custom Middleware:**
  - `EnsureUserIsAdmin` — Admin-only route protection (users, workspaces management)
  - `EnsureUserHasWorkspace` — Workspace context enforcement
  - `ValidateFolderInvitation` — Token-based access for external client portal
  - `HandleInertiaRequests` — Shares auth/workspace data with frontend
  - `HandleAppearance` — Theme/appearance persistence

## Route Architecture

### Authenticated Routes (auth + verified)
- `GET /dashboard` — DashboardController (invokable)
- `POST /workspace/switch` — WorkspaceSwitchController (invokable)

### Workspace-Scoped Routes (auth + verified + workspace)
- `CRUD /clients` — ClientController (resource)
- `CRUD /folders` — FolderController (resource)
- `POST /folders/{folder}/messages` — FolderMessageController
- `POST /folders/{folder}/media` — FolderMediaController (upload)
- `GET /folders/{folder}/media/{mediaId}` — FolderMediaController (download)

### Admin Routes (auth + verified + admin)
- `CRUD /users` — UserController (resource)
- `CRUD /workspaces` — WorkspaceController (resource)

### Public Client Portal (/c/ prefix, folder.invitation middleware)
- `GET|POST /c/upload/{token}` — Client file upload
- `GET|POST /c/confirm/{token}` — Client folder confirmation
- `GET|POST /c/refuse/{token}` — Client folder refusal

### Settings Routes (auth / auth+verified)
- `GET|PATCH /settings/profile` — Profile management
- `DELETE /settings/profile` — Account deletion
- `GET|PUT /settings/password` — Password change (throttled)
- `GET /settings/appearance` — Appearance/theme settings
- `GET /settings/two-factor` — Two-factor authentication management

## Email System

5 folder-related mailables handle client communication:
- **FolderInviteMail** — Invitation to access a folder
- **FolderFileRequestMail** — Request for file upload
- **FolderConfirmationMail** — Folder confirmation notification
- **FolderSituationMail** — Folder status update
- **FolderTextMessageMail** — Text message notification

## Frontend Architecture

### Component Organization
- **Pages** (31 Vue components): Mapped to routes via Inertia, organized by domain (auth, clients, folders, users, workspaces, settings, client portal)
- **Layouts** (8 components): AppLayout (sidebar/header variants), AuthLayout (card/simple/split variants), SettingsLayout
- **UI Components**: shadcn-vue design system with 20+ component groups (Button, Card, Dialog, Dropdown, Input, Select, Table, Tabs, Tooltip, etc.)
- **Business Components**: ClientForm, FolderForm, UserForm, WorkspaceForm, WorkspaceSwitcher, Pagination
- **Composables** (4): useAppearance, useCurrentUrl, useInitials, useTwoFactorAuth

### State Management
- No client-side store (Redux/Pinia) — state is server-driven via Inertia props
- `useForm()` from Inertia handles form state and submission
- Composables for shared client-side logic

### Type System
- TypeScript strict mode across all frontend code
- Type definitions in `resources/js/types/` (auth, navigation, UI types)
- Wayfinder generates typed route functions

## Testing Strategy

- **Framework:** Pest 4 (PHPUnit 12 compatible)
- **Test Suites:** Feature (13 test files) + Unit
- **Coverage Areas:** Authentication, settings, dashboard, user groups
- **Factories:** Model factories for test data generation
- **CI Matrix:** PHP 8.4 and 8.5

## CI/CD Pipeline

### Lint Workflow (`lint.yml`)
- Triggers: push/PR to develop, main, master, workos
- Steps: PHP setup → Composer install → npm install → Pint → Prettier → ESLint

### Test Workflow (`tests.yml`)
- Triggers: push/PR to develop, main, master, workos
- Matrix: PHP 8.4, 8.5
- Steps: PHP setup → Node 22 → Composer install → npm install → env setup → key generation → Vite build → Pest

## Deployment Configuration

### Docker Compose (Laravel Sail)
- **laravel.test** — PHP 8.5 application container (port 80, Vite 5173)
- **mysql** — MySQL 8.4 database (port 3306)
- **mailpit** — Email testing UI (ports 1025, 8025)
- **soketi** — WebSocket server / Pusher-compatible (port 6001)

### SSR Support
- Inertia SSR is enabled (`inertia.php` → `ssr.enabled = true`)
- SSR entry point: `resources/js/ssr.ts`
- SSR server URL: `http://127.0.0.1:13714`
