Files
SIRH/doc/audit-logging.md
T
tristan 608eeaa450 feat(audit) : filtres Employé et Utilisateur en champ texte (recherche libre)
Employé = recherche partielle sur nom/prénom (nouveau filtre back 'employee', LIKE via join) ;
Utilisateur = recherche partielle sur username. Remplace les selects par des champs texte.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 12:05:07 +02:00

70 lines
4.0 KiB
Markdown

# Journal des actions (Audit Log)
## Objectif
Tracer les actions utilisateurs pour diagnostiquer rapidement les problèmes de calcul signalés.
Quand un utilisateur signale une incohérence dans ses heures, RTT ou congés, le journal permet de voir
exactement ce qui a été modifié, par qui, et quand.
## Accès
- **Rôle requis** : `ROLE_SUPER_ADMIN` (rôle caché, non visible dans l'interface de gestion des utilisateurs)
- **Ajout du rôle** : directement en base de données
```sql
UPDATE users SET roles = '["ROLE_ADMIN","ROLE_SUPER_ADMIN"]' WHERE username = 'xxx';
```
- **Page** : `/audit-logs` (lien "Journal" dans la sidebar, visible uniquement avec le rôle)
## Actions tracées
| Processor | Entité | Actions |
|---|---|---|
| `AbsenceWriteProcessor` | Absence | create, delete |
| `WorkHourBulkUpsertProcessor` | WorkHour | create, update, delete |
| `WorkHourSiteValidationProcessor` | WorkHour | site_validate |
| `WorkHourBulkValidationProcessor` | WorkHour | validate |
| `WorkHourBulkSiteValidationProcessor` | WorkHour | site_validate |
| `EmployeeWriteProcessor` | Employee | create, update (changement contrat) |
| `ContractSuspensionWriteProcessor` | ContractSuspension | create, update |
| `EmployeeRttPaymentProcessor` | EmployeeRttPayment | update |
| `EmployeeFractionedDaysProcessor` | EmployeeLeaveBalance | update |
## Données stockées
Chaque entrée contient :
- **employee** : l'employé concerné (FK, nullable)
- **username** : l'utilisateur qui a effectué l'action
- **action** : type d'action (create, update, delete, validate, site_validate)
- **entityType** : type d'entité (work_hour, absence, employee, etc.)
- **description** : description lisible en français
- **changes** : diff JSON `{old: {...}, new: {...}}` avec les anciennes/nouvelles valeurs
- **affectedDate** : date de travail ou début d'absence (pour filtrage par période)
- **createdAt** : horodatage de l'action
- `ipAddress` : IP source de la requête (`Request::getClientIp()`) — nécessite `framework.trusted_proxies` derrière un reverse proxy, sinon IP du proxy
- `userAgent` : User-Agent brut de la requête
- `deviceLabel` : libellé lisible dérivé du User-Agent (`Type · OS · Navigateur`, ex. `Mobile · Android · Chrome`), via `App\Service\UserAgentParser`
- `deviceId` : identifiant d'appareil persistant envoyé par le front (header `X-Device-Id`, stocké en `localStorage['sirh-device-id']`). Distingue les **appareils** derrière un compte partagé (ex. « Usine »), pas les personnes.
Capture : automatique et centralisée dans `AuditLogger::log()` (via `RequestStack`) — aucun processor à modifier. En contexte CLI/cron (pas de requête), ces 4 champs restent `null`.
> ⚠️ **CORS** : le front et l'API sont sur des origines distinctes ; le header `X-Device-Id` ajouté à chaque requête déclenche un préflight CORS. Il **doit** figurer dans `nelmio_cors.allow_headers` (`config/packages/nelmio_cors.yaml`), sinon le navigateur bloque toutes les requêtes API.
## Filtres disponibles
- Par employé (affecté) — champ texte, recherche partielle sur nom/prénom (insensible à la casse)
- Par période (date affectée) — sélecteur de plage
- Par type(s) d'entité (multi-sélection)
- Par action(s) (multi-sélection)
- Par utilisateur / compte — champ texte, recherche partielle (insensible à la casse)
- Par IP (recherche partielle)
- Par appareil (recherche partielle sur le libellé ou le device id)
Pagination : `perPage` (10 / 25 / 50 / 100, défaut 10) + `page`.
L'écran utilise un `MalioDataTable`, un **drawer de filtre** (bouton « Filtrer » avec compteur de filtres actifs, état brouillon/appliqué, Réinitialiser/Appliquer) et un **drawer de détail** ouvert au clic sur une ligne (méta + contexte technique IP/appareil/User-Agent/device id + diff lisible des changements).
## Convention
Tout nouveau processor traitant des entités impactant les calculs (heures, absences, contrats, RTT)
doit intégrer le service `AuditLogger` et logger les actions create/update/delete.