feat : add audit log (table, writer, listener, API, admin UI, timeline)

Implemente le journal d'audit append-only sur toutes les mutations Doctrine
des entites portant #[Auditable]. Couvre les 5 tickets de doc/audit-log.md :

1. Table PG audit_log (uuid PK, jsonb changes, index entity/time/performer)
   + AuditLogWriter (DBAL connexion dediee audit, blacklist defense-in-depth
   sur password/plainPassword/token/secret) + RequestIdProvider (UUID v4 par
   requete HTTP principale).
2. Attributs Auditable / AuditIgnore dans Shared/Domain/Attribute/
   + AuditListener (onFlush capture + postFlush ecriture hors transaction ORM,
   pattern swap-and-clear, erreurs loguees jamais propagees). User annote.
3. API Platform read-only /api/audit-logs (permission core.audit_log.view)
   avec filtres entity_type / entity_id / action / performed_by / plage
   performed_at + DbalPaginator implementant PaginatorInterface (hydra:view
   genere automatiquement).
4. Page admin /admin/audit-log : tableau pagine, filtres persistes en query
   params, row expandable (diff + timeline de l'entite), entree sidebar avec
   permission. Composable useAuditLog avec resetAuditLog() auto-enregistre
   sur onAuthSessionCleared.
5. Composant AuditTimeline reutilisable : garde permission, lazy loading,
   dates relatives FR, skeleton loader.

Fix connexe : phpunit.dist.xml forcait APP_ENV=dev via <env> ce qui cablait
framework.test=false et rendait test.service_container indisponible ; le
JWT_PASSPHRASE ne matchait pas non plus les cles dev. Corrige en meme temps
pour debloquer la suite de tests.
This commit is contained in:
2026-04-20 20:51:10 +02:00
parent 140dca9061
commit de39fe6a3e
31 changed files with 2754 additions and 6 deletions

View File

@@ -26,7 +26,8 @@
"core": {
"roles": "Gestion des rôles",
"users": "Utilisateurs",
"sites": "Sites"
"sites": "Sites",
"audit_log": "Journal d'audit"
}
},
"dashboard": {
@@ -66,6 +67,35 @@
"switchSuccess": "Site courant changé"
}
},
"audit": {
"action": {
"create": "Création",
"update": "Modification",
"delete": "Suppression"
},
"entity": {
"user": "Utilisateur"
},
"empty": "Aucune activité enregistrée",
"no_results": "Aucun résultat pour ces filtres",
"timeline": {
"empty": "Aucun historique",
"load_more": "Voir plus"
},
"filters": {
"reset": "Réinitialiser",
"date_from": "Du",
"date_to": "Au",
"entity_type": "Type d'entité",
"user": "Utilisateur",
"action": "Action"
},
"detail": {
"field": "Champ",
"old_value": "Ancienne valeur",
"new_value": "Nouvelle valeur"
}
},
"success": {
"auth": {
"logout": "Deconnexion reussie"
@@ -132,6 +162,21 @@
"updated": "Permissions mises à jour avec succès"
}
},
"auditLog": {
"title": "Journal d'audit",
"table": {
"performedAt": "Date",
"performedBy": "Utilisateur",
"entityType": "Entité",
"entityId": "ID",
"action": "Action",
"summary": "Résumé"
},
"pagination": {
"previous": "Précédent",
"next": "Suivant"
}
},
"sites": {
"title": "Gestion des sites",
"newSite": "Nouveau site",