# Système de droits par fonctionnalité

## Vue d'ensemble

Chaque fonctionnalité ERP est identifiée par une **permission** (`feature_key`) de niveau `lecture` ou `ecriture`.  
Les permissions sont associées à un ou plusieurs **groupes Microsoft 365** (display names stockés dans `users.m365_groups`).

L'administration du mapping se fait sur **`/admin/droits`** (permissions `admin.droits.lecture` / `admin.droits.ecriture`).

## Modèle de données

| Table | Rôle |
|-------|------|
| `features_permissions` | Catalogue des permissions |
| `feature_permission_groups` | Liaison permission ↔ groupe M365 |
| `audit_log_permissions` | Historique des modifications de mapping |

## Catalogue et seed

- Configuration : `config/feature_permissions.php`
- Seeder : `php artisan db:seed --class=FeaturesPermissionsSeeder`

Mappings par défaut :

| Groupe M365 | Périmètre |
|-------------|-----------|
| `GS_DSI` | Toutes les permissions |
| `GS_ADMIN_ERP` | Tout sauf `admin.systeme` et `admin.maintenance` |
| `GS_DIRECTION_GENERALE` | Toutes les lectures + écritures métier de direction |
| `GS_COMPTABILITE` | Factures, bilan, Intacct, postes budgétaires, demandes fournisseurs, appels de fonds |
| `GS_ENVOL` | Lectures générales + lots, acquéreurs, marketing, chantier opérationnel |

## API applicative

### PHP

```php
if (userCan('factures.comptabilisation')) {
    // ...
}
```

Service injectable : `App\Services\PermissionService`

- `userHasPermission(User $user, string $featureKey): bool`
- `userPermissions(User $user): array` — liste des `feature_key` (cache fichier 5 min)
- `flushCache(?User $user = null): void` — à appeler après modification du mapping

### Middleware route

```php
Route::get('/exemple', ...)->middleware('feature.permission:marches.lecture');
```

Réponse 403 : page Inertia `Errors/Forbidden`.

### Vue / Inertia

Permissions partagées via `auth.permissions` dans `HandleInertiaRequests`.

```js
import { useUserCan } from '@/Composables/useUserCan';

const { userCan, userCanAny } = useUserCan();
if (userCan('programmes.lecture')) { /* ... */ }
```

## Migration progressive

Les contrôles historiques `hasM365Group()` / `m365.groups` restent en place.  
Remplacer progressivement par `userCan('feature_key')` ou le middleware `feature.permission`.

## Maintenance

Après modification des groupes sur `/admin/droits`, le cache permissions est vidé automatiquement (`PermissionService::flushCache()`).
