Les écrans expliquaient chacun leur propre action, mais rien ne racontait
l'enchaînement : un nouvel utilisateur ne pouvait pas deviner qu'un lieu
doit exister avant un agent, ni qu'un planning se saisit en brouillon
avant d'être validé. La page « faq » déroule ce parcours complet, du
paramétrage des lieux au suivi annuel, et répond aux questions qui
reviennent (chevauchements, quota dépassé, planning validé à corriger).
Son bouton d'accès est ancré à droite de la barre de navigation plutôt
que rangé dans un groupe d'intention : le guide n'est pas une étape du
travail, c'est un secours permanent. Il est donc volontairement absent de
$navigation — c'est aussi ce qui l'empêche d'être repêché par le filet
« Autres » et d'apparaître deux fois. La barre défilant horizontalement
quand les onglets débordent, le bloc est en position sticky pour rester
atteignable.
La page reste soumise à la règle V7.8 : le droit vient de
acces_role_page, ouvert aux trois rôles. Sans la migration, ni bouton ni
page.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La fiche agent portait deux cases à cocher pour la formation depuis l'ajout du
droit à l'enveloppe : celle-ci faisait doublon et disparaît, avec sa colonne
`agent.formation_repartition_annuelle` et tout ce qui la lisait — projection
SQL, création et modification d'agent, formulaires d'administration, JS, et
liste des colonnes obligatoires de SchemaModel.
L'enveloppe de formation ne dépend donc plus que du droit :
AgentModel::trainingEnvelopeMinutes() rend 14 h ou 0.
La colonne est retirée du socle (le CREATE TABLE ne la crée plus sur une base
neuve) et par migration_v7_9c sur les bases existantes. migration_v7_9b perd sa
clause AFTER, qui pointait sur la colonne supprimée et aurait fait échouer
l'installation d'une base neuve ; sa réécriture est sans risque, le script de
migration rejoue un fichier modifié et l'ALTER reste idempotent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nouvelle colonne `agent.droit_enveloppe_formation`, cochée par défaut, saisie à
la création de l'agent et modifiable depuis sa fiche. Un agent sans ce droit :
- ne voit plus le motif « Formation » dans le sélecteur de motif de l'éditeur de
planning ni dans le modal de la vue individuelle ;
- se voit refuser toute affectation de ce motif par le serveur, avec un message
qui nomme le motif et l'agent (save_planning.php et update_agent_entry.php) ;
- a une enveloppe de formation de 0 min au PTA annuel, et une ALERTE
FORMATION_SANS_DROIT si des heures de formation subsistent dans son planning.
À ne pas confondre avec `formation_repartition_annuelle`, qui existait déjà :
celle-ci dit que la formation est déjà comptée dans la répartition annuelle —
l'agent y a droit, l'enveloppe complémentaire n'est simplement pas ajoutée. Les
deux règles sont désormais rassemblées dans AgentModel::trainingEnvelopeMinutes(),
qui remplace les deux calculs « 840 ou 0 » jusque-là dupliqués.
Le motif interdit reste affiché lorsqu'il est déjà celui de la plage en cours
d'édition : le retirer de la liste changerait silencieusement le motif d'une
saisie existante. C'est le contrôle de saisie, puis le serveur, qui demandent
alors de corriger la plage.
La migration est nommée v7_9b et non v7_10 : les fichiers sont joués dans
l'ordre alphabétique, où « v7_10 » passerait avant « v7_8 ».
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ces deux cartes additionnaient les heures de tous les agents suivis, quotités
confondues : le pourcentage et le solde obtenus ne décrivaient la situation
d'aucun agent réel et n'appelaient aucune action. Le bloc « Suivi des quotas
annuels » conserve les indicateurs actionnables (agents suivis, agents sans
aucune heure) et le tableau agent par agent.
Les agrégats correspondants sont retirés du payload de api/dashboard_summary.php
et de leur calcul dans DashboardController : plus aucun consommateur ne les lit.
La tuile « Quotas dépassés » et son compteur de dépassements sont inchangés.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La liste des motifs d'une nouvelle plage s'ouvrait sur un placeholder vide
« Choisir un motif », alors que le temps de travail est le cas très majoritaire :
elle propose désormais « Heure de travail » (code TRAVAIL), avec repli sur le
premier motif décomptant le quota si le référentiel ne contient pas ce code.
Côté PDF, seul le code générique TRAVAIL était traité comme du temps travaillé.
Les motifs ALP matin, ALP soir, restauration, mercredi périscolaire,
extrascolaire, préparations et ménage de fond tombaient donc :
- dans un total invisible du bilan annuel (ligne « Heures travaillées » à 0 h 00
alors que les heures étaient bien décomptées plus bas) ;
- dans la couleur grise « Autre absence » des plannings agent et lieu.
La classification est centralisée dans App\Core\MotifCategories, réutilisée par
PtaModel (qui portait déjà la même liste) et par les deux services PDF. Un motif
inconnu du référentiel est rattaché au temps de travail dès lors qu'il décompte
le quota, pour qu'aucun total ne puisse disparaître d'un document.
La ligne « Heures travaillées » détaille en outre les motifs regroupés, et le
total décompté suit maintenant le drapeau compte_dans_quota comme QuotaModel :
il additionnait auparavant les congés, hors quota, en contradiction avec sa
propre note de bas de tableau.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le Service Enfance ouvrait onze onglets à plat et atterrissait sur l'écran de
saisie, alors que son travail commence par le contrôle. Les chiffres qui
déclenchent une action vivaient sur trois écrans distincts.
- Nouvelle page dashboard.php, réservée au Service Enfance et devenue sa page
d'atterrissage : quatre tuiles d'action, les brouillons les plus anciens avec
ouverture directe sur la bonne semaine, les plages de couverture les plus
déficitaires, et le suivi des quotas annuels par agent.
- Navigation regroupée par intention (Piloter / Planifier / Consulter /
Paramétrer). Les rôles à quelques pages gardent la barre simple.
- Sous-titre propre à chaque page : le bandeau générique n'apprenait rien.
- Pastille « À valider » alimentée depuis toutes les pages, et non plus
seulement depuis la page qu'elle annonce.
Aucune règle métier n'est modifiée : le tableau de bord relit ce que
PlanningModel, CoverageModel et QuotaModel calculent déjà, et son endpoint est
gardé par requireService(). Le droit d'accès à la page vient de la migration
V7.9 ; sans elle, l'onglet n'apparaît pas et homeUrl() se replie sur planning.
Vérifié sur la base réelle : les chiffres de quota du tableau de bord sont
identiques à ceux de api/annual_overview.php, les trois rôles rendent leurs
écrans sans erreur, le rendu JS a été exécuté dans un DOM avec la réponse réelle
de l'API, et la page ne produit aucun attribut style inline (CSP).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Commit technique : reproduit à l'identique l'état non commité de la copie
de travail (sécurisation V7.8, CSP à nonce, Session, migration des droits)
afin que le travail d'ergonomie qui suit soit isolable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>