Étape 2 : modèle de données complet et migration initiale
- Tables SQLModel : Edition, DayPart, Volunteer, Skill, Position, Shift, Availability, Assignment, Account, MagicLinkToken + tables d'association - Multi-édition (edition_id partout), énumérations en VARCHAR + CHECK, suppressions ON DELETE CASCADE (droit à l'effacement) - Dates/heures naïves en heure locale Europe/Paris (tzdata + TZ conteneur) - Migration Alembic 0001 écrite à la main, vérifiée par `alembic check` (aucun écart avec les modèles) et par un aller-retour downgrade/upgrade - Tests : graphe complet, unicité email par édition, N-N compétences, aller-retour d'énumération, cascade de suppression d'un bénévole Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
09d7d70076
commit
cb2e84adf0
@@ -51,25 +51,49 @@ Deux tables distinctes, deux écrans distincts, deux vocabulaires distincts.
|
||||
|
||||
## 2. Modèle de domaine
|
||||
|
||||
- **`Edition`** : année, `start_date`, `end_date`, `retention_days`
|
||||
(durée de rétention des données nominatives, paramétrable), liste de
|
||||
`DayPart`.
|
||||
- **`DayPart`** : découpage d'une journée propre à l'édition (matin,
|
||||
après-midi, soirée… nombre et bornes libres). Une `Availability` référence
|
||||
un `DayPart` + une date.
|
||||
- **`Volunteer`** : `email` (identifiant fonctionnel unique **par édition**,
|
||||
nullable pour les bénévoles créés à la main), `first_name`, `last_name`,
|
||||
`phone`, `tshirt_size`, `diet`, `comment`. Pas de date de naissance.
|
||||
- **`Skill`** : référentiel par édition (SST, permis B, régie son, langues…).
|
||||
N-N avec `Volunteer`. N-N avec `Shift` (compétences requises).
|
||||
- **`Position`** : `name`, `location`, `category`, `lead_account_id`.
|
||||
- **`Shift`** : `position_id`, `start_at`, `end_at` (peut finir le lendemain),
|
||||
`min_staff`, `ideal_staff`, compétences requises (N-N `Skill`).
|
||||
- **`Assignment`** : `volunteer_id`, `shift_id`, `status`, `source`, `locked`.
|
||||
- **`Account`** : `email`, `role`, `edition_id`, `volunteer_id` (nullable).
|
||||
- **`MagicLinkToken`** : `account_id`, `token_hash`, `expires_at`, `used_at`.
|
||||
Défini dans `backend/app/models/` (`enums.py`, `base.py`, `domain.py`).
|
||||
Clés primaires `UUID`. Champs d'audit `created_at` / `updated_at` sur toutes
|
||||
les tables sauf les tables d'association.
|
||||
|
||||
Multi-édition : toute entité métier porte un `edition_id`.
|
||||
- **`Edition`** : `year`, `name` (opt.), `start_date`, `end_date`,
|
||||
`retention_days` (durée de rétention des données nominatives en jours,
|
||||
`NULL` = pas de purge).
|
||||
- **`DayPart`** : découpage d'une journée propre à l'édition (nombre et bornes
|
||||
libres, paramétrable par la coordination). `code`, `label`, `start_time`,
|
||||
`end_time` (`end_time < start_time` ⇒ passe minuit), `order`. Unique
|
||||
(`edition_id`, `code`).
|
||||
- **`Volunteer`** : `email` (unique **par édition**, nullable pour les
|
||||
bénévoles créés à la main — plusieurs `NULL` autorisés), `first_name`,
|
||||
`last_name`, `phone`, `tshirt_size`, `diet`, `comment`. Pas de date de
|
||||
naissance.
|
||||
- **`Skill`** : référentiel par édition (`code`, `label`). N-N `Volunteer`
|
||||
(`volunteer_skill`). N-N `Shift` (`shift_required_skill`).
|
||||
- **`Position`** : `name`, `location`, `category` (`PositionCategory`),
|
||||
`lead_account_id` (→ `Account`, `SET NULL` à la suppression du compte).
|
||||
- **`Shift`** : `position_id`, `starts_at`, `ends_at` (peut finir le
|
||||
lendemain), `min_staff`, `ideal_staff`, compétences requises (N-N `Skill`).
|
||||
- **`Availability`** : `volunteer_id`, `date`, `day_part_id`, `status`
|
||||
(`AvailabilityStatus`). Unique (`volunteer_id`, `date`, `day_part_id`).
|
||||
- **`Assignment`** : `volunteer_id`, `shift_id`, `status`
|
||||
(`AssignmentStatus`, défaut `PROPOSED`), `source` (`AssignmentSource`,
|
||||
défaut `MANUAL`), `locked` (défaut `false`). Unique (`volunteer_id`,
|
||||
`shift_id`).
|
||||
- **`Account`** : `email` (unique par édition), `role` (`Role`), `edition_id`,
|
||||
`volunteer_id` (nullable, unique).
|
||||
- **`MagicLinkToken`** : `account_id`, `token_hash` (unique), `expires_at`,
|
||||
`used_at`.
|
||||
|
||||
Conventions techniques :
|
||||
|
||||
- Multi-édition : toute entité métier porte un `edition_id`.
|
||||
- Énumérations stockées en `VARCHAR` + `CHECK` (`native_enum=False`), pas de
|
||||
type ENUM natif PostgreSQL.
|
||||
- Suppression en cascade au niveau base (`ON DELETE CASCADE`) sur tous les
|
||||
`edition_id` et sur les liens vers `volunteer`, `shift`, `position`,
|
||||
`skill`, `account`. La suppression complète d'un bénévole (RGPD) efface donc
|
||||
ses `Availability`, `Assignment`, liens de compétence et son `Account`.
|
||||
- Dates/heures **naïves**, heure locale Europe/Paris (`TZ` du conteneur +
|
||||
`tzdata`). `app.models.local_now()` pour les horodatages.
|
||||
|
||||
### Rôles et accès
|
||||
|
||||
@@ -192,6 +216,7 @@ Aucune dépendance locale requise hors Docker.
|
||||
| Format | `docker compose run --rm backend uv run ruff format .` |
|
||||
| Créer une migration | `docker compose run --rm backend uv run alembic revision --autogenerate -m "..."` |
|
||||
| Appliquer les migrations | `docker compose run --rm backend uv run alembic upgrade head` |
|
||||
| Vérifier migration ↔ modèle | `docker compose run --rm backend uv run alembic check` (après `upgrade head`) |
|
||||
| Charger le jeu de démo | *(étape ultérieure)* `docker compose run --rm backend uv run python -m app.seed` |
|
||||
|
||||
---
|
||||
@@ -234,4 +259,5 @@ Aucune dépendance locale requise hors Docker.
|
||||
|
||||
| Étape | Description | État |
|
||||
|-------|-------------------------------------------------------|----------|
|
||||
| 1 | Squelette : monorepo, Docker, CI/CD, backend qui démarre | à valider |
|
||||
| 1 | Squelette : monorepo, Docker, CI/CD, backend qui démarre | validée |
|
||||
| 2 | Modèle de données complet + migration Alembic initiale | à valider |
|
||||
|
||||
Reference in New Issue
Block a user