fix(heures) : garde backend anti-suppression sur grille périmée (delete explicite) #36
Reference in New Issue
Block a user
Delete Branch "fix/work-hour-bulk-upsert-explicit-delete"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte (incident prod)
Le correctif #31 (dirty-tracking front) ne protège que les sessions chargeant le nouveau bundle. Un vieil onglet ouvert avant déploiement tourne encore sur l'ancien JS et envoie toute la grille périmée. Hier soir, un onglet ouvert le matin a supprimé ~10 lignes d'heures saisies dans la journée par d'autres utilisateurs (journal BDD à l'appui : 1 save = 2 updates + 8 deletes de lignes intactes).
Cause : le backend traitait toute entrée vide comme une suppression, sans aucune garde indépendante du client.
Correctif — suppression sur intention explicite (
delete: true)WorkHourBulkUpsertProcessorne supprime une ligne existante sur entrée vide que si l'entrée portedelete: true. Sinon → no-op (ligne préservée). Aucune grille périmée, quel que soit le client (vieil onglet inclus), ne peut plus détruire une saisie concurrente. La création de ligne technique de validation reste limitée ànull === $existing.Le front (à jour) pose
delete: truesur une ligne vidée volontairement (helperisEntryEmpty, appliqué après le filtre dirty-tracking) → suppression métier conservée. Flag optionnel ajouté au DTO front (WorkHourEntryPayload) et back (WorkHourBulkUpsert), défautfalse.Testabilité
Le processor dépend désormais des interfaces repo (
EmployeeScopedRepositoryInterface/WorkHourReadRepositoryInterface, repos concretsfinalnon mockables) → nouveau test unitaireWorkHourBulkUpsertProcessorTest(no-op sans flag / suppression avec flag / update normal).Limite résiduelle (choix : suppression explicite, pas verrou optimiste)
L'édition explicite d'une ligne sur données périmées peut encore écraser une saisie concurrente sur cette même ligne. Seule la suppression est blindée.
Vérification
Doc
doc/hours-save-dirty-tracking.md,CLAUDE.md, doc in-app (documentation-content.ts).🤖 Generated with Claude Code