# Dashboard widgets personnalisables

## Vue d'ensemble

La page d'accueil (`/dashboard`) affiche une grille de **widgets** configurables par utilisateur (positions, tailles).  
Chaque widget est visible uniquement si l'utilisateur possède les **permissions fonctionnelles** requises (voir `docs/droits.md`).

## Données

| Élément | Description |
|---------|-------------|
| `user_dashboard_widgets` | Layout par utilisateur (`widget_key`, `position_x/y`, `width`, `height`, `config`) |
| `config/dashboard_widgets.php` | Catalogue (titre, catégorie, permissions, tailles par défaut) |

## API (authentifié)

| Méthode | Route | Rôle |
|---------|-------|------|
| GET | `/api/dashboard/widgets-disponibles` | Widgets du catalogue non encore placés |
| GET | `/api/dashboard/widget/{key}/data` | Données widget (cache fichier 5 min) |
| POST | `/api/dashboard/layout` | Sauvegarde complète du layout |
| DELETE | `/api/dashboard/widget/{key}` | Retire un widget |

## Widgets (10)

| Clé | Permission(s) requise(s) |
|-----|--------------------------|
| `appels_de_fonds_en_retard` | `programmes.appels_de_fonds.lecture` |
| `factures_a_valider` | `factures.validation_nv1` ou `factures.validation_nv2` |
| `leads_marketing_recents` | `leads_marketing.lecture` |
| `synthese_chantier` | `marches.lecture` |
| `tresorerie_consolidee` | `bilan.lecture` |
| `synthese_commerciale` | `commercialisation.lecture` |
| `demandes_fournisseurs` | `demandes_fournisseurs.validation` |
| `synchros_intacct` | `intacct.synchro.lecture` |
| `calendrier` | `programmes.lecture` |
| `documents_recents` | `documents.lecture` |

## Layout par défaut

À la première visite (`UserDashboardLayoutService::ensureDefaultLayout`), un layout est créé selon le profil :

- **GS_COMPTABILITE** : factures, demandes fournisseurs, Intacct, appels de fonds en retard
- **GS_DIRECTION_GENERALE** : trésorerie, commercial, chantier, leads marketing
- **Autres** : synthèse chantier, calendrier, documents, factures à valider (avec variantes conducteur / commercial)

Seeder global : `php artisan db:seed --class=DashboardSeeder` (utilisateurs sans widgets existants).

## Interface

- **Mode édition** : drag & drop et redimensionnement (`grid-layout-plus`, 12 colonnes desktop / 1 mobile)
- **Ajouter un widget** : modale filtrée par permissions
- Chargement asynchrone des données avec skeleton ; erreur isolée par widget

## Services backend

- `WidgetCatalogService` — catalogue filtré par `PermissionService`
- `WidgetDataService` — agrégation métier + cache `widget:{key}:user:{id}`
- `DashboardDefaultLayoutService` — layout initial par rôle M365
- `UserDashboardLayoutService` — lecture / écriture layout utilisateur

## Composants Vue

- `Pages/Dashboard/Index.vue` — page principale
- `Components/Dashboard/DashboardGrid.vue` — grille
- `Components/Dashboard/WidgetWrapper.vue` — en-tête + fetch
- `Components/Dashboard/WidgetBody.vue` — rendu des données
