3 Commits
Author SHA1 Message Date
MichaelandClaude Opus 5 791dd523eb Donner une équipe à tout établissement neuf
Un établissement naissait sans équipe. Le planning s'ordonnant par équipe, il
n'avait alors aucune ligne où poser un créneau — même avec des salariés
rattachés. L'écran annonçait « cet établissement n'a pas encore d'équipe », ce
qui se lit « il n'y a personne », et rien ne disait où en créer une.

Deux corrections. La création d'un établissement pose une première équipe, à
l'installation comme depuis les réglages ; elle se renomme, et rien n'empêche
d'en ajouter d'autres. Et le message du planning dit désormais où aller : créer
l'équipe dans les réglages, puis rattacher les salariés depuis l'onglet
« Planification et accès » de leur fiche.

Les établissements déjà créés gardent leur situation : le correctif empêche d'en
produire de nouveaux sans équipe, il ne rattrape pas l'existant. Une équipe
s'ajoute en deux clics depuis Réglages · Établissements.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:02:15 +02:00
MichaelandClaude Opus 5 a0524c56d7 Sortir la démonstration du chemin d'installation
Une instance neuve passait par le seed pour être utilisable. Or le seed installe
une fiction : « Maison Rivage », des salariés inventés, quatre semaines de
planning, des absences. Sur une instance de travail, ces noms se confondent avec
de vrais salariés dans l'annuaire et au registre du personnel.

Le trou qu'il bouchait était réel : après les migrations, une instance avait le
schéma et rien à quoi l'accrocher. Aucun type d'absence, donc aucune demande
saisissable. Aucune étiquette, donc aucun créneau nommé. Aucune convention, donc
un moteur de règles muet qui laisse passer une semaine de soixante heures sans
rien dire.

L'écran d'installation pose donc désormais les référentiels : les douze
étiquettes, cinq types d'absence, la convention d'amorce IDCC 1517 avec
l'origine de chacun de ses paramètres, les durées de conservation et les jours
fériés des deux prochaines années. Ce ne sont pas des exemples mais des minima,
tous modifiables ensuite depuis les réglages.

Trois choses restent délibérément absentes. Aucun dimanche du maire : la liste
vient d'un arrêté municipal, et en inventer rendrait opposable un quota que
personne n'a accordé. Aucun code Silae sur les types d'absence : la
correspondance appartient au dossier du client. Aucun salarié, aucun créneau,
aucune absence.

Le seed devient `prisma/seed-demo.ts`, réservé au harnais Playwright. `db:seed`
disparaît au profit de `db:seed:demo` : il n'y a plus rien à semer pour
démarrer, et un nom qui le dit vaut mieux qu'un commentaire qui l'explique.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 13:37:19 +02:00
Claude 727c05407a Écran de première installation
Les migrations posent le schéma et rien d'autre : une instance neuve n'a
aucun compte et aucun utilisateur, donc personne ne peut se connecter. Le
seed n'y remédie pas — il installe une démonstration et refuse de tourner
en production, à raison.

La première visite est désormais redirigée vers `/installation` : nom de
l'entreprise, premier établissement avec son fuseau, et compte
administrateur. L'écran crée le compte, le catalogue des capacités, les
cinq rôles fournis, le propriétaire et son périmètre, puis ouvre la session
par le chemin ordinaire — le rôle propriétaire exige aussitôt un second
facteur, comme il se doit.

Il ne se rouvre pas. Une table `Installation` d'une seule ligne, contrainte
en base et protégée par un trigger append-only, marque l'instance. Elle est
délibérément hors RLS, et c'est sa raison d'être : la politique d'`Account`
ne laisse voir que le compte courant, si bien qu'une instance installée
paraîtrait vierge à qui n'a pas de session — et la création d'un
propriétaire se rouvrirait à tout venant. Le recensement des politiques
porte l'exception, affirmée dans les deux sens.

Deux défauts trouvés en éprouvant l'écran sur une base réellement vierge :

`INSERT ... RETURNING` sur `Account` était refusé. L'insertion est permise,
mais la relecture de la ligne écrite passe par la politique de lecture, qui
exige un compte courant. L'identifiant est donc tiré côté application et
annoncé avant la création — la règle de partout, appliquée à la
transaction qui crée le compte.

Et un défaut qui dépassait cet écran : React 19 vide les champs non
contrôlés dès qu'une action se termine, refus compris. Les champs vidés
portant `required`, le clic suivant était arrêté par la validation du
navigateur avant d'émettre un `submit` — le formulaire paraissait mort. Le
formulaire de connexion en souffrait aussi ; la suite l'avait manqué parce
qu'aucun test ne soumettait deux fois de suite. `PersistentForm`
photographie la saisie à l'envoi et la rétablit, mots de passe exclus.

Au passage, `Field` rattache son indication par `aria-describedby` : placée
dans le `<label>`, elle entrait dans le nom accessible du champ.

Éprouvé sur une base vierge, image de production, rôle NOSUPERUSER
NOBYPASSRLS : redirection, trois refus motivés, installation, second
facteur exigé, écran refermé pour le propriétaire comme pour un visiteur.
450 tests unitaires et d'intégration, 77 tests de bout en bout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-09 19:10:25 +00:00