# Architecture du projet

## Structure des dossiers

```
project/
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Admin/                    # Controllers back-office
│   │   │   │   ├── DashboardController.php
│   │   │   │   ├── PageController.php
│   │   │   │   ├── BlockController.php
│   │   │   │   ├── MenuController.php
│   │   │   │   ├── MenuItemController.php
│   │   │   │   ├── MediaController.php
│   │   │   │   ├── SettingsController.php
│   │   │   │   └── TemplateController.php
│   │   │   └── Front/                    # Controllers front-office
│   │   │       ├── PageController.php
│   │   │       └── HomeController.php
│   │   └── Middleware/
│   │       ├── AdminAccess.php
│   │       └── HandleInertiaRequests.php
│   ├── Models/
│   │   ├── Page.php
│   │   ├── Block.php
│   │   ├── Template.php
│   │   ├── Menu.php
│   │   ├── MenuItem.php
│   │   ├── MenuLocation.php
│   │   ├── Media.php
│   │   ├── Setting.php
│   │   └── User.php
│   └── Services/
│       ├── PageService.php
│       ├── MenuService.php
│       ├── MediaService.php
│       └── SettingsService.php
│
├── resources/
│   └── js/
│       ├── blocks/                       # Registre partagé back + front
│       │   ├── index.js                  # Registre central
│       │   ├── schema.js                 # SOURCE DE VÉRITÉ des props
│       │   ├── core/                     # Blocs génériques
│       │   │   ├── HeroBlock/
│       │   │   │   ├── Back.vue
│       │   │   │   └── Front.vue
│       │   │   ├── TextBlock/
│       │   │   ├── ImageBlock/
│       │   │   ├── GalleryBlock/
│       │   │   ├── ButtonBlock/
│       │   │   ├── DividerBlock/
│       │   │   └── ColumnsBlock/
│       │   └── metier/
│       │       ├── PropertyListBlock/
│       │       ├── PropertyCardBlock/
│       │       ├── BookingFormBlock/
│       │       ├── AvailabilityCalendarBlock/
│       │       ├── MapBlock/
│       │       ├── ReviewsBlock/
│       │       └── ContactFormBlock/
│       │
│       ├── backoffice/                   # Application Quasar
│       │   ├── app.js
│       │   ├── layouts/
│       │   │   └── AdminLayout.vue
│       │   ├── components/
│       │   │   ├── builder/
│       │   │   │   ├── PageBuilder.vue
│       │   │   │   ├── BuilderCanvas.vue
│       │   │   │   ├── BlockPanel.vue
│       │   │   │   └── PropsEditor.vue
│       │   │   ├── menus/
│       │   │   └── media/
│       │   └── pages/
│       │
│       └── frontoffice/                  # Application Vue publique
│           ├── app.js
│           ├── layouts/
│           │   └── SiteLayout.vue
│           ├── components/
│           │   ├── NavMenu.vue
│           │   └── BlockRenderer.vue
│           └── pages/
│               ├── DynamicPage.vue
│               └── NotFound.vue
│
├── routes/
│   ├── web.php                           # Routes front-office
│   └── admin.php                         # Routes back-office
│
└── database/
    └── migrations/
```

---

## Flux de données — Front-office

```
Visiteur → GET /{slug}
               │
               ▼
    Front\PageController::show()
               │
               ├─ Page::with(['blocks','template'])->whereSlug($slug)
               ├─ MenuService::all()        (cache Redis)
               └─ SettingsService::shared() (cache Redis)
               │
               ▼
    Inertia::render('Templates/{template}', [
        'page'     => $page,
        'blocks'   => $page->blocks->groupBy('zone'),
        'menus'    => $menus,
        'settings' => $settings,
    ])
               │
               ▼
    Vue résout le template → injecte les blocs par zone
    BlockRenderer.vue résout chaque bloc → Front.vue du bloc
```

## Flux de données — Sauvegarde back-office

```
Admin → PUT /admin/pages/{id}/blocks
               │
               ▼
    Admin\BlockController::sync()
               │
               ├─ Valide les types (existent dans schema.js ?)
               ├─ PageService::syncBlocks($page, $blocks)
               │   ├─ Supprime les blocs existants
               │   └─ Recrée dans l'ordre reçu
               └─ Cache invalidé pour cette page
```

## Injection Inertia globale

Les données suivantes sont disponibles dans TOUTES les pages Vue via usePage().props :

```php
// HandleInertiaRequests.php
public function share(Request $request): array
{
    return [
        'auth'     => $request->user(),
        'menus'    => MenuService::all(),
        'settings' => SettingsService::shared(),
    ];
}
```

---

## Règles d'architecture

- Un Controller : valider → appeler Service → retourner Inertia/JSON. Rien de plus.
- Un Service : toute la logique métier et la gestion du cache.
- Le cache est géré exclusivement dans les Services.
- Les blocs front-office ne connaissent pas Inertia — props uniquement.
- Back-office et front-office ne partagent aucun composant Vue, seulement les schémas.
- Pas de hooks, pas de filtres, pas d'events CMS — logique directe uniquement.
