using System; using System.Linq; using System.Threading.Tasks; using ManagerService.Data; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace ManagerService.Services { /// /// Purge le journal d'audit au-delà de . /// /// ⚠️ **C'est un sujet RGPD, et rien d'autre.** `AuditLog` porte un `UserId`, et les /// valeurs avant/après d'une modification de `User` contiennent e-mail, prénom et nom — /// conservés sans limite jusqu'ici, alors que `VisitEvent` purge à 13 mois et /// `VisitorQuestion` à 90 jours. **Ce n'est pas un sujet de volume** : depuis que le flot /// machine de `WeatherSyncService` est coupé (2026-08-12), la table ne croît qu'au rythme /// des éditions humaines. /// /// **12 mois, uniforme.** Pas 13 : les 13 mois des statistiques existent pour comparer une /// saison à la précédente, et recopier ce chiffre ici serait du mimétisme. ⛔ Écarté aussi : /// garder les suppressions plus longtemps que les créations et modifications — ça double /// les règles pour un cas qu'une sauvegarde couvre déjà. /// /// ⚠️ **Inerte tant que Audit:RetentionDays n'est pas défini**, exactement comme /// et pour la même raison : c'est une suppression /// définitive, et le pg_dump quotidien n'est toujours pas en place. Supprimer des lignes /// d'audit sans restauration fine est la pire combinaison possible. /// /// ⛔ Ne pas s'aligner sur , qui tourne sans /// condition : ses 90 jours sont un engagement écrit dans les CGU, pas un réglage /// d'exploitation. Ici, aucun contrat ne fixe la durée. /// public class AuditLogPurgeService { /// Durée recommandée. Voir le lot J du plan V1. public const int DefaultRetentionDays = 365; private readonly MyInfoMateDbContext _dbContext; private readonly IConfiguration _configuration; private readonly ILogger _logger; public AuditLogPurgeService( MyInfoMateDbContext dbContext, IConfiguration configuration, ILogger logger) { _dbContext = dbContext; _configuration = configuration; _logger = logger; } public async Task PurgeAsync() { var retentionDays = _configuration.GetValue("Audit:RetentionDays"); if (retentionDays <= 0) { _logger.LogInformation( "Purge du journal d'audit ignorée : Audit:RetentionDays non défini. " + "Valeur attendue une fois le pg_dump en place : {Expected}.", DefaultRetentionDays); return; } var cutoff = DateTime.UtcNow.AddDays(-retentionDays); var deleted = await _dbContext.AuditLogs .Where(a => a.Timestamp < cutoff) .ExecuteDeleteAsync(); _logger.LogInformation( "Purge du journal d'audit : {Deleted} entrée(s) antérieure(s) au {Cutoff:yyyy-MM-dd} supprimée(s).", deleted, cutoff); } } }