Repository navigation
release: livraison develop → main (5 PR, unités encadrées, rôles et âge, email réservé à l ADMIN) - #186
Merged
Conversation
…DMIN Changer l'email d'un compte permettait de s'y connecter : « mot de passe oublié » envoie le lien à la nouvelle adresse. Le RG et la secrétaire (user.manage) contournaient ainsi user.password.set, réservé à l'ADMIN depuis #173. - Nouvelle action `user.email.set`, ADMIN seul. - `updateUserAccount` refuse un email modifié sans ce droit ; nom, prénom et téléphone restent modifiables. - Formulaire : champ email en lecture seule avec explication pour les non-ADMIN. Vérifié en build de prod : RG et secrétaire refusés même en forçant le champ côté navigateur, base inchangée ; téléphone modifiable ; l'ADMIN change l'email. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Suite de revue : sans `user.email.set`, la transaction garde l'email relu en base au lieu de celui du formulaire. Un enregistrement du RG ou de la secrétaire sur une page ouverte avant un changement d'email par l'ADMIN n'écrase plus ce changement. Le message de refus le mentionne. Vérifié en build de prod : l'ADMIN change l'email pendant que le RG a la fiche ouverte ; l'enregistrement du RG est refusé, l'email de l'ADMIN est conservé. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…le RG, parents prévenus Décision : seul un compte qui se connecte déjà est réservé à l'ADMIN. Un compte sans connexion (compte enfant) peut recevoir sa première adresse de qui gère les comptes, pour garder l'activation d'un jeune qui atteint 15 ans sans passer par l'ADMIN. - `canChangeAccountEmail` (src/lib/permissions.ts) : `user.email.set` (ADMIN) pour tout compte, `user.manage` pour un compte sans connexion. - Compte enfant qui reçoit une vraie adresse : alerte forcée (SECURITY_ALERT) à chaque parent rattaché. - Audit USER_ACCOUNT_UPDATED : ancienne et nouvelle adresse quand l'email change, effacées à l'anonymisation (liste blanche, test ajouté). Vérifié en build de prod : secrétaire refusée sur un compte qui se connecte (base inchangée) ; secrétaire attribue l'email d'un compte enfant de 16 ans (connexion activée, alerte au parent, audit ancienne → nouvelle) ; le compte devenu connectable repasse en lecture seule ; l'ADMIN change l'email d'un adulte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…able hors ADMIN Revue : retirer ses rôles à un adulte puis lui donner une date de moins de 15 ans le passait en canLogin=false sans changer son adresse réelle ; la secrétaire ou le RG pouvait alors la remplacer par la sienne et se connecter via « mot de passe oublié ». - `canChangeAccountEmail` exige en plus une adresse provisoire (`PLACEHOLDER_EMAIL_SUFFIX`, déplacé dans src/lib/permissions.ts). - Changement d'email comparé sans la casse des deux côtés : plus d'audit ni d'alerte aux parents sur une simple différence de majuscules. - Messages : « une adresse email déjà attribuée ». Vérifié en build de prod : la secrétaire est refusée sur un adulte en canLogin=false avec adresse réelle (base inchangée) ; elle attribue toujours l'adresse d'un compte enfant de 16 ans. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e hors ADMIN Suite de revue : - `canChangeAccountEmail` exclut les comptes supprimés (anonymisés) : leur adresse est aussi provisoire, et y remettre une adresse réelle réintroduisait de la PII dans une fiche effacée, sans expurgation de l'audit. - `canSetEmailTo` : hors ADMIN, une nouvelle adresse ne peut pas finir par @piloti.invalid. Poser `deleted+<id>@piloti.invalid` d'un autre compte bloquait son anonymisation (contrainte d'unicité). Vérifié en build de prod : secrétaire refusée sur un compte supprimé et sur une adresse provisoire saisie à la main (base inchangée) ; elle attribue toujours l'adresse réelle d'un compte enfant de 16 ans. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Abandonne la règle « un mineur ne reçoit que le rôle Jeune » (#122, PR #126). Un ADMIN ou un RG peut attribuer n'importe quel rôle à n'importe quel compte, y compris à un mineur. - supprime assignableRolesForBirthDate et ses tests - approveUser, setUserRoles : plus de contrôle d'âge - setUserBirthDate : ne bloque plus une date « mineure » sur un compte qui porte un rôle d'encadrement (la coupure de connexion sous 15 ans reste en place) - RolesEditor, ApproveDialog : plus de filtre par âge (le badge Mineur reste affiché) - DECISIONS.md : D-044 Les verrous canEnableLogin/MIN_LOGIN_AGE, dm-policy, consentement parental et comptes enfants sont inchangés. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(admin): #128 — l'âge ne restreint plus les rôles attribuables
# Conflicts: # src/app/(app)/admin/utilisateurs/[id]/modifier/page.tsx
fix(roles): une adresse email déjà attribuée n'est modifiable que par l'ADMIN
- Nouvelle table UnitLead (userId, unit) : unités ENCADRÉES, distinctes de l'unité d'appartenance User.unit. La migration reprend les chefs actuels. - Le périmètre d'un CHEF (inUnitScope, canActOnUnit, scopedUnits, canReadPedagoNotes) devient ses UnitLead (ledUnits, chargé par getCurrentUser). Fail-closed : un CHEF sans UnitLead n'encadre rien. Les rôles transverses gardent leur périmètre d'avant (unité d'appartenance). - Un seul point d'écriture (writeLeadUnits, admin/actions.ts), verrouillé par un test statique. approveUser et setUserRoles gardent CHEF et UnitLead cohérents ; setUserUnit ne touche pas au périmètre ; l'anonymisation supprime les UnitLead. - Seed : un compagnon CHEF qui encadre les Louveteaux. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Décision de Mathis : seul le CHEF est borné par ledUnits, les autres rôles restent sur User.unit. Dette connue, à supprimer par la matrice de rôles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OLES-06) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(admin): #128 — unités encadrées (UnitLead), périmètre d'un chef
…modération et pédagogie - dm-policy : « chef de l'unité du jeune » = CHEF qui encadre son unité (ledUnits) ; la règle entre mineurs de 15 à 17 ans passe avant. - Signalements : notification et file des CHEF par unités encadrées, fail-closed sans encadrement. - 2e validation pédagogique : notifie les chefs qui encadrent l'unité. - setUserRoles ne recrée plus d'UnitLead sur un compte DELETED. - D-045 amendée. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(communication): #128 — chef d'unité par UnitLead en messagerie, modération et pédagogie
…d'un chef - Salons : un chef accède aux salons des unités qu'il encadre ; exclusion (excludeUnits) seulement si toutes ses unités sont exclues. - Annonces, notifications d'événement et iCal : un chef reçoit aussi ceux des unités qu'il encadre. Relances et cotisations restent à l'appartenance. - Bilan des présences : unité présélectionnée parmi les unités encadrées. - /admin/utilisateurs/[id]/modifier : éditeur « Unités encadrées » (setUserLeadUnits), message clair pour un compte non Chef ; audit avec l'avant et l'après. Unités encadrées affichées dans la liste (avec filtre) et sur la fiche membre. - CLAUDE.md : unité d'appartenance ≠ unités encadrées. D-045 amendée. Refs #128 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alogue Relecture : la première unité encadrée dépendait de l'ordre de chargement des UnitLead. Libellé « Encadre : … » calculé une fois par ligne. Refs #128 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(admin): #128 — unités encadrées à l'écran et dans la visibilité d'un chef
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Origine
Livraison
develop→main: 5 PR (#176, #182, #183, #184, #185), 12 commits hors merges. Closes #128.20261007163359_unit_lead. Elle crée la tableUnitLeadet insère des données : unUnitLead(userId, unit)pour chaque compte Chef qui a une unité (comptes anonymisés exclus), plus une ligne d'audit par compte repris. Idempotente (INSERT OR IGNORE), sans effet sur une base vierge.docker-compose.yml,.env.examplenipackage.json./admin/utilisateurs/[id]/modifier). La migration ne reprend que l'unité d'appartenance des chefs actuels : ils gardent exactement leurs droits, mais aucun compagnon n'encadre une autre unité tant que ce n'est pas saisi.Ce qui change
Pourquoi
Un compagnon ne pouvait pas encadrer une unité, parce que le périmètre d'un chef reposait sur son unité d'appartenance, qui est unique (#128). Et la faille de #176 contournait le choix de #173 (mot de passe réservé à l'ADMIN).
Preuves
develop(fix(roles): une adresse email déjà attribuée n'est modifiable que par l'ADMIN #176, fix(admin): #128 — l'âge ne restreint plus les rôles attribuables #182, feat(admin): #128 — unités encadrées (UnitLead), périmètre d'un chef #183, feat(communication): #128 — chef d'unité par UnitLead en messagerie, modération et pédagogie #184, feat(admin): #128 — unités encadrées à l'écran et dans la visibilité d'un chef #185). Chacune trace ses sous-agents (reviewer,security-auditor,verifier) dans sa section Preuves, sauf fix(admin): #128 — l'âge ne restreint plus les rôles attribuables #182 et fix(roles): une adresse email déjà attribuée n'est modifiable que par l'ADMIN #176, antérieures à cette règle.git merge-tree origin/main origin/develop: aucun conflit.unit_leadrejouée sur base vierge et sur base seedée dans feat(admin): #128 — unités encadrées (UnitLead), périmètre d'un chef #183.Invariants
withAudit(): vérifié PR par PR (setUserLeadUnitsavec avant/après)can(user, "…"):user.manage,user.email.set20261007163359_unit_leadUnitLead. Le seed contient un chef de 17 ans.Décisions prises
Entrées
DECISIONS.md: D-044 (l'âge ne restreint plus les rôles) et D-045 (le périmètre d'un chef estUnitLead). Choix A validé : un RG ou une secrétaire peut s'attribuer CHEF et des unités encadrées, avec trace dans l'audit et sans notification.Risques et points à vérifier
TODO(ROLES-06)) : le Chef est borné parledUnits, les autres rôles parUser.unit. La matrice de rôles la résoudra.leaderIdsignorecanLogin, et les libellés d'unité ne sont pas uniformes dans la liste admin.