From 7352ecef44863e4872785f5ba8197961de71d260 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sun, 31 May 2026 16:50:53 -0400 Subject: [PATCH] Ajouter garde-fous d utilisation --- backend/app/routers/accueil.py | 2 + docs/GARDE_FOUS_SOCIAUX.md | 51 +++++++++ docs/UTILISATEURS.md | 20 ++++ frontend/src/App.jsx | 4 + frontend/src/pages/Accueil.jsx | 4 +- frontend/src/pages/JournalActions.jsx | 5 +- frontend/src/pages/ModePapier.jsx | 109 ++++++++++++++++++++ frontend/src/pages/PrincipesUtilisation.jsx | 44 ++++++++ frontend/src/pages/Profil.jsx | 73 ++++++++++++- 9 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 docs/GARDE_FOUS_SOCIAUX.md create mode 100644 frontend/src/pages/ModePapier.jsx create mode 100644 frontend/src/pages/PrincipesUtilisation.jsx diff --git a/backend/app/routers/accueil.py b/backend/app/routers/accueil.py index b335a7f..e25f712 100644 --- a/backend/app/routers/accueil.py +++ b/backend/app/routers/accueil.py @@ -21,6 +21,8 @@ MODULES_CONSULTATION = [ ModuleTuile(code="C5", nom="Gouvernance", description="Décisions du groupe", icone="📌", couleur="red"), ModuleTuile(code="C7", nom="Mon profil", description="Modifier, PIN, notifications", icone="👤", couleur="gray"), ModuleTuile(code="C9", nom="Postes à pourvoir", description="Postes disponibles, candidature", icone="🙋", couleur="yellow"), + ModuleTuile(code="C11", nom="Principes d'utilisation", description="L'application comme outil de service", icone="🧭", couleur="indigo"), + ModuleTuile(code="C12", nom="Mode papier", description="Formulaires de reprise en main", icone="🖨️", couleur="gray"), ModuleTuile(code="S1T", nom="Trésorerie", description="État des résultats, soldes, registre", icone="🏦", couleur="green"), ] diff --git a/docs/GARDE_FOUS_SOCIAUX.md b/docs/GARDE_FOUS_SOCIAUX.md new file mode 100644 index 0000000..5796142 --- /dev/null +++ b/docs/GARDE_FOUS_SOCIAUX.md @@ -0,0 +1,51 @@ +# Garde-fous sociaux pour l'application + +Ce document propose des textes de support que le groupe peut lire, adapter et adopter. +Ils visent a garder l'application a sa juste place : un outil de service, pas une autorite. + +## Resolution type + +> Le groupe reconnait cette application comme un outil de service. Elle vise a alleger les taches, preserver l'historique et soutenir la transparence. Elle ne remplace pas la conscience de groupe, ne sert pas a surveiller les membres et ne doit jamais etre necessaire pour participer a une reunion. Les membres conservent la possibilite de reprendre les processus sur papier lorsque l'informatique n'est pas disponible. + +## Charte courte d'utilisation + +1. L'application assiste le groupe; elle ne decide pas pour lui. +2. Le journal sert a comprendre les changements, corriger les erreurs et proteger l'historique. +3. Les permissions suivent les postes de service et doivent etre revues regulierement. +4. Les donnees personnelles conservees doivent rester minimales et utiles. +5. Les rapports imprimables permettent une reprise en main si l'outil est indisponible. +6. Le compte Sysadmin est un outil technique, pas un poste de pouvoir dans le groupe. +7. Les decisions importantes demeurent prises en assemblee, selon la conscience de groupe. + +## Message de presentation aux membres + +Cette application a ete concue pour aider les serviteurs du groupe a faire leur service plus simplement. +Elle rassemble les informations utiles aux rencontres, assemblees, finances, postes et decisions du groupe. + +Elle ne remplace pas la parole, la confiance, la conscience de groupe ni les traditions. +Elle sert surtout a eviter les oublis, faciliter les rapports, garder une trace des changements et permettre une meilleure continuite entre les serviteurs. + +Chaque membre peut consulter ce qui lui est utile selon ses acces. +Les actions importantes sont journalisees pour proteger l'historique, non pour surveiller les membres. +Lorsque l'informatique n'est pas disponible, le groupe peut continuer sur papier et ressaisir les informations plus tard. + +## Questions a revoir periodiquement + +- Les permissions correspondent-elles encore aux postes reellement occupes? +- Les rapports produits aident-ils vraiment les discussions du groupe? +- Des donnees inutiles sont-elles conservees? +- Le journal est-il utilise pour comprendre et non pour blamer? +- Le groupe sait-il continuer une rencontre ou une assemblee sans l'application? +- Le mot de passe Sysadmin a-t-il ete change apres installation? +- Les sauvegardes sont-elles recentes et protegees? + +## Reprise papier + +Si l'application n'est pas disponible: + +1. Ouvrir le module `Mode papier` si l'app est encore accessible, ou utiliser des formulaires deja imprimes. +2. Continuer la rencontre ou l'assemblee normalement. +3. Identifier clairement la date, le responsable et les montants. +4. Faire approuver les rapports comme d'habitude. +5. Ressaisir les donnees dans l'application lorsque le service revient. +6. Conserver le papier jusqu'a verification par le secretaire ou le tresorier. diff --git a/docs/UTILISATEURS.md b/docs/UTILISATEURS.md index fd39cc1..03d1696 100644 --- a/docs/UTILISATEURS.md +++ b/docs/UTILISATEURS.md @@ -49,6 +49,8 @@ Le module `Profil` permet de modifier ses informations personnelles : Un membre peut aussi choisir les types de changements pour lesquels il souhaite être notifié, lorsque les notifications sont disponibles sur son appareil. +Le profil explique aussi quelles données personnelles sont conservées et pourquoi. Il affiche les postes actifs du membre et les modules visibles afin que chacun puisse comprendre d'où viennent ses accès. + ### Notifications Les notifications push sont optionnelles. Le membre choisit les catégories de changements qui l'intéressent depuis son profil. Les notifications dépendent aussi du navigateur, du téléphone et de l'autorisation donnée par l'utilisateur. @@ -66,6 +68,8 @@ La page `Accueil` regroupe ce qu'un membre consulte souvent : - événements; - littérature; - profil; +- principes d'utilisation; +- mode papier; - modules de consultation. ### Rencontres @@ -541,6 +545,20 @@ Le rapport d'assemblée d'affaires tient lieu de procès-verbal imprimable. Il r Le rapport de trésorerie présente les résultats du mois précédent et les positions de trésorerie à la fin de ce mois. +### Mode papier + +Le module `Mode papier` offre des formulaires vierges imprimables pour : + +- rencontre hebdomadaire; +- assemblée d'affaires; +- trésorerie. + +Ces formulaires servent de plan de secours. Ils permettent de continuer les activités du groupe si l'application ou le réseau ne sont pas disponibles, puis de ressaisir les données plus tard. + +### Principes d'utilisation + +Le module `Principes d'utilisation` rappelle que l'application est un outil de service. Elle soutient le groupe, mais ne remplace pas la conscience de groupe, la discussion ni les processus papier lorsque nécessaires. + ## 13. Journal Le journal conserve les actions modificatrices faites dans l'application. @@ -556,6 +574,8 @@ Le journal présente deux niveaux : l'historique métier, qui explique les chang Les consultations simples ne sont pas journalisées comme actions modificatrices. Le journal est réservé aux exécutifs. +Le journal doit servir à comprendre les changements et protéger l'historique, pas à surveiller les membres. + ## 14. Modifications simultanées Il peut arriver que deux membres exécutifs travaillent sur la même information en même temps. diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d7a43bd..0338828 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -30,6 +30,8 @@ import ReunionHebdomadaire from './pages/ReunionHebdomadaire'; import AssembleeAffaires from './pages/AssembleeAffaires'; import AssembleeInvite from './pages/AssembleeInvite'; import JournalActions from './pages/JournalActions'; +import PrincipesUtilisation from './pages/PrincipesUtilisation'; +import ModePapier from './pages/ModePapier'; import BottomNav from './components/BottomNav'; export default function App() { @@ -92,6 +94,8 @@ export default function App() { case 'M4': pageActive = ; break; case 'G8': pageActive = ; break; case 'C9': pageActive = ; break; + case 'C11': pageActive = ; break; + case 'C12': pageActive = ; break; case 'C10': pageActive = ; break; default: pageActive = ; } diff --git a/frontend/src/pages/Accueil.jsx b/frontend/src/pages/Accueil.jsx index 26ab5c1..1233d24 100644 --- a/frontend/src/pages/Accueil.jsx +++ b/frontend/src/pages/Accueil.jsx @@ -12,7 +12,7 @@ const COULEURS = { gray: 'bg-gray-50 border-gray-200 text-gray-700', }; -const NAVIGABLE = ['C7', 'S1', 'S1T', 'S2', 'S3', 'S4', 'S5', 'C1', 'C2', 'C4', 'C5', 'C9', 'G2', 'G9', 'G11', 'G12', 'G13', 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6']; +const NAVIGABLE = ['C7', 'S1', 'S1T', 'S2', 'S3', 'S4', 'S5', 'C1', 'C2', 'C4', 'C5', 'C9', 'C11', 'C12', 'G2', 'G9', 'G11', 'G12', 'G13', 'M0', 'M1', 'M2', 'M3', 'M4', 'M5', 'M6']; const MODULES_CONTEXTE = new Set(['S0', 'M0', 'M1', 'M2']); const CONTEXTES = { @@ -22,7 +22,7 @@ const CONTEXTES = { sections: [ { titre: 'À faire maintenant', codes: ['S5', 'C5', 'C9'] }, { titre: 'État', codes: ['S1T', 'C2', 'C1', 'C4'] }, - { titre: 'Mon espace', codes: ['C7'] }, + { titre: 'Mon espace', codes: ['C7', 'C11', 'C12'] }, ], }, reunion: { diff --git a/frontend/src/pages/JournalActions.jsx b/frontend/src/pages/JournalActions.jsx index 967b5d1..e6187a6 100644 --- a/frontend/src/pages/JournalActions.jsx +++ b/frontend/src/pages/JournalActions.jsx @@ -122,6 +122,9 @@ export default function JournalActions() { {tab === 'historique' && (
+

