Le bandeau de la grille affichait contrat, planifié, écart, dimanches et jours
de repos. PLAN.md §7.4 en demande cinq autres : heures contractuelles,
planifié, absences, écart, repos compensateur. La capture du produit audité le
confirme.
L'écart n'était pas cosmétique. Les dimanches travaillés et les jours de repos
se lisent déjà sur la grille, colonne par colonne. Le repos compensateur, lui,
ne se lit nulle part ailleurs : c'est une contrepartie due — au dimanche
travaillé, au dépassement de contingent — et l'omettre du bandeau masquait la
seule valeur qui dit qu'une dette existe.
Le compteur RC n'était alimenté par rien : les repos posés n'étaient tout
simplement pas chargés avec la semaine. Ils le sont, et seul le repos
compensateur y entre — le repos hebdomadaire est un droit déjà pris, les
additionner ferait disparaître la dette dans un total qui ne veut rien dire.
Deux écrans de réglages complètent le lot. L'impression gouverne le planning
affiché en salle : orientation, densité, totaux, dimanche, colonne
d'émargement. Cette dernière porte un avertissement — un émargement papier ne
vaut pas décompte du temps de travail, et le décompte reste celui de PlanFlow.
L'objectif de productivité est nullable et non « zéro par défaut » : zéro est un
objectif inatteignable, l'absence de valeur dit qu'aucun objectif n'a été fixé.
Vider le champ efface donc l'objectif au lieu de le mettre à zéro. L'écran
rappelle aussi ce que l'indicateur n'est pas : il éclaire une décision
d'organisation, il ne mesure pas le travail d'une personne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le planning quitte le module de démonstration : la grille lit `WeeklySchedule`
et `Shift`, et les quatre derniers fichiers de `src/lib/demo/` qui portaient des
salariés fictifs disparaissent.
Modèle
- `TeamMember` : rattachement d'un salarié à une équipe, distinct de
`MembershipScope` (qui dit ce qu'un manager a le droit de voir). Sans lui, un
salarié sans créneau n'apparaîtrait pas dans la grille — c'est-à-dire l'état
de départ de toute semaine en construction.
- RLS sur `WeeklySchedule`, `Shift`, `Rest`, `DailyNote` et `TeamMember`.
Temps
- `src/domain/planning/week.ts` : repérage par couple année ISO + semaine ISO,
jamais par date de début. Le lundi 29 décembre 2025 appartient à la semaine 1
de 2026 ; une clé fondée sur la date ferait apparaître deux semaines 1.
- `zonedInstant` / `zonedMidnight` corrigent le décalage mesuré **à l'instant
visé**. Le 29 mars 2026, minuit est en UTC+1 et 09 h en UTC+2 : ajouter neuf
heures à minuit donnerait 10 h locales.
- La semaine du retour à l'heure d'hiver dure 169 h, celle du passage à l'heure
d'été 167 — vérifié par test.
Écritures
- Création, modification, suppression de créneau ; publication et dépublication
**par équipe**, avec verrou optimiste sur `version` : deux managers sur la
même grille est le cas normal, pas l'exception.
- Chevauchement refusé en transaction, pas seulement dans le formulaire.
- Modifier une semaine publiée exige `planning.edit_published`, capacité que le
rôle manager n'a pas : un salarié a organisé sa semaine sur ce qu'il a lu.
- Toute mutation laisse une entrée d'audit ; la suppression écrit sa trace
**avant** l'effacement, sinon l'état supprimé serait perdu.
Lecture
- `planning.view_unpublished` filtre en base : sans cette capacité, les
brouillons ne sont pas chargés du tout. Un test vérifie que les horaires
n'apparaissent pas dans le HTML servi — un masquage CSS les y laisserait.
- Vue jour reconstruite sur les mêmes données, amplitude déduite de la journée
réelle plutôt que figée à 06 h–21 h.
Vérification
- 26 tests unitaires sur le repérage des semaines et la mise en grille.
- Parcours e2e : poser un créneau, refus de chevauchement, publier, dépublier ;
et ce que voient un salarié et un manager sur la même semaine.
- `scripts/dev-db.sh` : la base de développement est éphémère dans cet
environnement, la remonter ne doit pas être une redécouverte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv