WP-09 : tableau de bord RH, et disparition des données de démonstration

`src/lib/demo` n'existe plus. Aucun écran de PlanFlow ne lit désormais autre
chose que la base.

Un indicateur doit être explicable
Chaque tuile est un lien vers ses lignes sources : profils incomplets, fins de
période d'essai, titres de séjour, entrées, sorties, avenants, journal des
absences. Un chiffre qu'on ne peut pas ouvrir ne se corrige pas — il se
conteste. Et chaque ligne mène à la fiche du salarié.

Les manques sont **nommés**, pas comptés : « 6 profils incomplets » n'aide
personne à agir, « il manque l'IBAN de trois salariés » se règle en un message.
Le NIR et l'IBAN sont contrôlés par la présence de leur colonne chiffrée, jamais
déchiffrés — savoir qu'une valeur existe n'exige pas de la lire.

Des chiffres qui refusent de mentir
- La rotation moyenne entrées et sorties : compter seulement les départs
  sous-estime la rotation d'une équipe qui recrute autant qu'elle perd.
- Sur un effectif nul, elle rend `—` et non « 0 % ». Zéro pour cent de rotation
  sur un établissement vide est une affirmation fausse, pas une absence de
  mouvement.
- L'absentéisme se rapporte aux jours **théoriquement travaillés**, pas aux
  jours calendaires : rapporter à 30 jours ferait passer un problème réel pour
  du bruit.
- Un taux horaire absent vaut zéro dans le coût, jamais une estimation :
  afficher un coût inventé serait pire qu'un coût partiel.

Les échéances remontent avant de tomber
Périodes d'essai à 45 jours, titres de séjour à 90. Les échéances **dépassées**
sont conservées et placées en tête : une période d'essai qu'on a laissé filer
est plus urgente qu'une échéance à venir, et la masquer parce qu'elle est passée
est précisément ce qui la rend coûteuse.

Périmètre et confidentialité
Le filtrage par établissement s'applique **avant** l'agrégation : les mouvements
d'un autre établissement ne transparaissent pas, même fondus dans un total. Le
journal des absences ne porte jamais le motif médical — un tableau de bord n'en
a aucun besoin.

Un salarié, qui n'a pas accès à l'annuaire, reçoit un accueil adapté plutôt
qu'une erreur d'autorisation ou un tableau de bord vide.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
This commit is contained in:
Claude committed 2026-08-08 12:40:19 +00:00
1 parent 19f082b7ef
commit 10a9c923e2
12 files changed
+1360 -227

No files matched your search

+8 -5
View File
@@ -29,9 +29,12 @@ export const NAVIGATION: NavSection[] = [
label: 'Aperçu',
items: [
{ id: 'taches', label: 'Tâches RH', href: '/' },
{ id: 'entrees', label: 'Entrées et sorties' },
{ id: 'profils', label: 'Profils incomplets', badge: '6' },
{ id: 'soldes-cp', label: 'Compteurs de congés payés' },
{ id: 'entrees', label: 'Entrées et sorties', href: '/?liste=entrees' },
{ id: 'profils', label: 'Profils incomplets', href: '/?liste=profils' },
{ id: 'titres', label: 'Titres de séjour', href: '/?liste=titres' },
// Ancre plutôt que route : `/conges` appartient à la section Congés, et
// deux entrées allumées pour un même écran rendent la navigation muette.
{ id: 'soldes-cp', label: 'Compteurs de congés payés', href: '/conges#compteurs' },
],
},
{
@@ -42,7 +45,7 @@ export const NAVIGATION: NavSection[] = [
{ id: 'jour', label: 'Vue jour', href: '/planning/jour' },
{ id: 'etiquettes', label: 'Vue par poste', href: '/planning/etiquettes' },
{ id: 'mois', label: 'Vue mois', href: '/planning/mois' },
{ id: 'besoins', label: 'Besoins non couverts', badge: '5' },
{ id: 'besoins', label: 'Besoins non couverts' },
{ id: 'modeles', label: "Modèles d'ouverture" },
],
},
@@ -59,7 +62,7 @@ export const NAVIGATION: NavSection[] = [
label: 'Congés',
items: [
{ id: 'calendrier', label: 'Calendrier des absences', href: '/conges' },
{ id: 'attente', label: 'Demandes en attente', href: '/conges#attente', badge: '3' },
{ id: 'attente', label: 'Demandes en attente', href: '/conges#attente' },
{ id: 'politiques', label: 'Politiques de congés' },
],
},