+ Le journal sert à comprendre les changements et protéger l'historique, pas à surveiller les membres. +

updateFiltre('q', e.target.value)} @@ -210,7 +213,7 @@ export default function JournalActions() {

Domaine
{domaineLabel(item.table_cible)}

Action
{item.action}

-

Objet
{item.objet_id}

+

Référence technique
{item.objet_id}

{item.chemin_api &&

API
{item.chemin_api}

}
diff --git a/frontend/src/pages/ModePapier.jsx b/frontend/src/pages/ModePapier.jsx new file mode 100644 index 0000000..9f14c33 --- /dev/null +++ b/frontend/src/pages/ModePapier.jsx @@ -0,0 +1,109 @@ +import React from 'react'; +import PageHeader from '../components/PageHeader'; +import { useStore } from '../stores/store'; + +const formulaires = [ + { + titre: 'Rencontre hebdomadaire', + description: 'Présences informelles, collecte, ventes, jetons et notes de réunion.', + fichier: 'rencontre', + }, + { + titre: "Assemblée d'affaires", + description: 'Ordre du jour, présences, propositions, décisions, postes et rapport du trésorier.', + fichier: 'assemblee', + }, + { + titre: 'Trésorerie', + description: 'Collectes, dépôts, dépenses, réserves et rapprochement mensuel.', + fichier: 'tresorerie', + }, +]; + +const lignes = (n) => Array.from({ length: n }, (_, i) => `
${i + 1}.
`).join(''); + +function htmlFormulaire(type, groupe) { + const nomGroupe = groupe?.nom || 'Groupe'; + const commun = ` +
+

${nomGroupe}

+

Formulaire papier de reprise en main

+
+
+
Date: ____________________
+
Responsable: ____________________
+
`; + const sections = { + rencontre: ` +

Rencontre hebdomadaire

+
+
Montant: __________
Détenteur: __________
+ ${lignes(6)} + ${lignes(6)} +
`, + assemblee: ` +

Assemblée d'affaires

+ ${lignes(12)} +
+ ${lignes(10)} + ${lignes(6)} +
`, + tresorerie: ` +

Trésorerie

+ ${lignes(8)} + ${lignes(8)} + ${lignes(8)} +
`, + }; + return `${nomGroupe} - ${type} + ${commun}${sections[type]}`; +} + +export default function ModePapier() { + const { groupe } = useStore(); + + const imprimer = (type) => { + const win = window.open('', '_blank'); + if (!win) return; + win.document.write(htmlFormulaire(type, groupe)); + win.document.close(); + }; + + return ( +
+ +
+
+

+ Ces formulaires vierges servent de plan de secours. Ils permettent de poursuivre une rencontre, + une assemblée ou une opération de trésorerie, puis de ressaisir les données plus tard. +

+
+ {formulaires.map((formulaire) => ( + + ))} +
+
+ ); +} diff --git a/frontend/src/pages/PrincipesUtilisation.jsx b/frontend/src/pages/PrincipesUtilisation.jsx new file mode 100644 index 0000000..d758340 --- /dev/null +++ b/frontend/src/pages/PrincipesUtilisation.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import PageHeader from '../components/PageHeader'; + +const PRINCIPES = [ + ['Outil de service', "L'application soutient les serviteurs; elle ne remplace jamais la conscience de groupe."], + ['Reprise sur papier', "Les rencontres, assemblées et rapports doivent pouvoir continuer même si l'informatique tombe."], + ['Sobriété des données', "On conserve seulement les renseignements utiles au fonctionnement du groupe."], + ['Transparence', "Le journal sert à comprendre les changements et protéger l'historique, pas à surveiller les membres."], + ['Pouvoirs visibles', "Les accès viennent des postes occupés. Les actions sensibles doivent rester explicables au groupe."], + ['Participation libre', "L'application ne doit jamais devenir nécessaire pour assister à une réunion ou participer au groupe."], +]; + +export default function PrincipesUtilisation() { + return ( +
+ +
+
+

+ Cette application aide le groupe à alléger les tâches, préserver l'historique et soutenir la transparence. + Elle ne gouverne pas le groupe. Les décisions demeurent prises par les membres, selon les pratiques du groupe. +

+
+ +
+ {PRINCIPES.map(([titre, texte]) => ( +
+

{titre}

+

{texte}

+
+ ))} +
+ +
+

Boussole simple

+

+ Une fonctionnalité est saine si elle augmente la capacité du groupe à se servir lui-même. + Elle devient fragile si elle augmente surtout le contrôle sur les membres. +

+
+
+
+ ); +} diff --git a/frontend/src/pages/Profil.jsx b/frontend/src/pages/Profil.jsx index b91dfd1..916ce33 100644 --- a/frontend/src/pages/Profil.jsx +++ b/frontend/src/pages/Profil.jsx @@ -10,7 +10,15 @@ import { } from '../utils/pushNotifications'; export default function Profil() { - const { setPage, estSysadmin, logout } = useStore(); + const { + setPage, + estSysadmin, + logout, + postes, + modulesConsultation, + modulesSaisie, + modulesGestion, + } = useStore(); const [profil, setProfil] = useState(null); const [editing, setEditing] = useState(false); const [form, setForm] = useState({}); @@ -169,6 +177,15 @@ export default function Profil() { ); + const modulesAccessibles = [ + ...(modulesConsultation || []), + ...(modulesSaisie || []), + ...(modulesGestion || []), + ].reduce((acc, module) => { + if (!acc.some((m) => m.code === module.code)) acc.push(module); + return acc; + }, []); + return (
@@ -240,6 +257,51 @@ export default function Profil() { )}
+
+
+

Données conservées

+

+ L'application conserve seulement les informations utiles au service du groupe. +

+
+
+ + + + + + +
+

+ Le droit à l'oubli conserve l'ID et le prénom pour l'historique, puis neutralise les autres renseignements personnels. +

+
+ +
+
+

Pourquoi ai-je accès à ceci?

+

+ Les accès viennent des postes actifs occupés. Les modules de consultation sont visibles aux membres connectés. +

+
+
+

Postes actifs

+

{estSysadmin ? 'Sysadmin' : postes?.length ? postes.join(', ') : 'Aucun poste actif'}

+
+ {modulesAccessibles.length > 0 && ( +
+

Modules visibles

+
+ {modulesAccessibles.map((module) => ( + + {module.nom} + + ))} +
+
+ )} +
+ {/* Notifications */}
@@ -356,3 +418,12 @@ export default function Profil() {
); } + +function InfoDonnee({ nom, raison }) { + return ( +
+

{nom}

+

{raison}

+
+ ); +}