Étape 5 : API CRUD, matrice et validation branchée

- CRUD complet, scopé par édition, sur Position, Shift, Volunteer, Assignment
  (routers app/api/*, schémas Pydantic, dépendance get_edition partagée)
- Volunteer : gestion des compétences par codes (création à la volée),
  suppression = effacement complet en cascade (RGPD)
- Shift : contrôle fin > début, poste de la même édition, compétences requises
- Assignment : toute écriture active passe par le moteur de validation ;
  violation bloquante -> 422 error.validation_failed, avertissements renvoyés
  dans la réponse. Endpoint POST .../assignments/validate en simulation.
  app/validation/loader.py construit la ValidationInput depuis la base.
- GET /editions/{id}/matrix : postes -> créneaux -> {min, ideal, confirmed,
  proposed}, source de l'écran principal
- 30 tests d'API (CRUD, 404/409/422, cascade, blocage, avertissements, matrice,
  loader) ; 104 tests au total ; alembic check toujours vert
- Clés de traduction shift.* / assignment.* / volunteer.* ajoutées

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
AdamThomas
2026-09-09 22:54:22 +02:00
co-authored by Claude Sonnet 5
parent c96e85af37
commit 74e35f0195
20 changed files with 1775 additions and 8 deletions
+6
View File
@@ -4,6 +4,12 @@
"error.forbidden": "Accès refusé",
"error.unauthorized": "Authentification requise",
"error.validation_failed": "La validation a échoué",
"error.conflict": "Conflit avec une ressource existante.",
"shift.ends_not_after_starts": "La fin du créneau doit être postérieure à son début.",
"shift.position_wrong_edition": "Le poste n'appartient pas à cette édition.",
"volunteer.duplicate_email": "Un bénévole avec cet email existe déjà dans l'édition.",
"assignment.wrong_edition": "Le bénévole ou le créneau n'appartient pas à cette édition.",
"assignment.duplicate": "Ce bénévole est déjà affecté à ce créneau.",
"import.error.empty_file": "Le fichier est vide.",
"import.error.encoding": "L'encodage du fichier n'est pas reconnu.",