Repository navigation
feat(admin): #128 — unités encadrées à l'écran et dans la visibilité d'un chef - #185
Merged
Merged
Conversation
…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>
Owner
Author
5 tasks done
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
Refs #128 — étape 4 sur 4 (écrans et visibilité). Je ne ferme pas l'issue : la reprise de données (« saisir les compagnons qui encadrent déjà ») se fait à la main, avec l'écran ajouté ici.
Ce qui change
/admin/utilisateurs/[id]/modifier, à côté de l'unité d'appartenance. Pour un compte qui n'est pas Chef, l'éditeur explique qu'il faut d'abord lui donner ce rôle. Si le rôle a été retiré entre-temps, le serveur refuse avec « Seul un compte Chef peut encadrer une unité. ».Pourquoi
Après #183 et #184, Lucas pouvait agir sur les Louveteaux sans voir leurs salons, ni leurs annonces, ni leurs événements. Aucun écran ne permettait non plus de dire quelles unités un chef encadre :
setUserLeadUnitsn'avait pas d'appelant.Preuves
pnpm lint: ✅ 0 erreur. Les 3 warnings existent déjà surdevelop(TicketsSection.tsx,place-actions.ts).pnpm typecheck: ✅pnpm test: ✅ 627 tests, contre 602 surdevelop. Les 25 tests ajoutés ont été écrits avant le code : 10 échecs constatés pour la bonne raison (fonction absente, unité encadrée ignorée), puis verts.src/modules/communication/access.test.ts(nouveau, 16 tests) :UnitLeadsans rôle Chef n'ouvre rien ;UnitLeadgarde le comportement d'avant ;canAccessChanneletcanWriteChanneldonnent le même résultat avecUnitLead= unité qu'avant refactor(comptes): un compagnon peut être chef — le modèle ne gère ni plusieurs rôles d'unité ni plusieurs unités #128.src/modules/communication/audience.test.ts(+5) :UnitLeadsans Chef n'ajoute rien ;UnitLead= unité) garde la même audience sur toutes les cibles.src/lib/permissions.test.ts(+3) :ledUnitsOf.src/modules/admin/user-filters.test.ts(+1) : filtreledUniten liste blanche.pnpm dev:worktree(port 3101), base du worktree seedée (db:seedpuisdb:seed:branches). Chaque vérification lit aussi l'état en base. Après les correctifs de relecture, 29/29 et 21/21 vérifications vertes.louveteaux(accessUnits ["LOUVETEAUX"]) ettous-sauf-compagnons(ouvert,excludeUnits ["COMPAGNONS"]).louveteaux,compagnonsettous-sauf-compagnons, paspionniers;louveteaux(message en base) ;/annonces;EVENT_UPDATE. Léa (Louveteaux) le reçoit aussi, comme avant. Robin et Éléonore (cheffe des Compagnons) ne le reçoivent pas. L'événement est posté dans le salonlouveteaux;/compte) contient les événements Louveteaux et ceux des Compagnons. Celui de Robin ne contient aucun événement Louveteaux ;/planning/presencesne propose que les Louveteaux, présélectionnés ;/communication/louveteaux→ 404 ;tous-sauf-compagnonsabsent de sa liste ;/planning/presences→ redirection vers/dashboard.pionnierset paslouveteaux, comme avant.setUserLeadUnits, première exécution réelle) :UnitLead=[LOUVETEAUX, SCOUTS]. L'audit portepreviousUnits ["LOUVETEAUX"]→units ["LOUVETEAUX","SCOUTS"], avec l'admin pour auteur. Lucas voit alorsscouts-guideset son bilan propose les deux unités ;[LOUVETEAUX], avec l'audit inverse. Lucas perdscouts-guides;Notificationest contrôlée), et le flux SSE en direct.92c4c8a) :security-auditor: 1 passe. Aucun point bloquant ni élevé. 4 points relevés, 0 corrigé, 4 laissés (voir « Risques ») :leaderIdsignorecanLogin;ledUnitsest dupliquée.reviewer: 1 passe. Il a atteint sa limite de tours et je l'ai relancé une fois pour qu'il conclue : c'est la même relecture. Il n'a pas relu les tests,CLAUDE.md, D-045 ni la fin deuser-actions.tsx. Aucun point bloquant ni élevé. 5 points relevés :UnitLead, et le libellé « Encadre » était calculé deux fois par ligne ;leaderIdsfaite aussi pour les appelants qui ne s'en servent pas.verifier: 1 passe sur le commit92c4c8a. Il a rejoué les deux scripts (29/29, 21/21) et vérifié par ses propres scripts :tous-sauf-compagnons, Robin reçoit 404 ;louveteauxet/planning/presencesle renvoie vers/planning. Les unités sont rendues ensuite, avec un audit à chaque étape.architect: conception tranchée par Mathis (option E et règles de la tâche) ;featureettest-engineer: code et tests écrits dans le fil principal, tests rouges avant le code ;debugger: aucun bug à diagnostiquer ;refactorer: pas de refactor ;doc-writer:CLAUDE.mdet D-045 rédigés dans le fil principal ;git-manager: commits et PR faits dans le fil principal ;explorer/Explore: recherches faites dans le fil principal ;project-manager: sans objet.Invariants
withAudit(): la seule mutation touchée estsetUserLeadUnits, déjà souswithAudit. Son audit porte maintenantpreviousUnits, lu dans la même transaction. Le refus pour un compte non Chef annule la transaction sans écrire d'audit.can(user, "…"):requireCan("user.manage");ensureCan("user.manage")puisassertCanManageTarget(garde inchangée) ;PERMISSIONSetinUnitScopene sont pas modifiées ; seul le helperledUnitsOfest ajouté.dm-policysont inchangés : Lucas n'écrit toujours en privé à aucun mineur ;Décisions prises
ledUnitsOf), comme dansinUnitScopeetdm-policy. Une ligneUnitLeadorpheline n'ouvre rien.event.manage(PERMISSIONS["event.manage"] = [CHEF, RG]), et pour luigetNextEventne filtre pas par unité : il voit déjà les événements des Louveteaux. Ajouter les unités encadrées au filtre « membre » aurait été du code mort.leaderIdsest un champ à part deresolveUnitAudience, horsallIds. SeulnotifyEventAudiencel'utilise. Les campagnes de cotisation (jeunes et parents) et les messages de prêt et de tâche ne changent pas.reminders.tsreste sur l'appartenance, selon la consigne.USER_LEAD_UNITS_CHANGEDporte l'avant et l'après, comme la correction de date de naissance.CLAUDE.mdgagne la convention « unité d'appartenance ≠ unités encadrées ». D-045 est amendée (étape 4).Risques et points à vérifier
security-auditor) : effet du choix A. Un RG ou une secrétaire qui s'attribue CHEF puis des unités encadrées lit et écrit dans les salons de ces unités et reçoit leurs annonces et leurs événements. Avant cette PR, cela ne lui donnait que le périmètre d'action. Tout est tracé (USER_ROLE_CHANGED,USER_LEAD_UNITS_CHANGED, où l'acteur est la cible), mais personne n'est prévenu. Correctif proposé, non appliqué puisque le choix A est validé : notifier l'ADMIN et le RG quand un compte modifie ses propres unités encadrées.reviewer) : l'accès élargi vaut partout oùcanAccessChannelest appelé. C'est le cas du signalement d'un message (moderation-actions.ts:66, il faut voir le salon pour signaler) et des sondages. Lucas peut donc signaler un message du salon des Louveteaux et y voter. Le traitement des signalements passe toujours parcanModerateReportetledUnits(feat(communication): #128 — chef d'unité par UnitLead en messagerie, modération et pédagogie #184).security-auditor), déjà vrai avant : un flux SSE ouvert n'est pas réévalué. Après le retrait d'une unité, le flux continue d'envoyer des événements{type, id}jusqu'à la reconnexion. Le contenu, lui, passe par des actions qui revérifient l'accès.security-auditor) :leaderIdsne filtre pascanLogin, commememberIdsaujourd'hui. Un compte enfant porteur de CHEF, cas qui n'existe pas, serait notifié.unitLeads → ledUnitsest construit à 4 endroits nouveaux (SSE,notifyChannelMessage,loadAudienceContext, iCal). Si un futur appelant l'oublie, il est fail-closed, sans fuite ;leaderIdss'exécute aussi pour les appelants deresolveUnitAudiencequi ne s'en servent pas ;communication/access.ts(règle d'exclusion),communication/audience.ts,audience/unit-audience.tsetLeadUnitsEditordansuser-actions.tsx.accessUnits=["LOUVETEAUX"].🤖 Generated with Claude Code