diff --git a/CESIZen_Soutenance.pptx b/CESIZen_Soutenance.pptx index 22dbbd7..29980bf 100644 Binary files a/CESIZen_Soutenance.pptx and b/CESIZen_Soutenance.pptx differ diff --git a/CLAUDE.md b/CLAUDE.md index 6939626..64c1c86 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,8 +48,8 @@ Cesizen/ | Configurer les émotions (2 niveaux) | Admin | ✅ | N/A | ### Hiérarchie des émotions (seed) -7 émotions de base (niveau 1) avec 33 sous-émotions (niveau 2) : -Joie, Tristesse, Colère, Peur, Dégoût, Surprise, Amour. +6 émotions de base (niveau 1) avec 36 sous-émotions (niveau 2), conformes au référentiel du sujet : +Joie, Colère, Peur, Tristesse, Surprise, Dégoût. ## Grille de priorisation des besoins Critères utilisés : Complexité (0-3), Valeur ajoutée Ministère (0-3), Valeur ajoutée Utilisateur (0-3), Nécessité (0-2), Interdépendance (0-2). Total sur 15. diff --git a/Plan_Oral_CESIZen.md b/Plan_Oral_CESIZen.md index 2630671..6f14f2f 100644 --- a/Plan_Oral_CESIZen.md +++ b/Plan_Oral_CESIZen.md @@ -16,7 +16,7 @@ | **0:00 – 2:00** (2′) | 1 — 2 | **Introduction** | Se présenter. Annoncer le commanditaire (Ministère) et l'objet : une plateforme grand public de santé mentale. Donner le fil rouge : « je vais dérouler le recueil du besoin, la priorisation, la réponse fonctionnelle, puis la modélisation technique et la conformité RGPD. » Présenter le sommaire (slide 2). | | **2:00 – 5:00** (3′) | 3 — 4 | **Contexte, enjeux, parties prenantes** | Rappeler l'enjeu sociétal (22 % des Français, SPF 2023) et la stigmatisation. Énoncer les 4 objectifs stratégiques. Présenter les parties prenantes et les 3 acteurs (Visiteur, Utilisateur, Administrateur). Insister : « le besoin a été **reformulé**, pas recopié. » | | **5:00 – 7:00** (2′) | 5 — 6 | **Besoins & priorisation** | Périmètre : 2 modules obligatoires + Tracker au choix ; modules écartés assumés. Présenter la grille pondérée /15 (5 critères). Conclusion argumentée : « le Tracker cumule 4 fonctionnalités à 9-10/15, c'est le module au choix le plus rentable. » | -| **7:00 – 12:00** (5′) | 7 — 8 — 9 | **Réponse fonctionnelle** | Module Comptes : JWT, RGPD, admin (slide 7 + maquette). Module Informations : feeds, modération, slug auto (slide 8). Module Tracker : wizard 3 étapes, journal, rapports 4 périodes, 7+33 émotions (slide 9 + maquettes). Montrer que chaque écran répond à un besoin précis. | +| **7:00 – 12:00** (5′) | 7 — 8 — 9 | **Réponse fonctionnelle** | Module Comptes : JWT, RGPD, admin (slide 7 + maquette). Module Informations : feeds, modération, slug auto (slide 8). Module Tracker : wizard 3 étapes, journal, rapports 4 périodes, 6+36 émotions (slide 9 + maquettes). Montrer que chaque écran répond à un besoin précis. | | **12:00 – 16:00** (4′) | 10 — 11 — 12 | **Modélisation** | Cas d'usage UML (slide 10) : couverture par acteur. MCD Merise (slide 11) : 8 entités, cardinalités, hiérarchie d'émotions auto-référencée. Architecture MVC découplée (slide 12) : 1 API REST Laravel → 2 clients ; justifier le pattern (testabilité, évolutivité, non-duplication). | | **16:00 – 17:30** (1′30) | 13 | **RGPD & données sensibles** | Données de santé = sensibles (art. 9). Consentement, droits CNIL (export/anonymisation), soft delete. Sécurité : chiffrement AES-256/TLS, JWT, HDS, table audits. | | **17:30 – 19:00** (1′30) | 14 | **Prototype & perspectives** | Prototype fonctionnel (Laravel + Next.js + Expo + Docker). Ouverture : activer les modules écartés sans réécrire le modèle, Open Data, Mon Espace Santé (FHIR), i18n. | @@ -49,7 +49,7 @@ > Le besoin est un journal personnel unique ; le tracker est créé automatiquement à l'inscription. Le modèle reste extensible (passer en 1-N) si un jour on veut plusieurs journaux thématiques. **Q7. Comment gérez-vous la hiérarchie d'émotions à 2 niveaux ?** -> Une seule table `emotions` avec auto-référence `parent_id` : niveau 1 = parent_id NULL, niveau 2 = parent_id renseigné. 7 émotions de base + 33 sous-émotions. L'admin la configure via le CRUD émotions. +> Une seule table `emotions` avec auto-référence `parent_id` : niveau 1 = parent_id NULL, niveau 2 = parent_id renseigné. 6 émotions de base + 36 sous-émotions (référentiel du sujet). L'admin la configure via le CRUD émotions. ### Données & sécurité (RGPD) **Q8. Les données émotionnelles sont sensibles — comment êtes-vous conforme ?** diff --git a/assets_dossier/mcd.png b/assets_dossier/mcd.png index b071ae8..cd808be 100644 Binary files a/assets_dossier/mcd.png and b/assets_dossier/mcd.png differ diff --git a/assets_dossier/mockup_informations.png b/assets_dossier/mockup_informations.png new file mode 100644 index 0000000..c464c24 Binary files /dev/null and b/assets_dossier/mockup_informations.png differ diff --git a/assets_dossier/mockup_wizard.png b/assets_dossier/mockup_wizard.png index 51f6995..932884e 100644 Binary files a/assets_dossier/mockup_wizard.png and b/assets_dossier/mockup_wizard.png differ diff --git a/backend/database/seeders/EmotionSeeder.php b/backend/database/seeders/EmotionSeeder.php index 0659a57..96cef88 100644 --- a/backend/database/seeders/EmotionSeeder.php +++ b/backend/database/seeders/EmotionSeeder.php @@ -12,30 +12,22 @@ class EmotionSeeder extends Seeder */ public function run(): void { + // Référentiel d'émotions conforme au sujet détaillé CESIZen (§7) : + // 6 émotions de base (niveau 1) et leurs sous-émotions (niveau 2). + // La colonne « Surprise » du sujet liste « Étonnement » en double (coquille) : + // l'occurrence est dédupliquée ici. Total : 36 sous-émotions. $emotions = [ [ 'nom' => 'Joie', 'couleur' => '#FFD700', 'icone' => '😊', 'sous_emotions' => [ - ['nom' => 'Bonheur', 'couleur' => '#FFE44D'], - ['nom' => 'Gratitude', 'couleur' => '#FFEB70'], - ['nom' => 'Sérénité', 'couleur' => '#FFF0A0'], - ['nom' => 'Enthousiasme', 'couleur' => '#FFE333'], - ['nom' => 'Fierté', 'couleur' => '#FFED80'], - ['nom' => 'Espoir', 'couleur' => '#FFF4B3'], - ], - ], - [ - 'nom' => 'Tristesse', - 'couleur' => '#4169E1', - 'icone' => '😢', - 'sous_emotions' => [ - ['nom' => 'Mélancolie', 'couleur' => '#6A8BE9'], - ['nom' => 'Solitude', 'couleur' => '#7D9BED'], - ['nom' => 'Déception', 'couleur' => '#90ABF1'], - ['nom' => 'Nostalgie', 'couleur' => '#A3BBF5'], - ['nom' => 'Chagrin', 'couleur' => '#5A7DE5'], + ['nom' => 'Fierté', 'couleur' => '#FFE44D'], + ['nom' => 'Contentement', 'couleur' => '#FFEB70'], + ['nom' => 'Enchantement', 'couleur' => '#FFF0A0'], + ['nom' => 'Excitation', 'couleur' => '#FFE333'], + ['nom' => 'Émerveillement', 'couleur' => '#FFED80'], + ['nom' => 'Gratitude', 'couleur' => '#FFF4B3'], ], ], [ @@ -45,9 +37,10 @@ class EmotionSeeder extends Seeder 'sous_emotions' => [ ['nom' => 'Frustration', 'couleur' => '#E34363'], ['nom' => 'Irritation', 'couleur' => '#E9637F'], - ['nom' => 'Agacement', 'couleur' => '#EF839B'], - ['nom' => 'Rage', 'couleur' => '#E23355'], - ['nom' => 'Indignation', 'couleur' => '#E85373'], + ['nom' => 'Rage', 'couleur' => '#EF839B'], + ['nom' => 'Ressentiment', 'couleur' => '#E23355'], + ['nom' => 'Agacement', 'couleur' => '#E85373'], + ['nom' => 'Hostilité', 'couleur' => '#EE93A7'], ], ], [ @@ -55,22 +48,25 @@ class EmotionSeeder extends Seeder 'couleur' => '#9932CC', 'icone' => '😰', 'sous_emotions' => [ - ['nom' => 'Anxiété', 'couleur' => '#AD5BD6'], - ['nom' => 'Inquiétude', 'couleur' => '#B96FDC'], - ['nom' => 'Panique', 'couleur' => '#C583E2'], - ['nom' => 'Stress', 'couleur' => '#D197E8'], - ['nom' => 'Appréhension', 'couleur' => '#DDABEE'], + ['nom' => 'Inquiétude', 'couleur' => '#AD5BD6'], + ['nom' => 'Anxiété', 'couleur' => '#B96FDC'], + ['nom' => 'Terreur', 'couleur' => '#C583E2'], + ['nom' => 'Appréhension', 'couleur' => '#D197E8'], + ['nom' => 'Panique', 'couleur' => '#DDABEE'], + ['nom' => 'Crainte', 'couleur' => '#C97FE0'], ], ], [ - 'nom' => 'Dégoût', - 'couleur' => '#228B22', - 'icone' => '🤢', + 'nom' => 'Tristesse', + 'couleur' => '#4169E1', + 'icone' => '😢', 'sous_emotions' => [ - ['nom' => 'Aversion', 'couleur' => '#4DA64D'], - ['nom' => 'Répulsion', 'couleur' => '#66B366'], - ['nom' => 'Mépris', 'couleur' => '#80C080'], - ['nom' => 'Écœurement', 'couleur' => '#3D9C3D'], + ['nom' => 'Chagrin', 'couleur' => '#6A8BE9'], + ['nom' => 'Mélancolie', 'couleur' => '#7D9BED'], + ['nom' => 'Abattement', 'couleur' => '#90ABF1'], + ['nom' => 'Désespoir', 'couleur' => '#A3BBF5'], + ['nom' => 'Solitude', 'couleur' => '#5A7DE5'], + ['nom' => 'Dépression', 'couleur' => '#87A1EF'], ], ], [ @@ -80,19 +76,23 @@ class EmotionSeeder extends Seeder 'sous_emotions' => [ ['nom' => 'Étonnement', 'couleur' => '#FFA333'], ['nom' => 'Stupéfaction', 'couleur' => '#FFB666'], - ['nom' => 'Émerveillement', 'couleur' => '#FFC999'], - ['nom' => 'Choc', 'couleur' => '#FF9A1A'], + ['nom' => 'Sidération', 'couleur' => '#FFC999'], + ['nom' => 'Incrédule', 'couleur' => '#FF9A1A'], + ['nom' => 'Émerveillement', 'couleur' => '#FFAD4D'], + ['nom' => 'Confusion', 'couleur' => '#FFC080'], ], ], [ - 'nom' => 'Amour', - 'couleur' => '#FF69B4', - 'icone' => '💕', + 'nom' => 'Dégoût', + 'couleur' => '#228B22', + 'icone' => '🤢', 'sous_emotions' => [ - ['nom' => 'Tendresse', 'couleur' => '#FF87C3'], - ['nom' => 'Affection', 'couleur' => '#FFA5D2'], - ['nom' => 'Compassion', 'couleur' => '#FFC3E1'], - ['nom' => 'Admiration', 'couleur' => '#FF96CA'], + ['nom' => 'Répulsion', 'couleur' => '#4DA64D'], + ['nom' => 'Déplaisir', 'couleur' => '#66B366'], + ['nom' => 'Nausée', 'couleur' => '#80C080'], + ['nom' => 'Dédain', 'couleur' => '#3D9C3D'], + ['nom' => 'Horreur', 'couleur' => '#5CAC5C'], + ['nom' => 'Dégoût profond', 'couleur' => '#73BA73'], ], ], ]; diff --git a/generate_cahier_charges.py b/generate_cahier_charges.py index 0331a8a..a8c8141 100644 --- a/generate_cahier_charges.py +++ b/generate_cahier_charges.py @@ -35,6 +35,10 @@ _UNICODE_FIX = { '≤': '<=', '≥': '>=', '°': 'deg', + 'œ': 'oe', + 'Œ': 'OE', + 'æ': 'ae', + 'Æ': 'AE', } def _safe(s): @@ -265,8 +269,38 @@ for lib, val in metadata: pdf.set_font('Helvetica', '', 10) pdf.cell(0, 7, val, new_x="LMARGIN", new_y="NEXT") -# ─────────────── 1. Glossaire ─────────────── +# ─────────────── Sommaire ─────────────── pdf.add_page() +pdf.set_font('Helvetica', 'B', 16) +pdf.set_text_color(*COULEUR_BLEU) +pdf.set_fill_color(*COULEUR_BLEU_CLAIR) +pdf.cell(0, 11, ' Sommaire', fill=True, new_x="LMARGIN", new_y="NEXT") +pdf.ln(6) +sommaire = [ + ('1', 'Glossaire'), + ('2', 'Recueil du besoin'), + ('3', 'Critères de priorisation et pondération'), + ('4', 'Cahier des charges - Analyse'), + ('5', 'Réponse fonctionnelle - Spécifications par module'), + ('6', "Schématisation UML - Cas d'usage"), + ('7', 'Modèle Conceptuel de Données (MCD)'), + ('8', 'Conception technique - Architecture MVC'), + ('9', 'Diagrammes UML - Séquences clés'), + ('10', 'Gestion des données personnelles et sensibles (RGPD)'), + ('11', 'Analyse des risques et mitigation'), + ('12', 'Exigences non-fonctionnelles'), + ('13', 'Conclusion'), +] +for num, titre in sommaire: + pdf.set_font('Helvetica', 'B', 11) + pdf.set_text_color(*COULEUR_SECONDAIRE) + pdf.cell(12, 8.5, num) + pdf.set_font('Helvetica', '', 11) + pdf.set_text_color(40, 40, 40) + pdf.cell(0, 8.5, titre, new_x="LMARGIN", new_y="NEXT") +pdf.ln(6) + +# ─────────────── 1. Glossaire (même page que le sommaire) ─────────────── pdf.h1(1, 'Glossaire') glossaire = [ ('MVC', "Modèle-Vue-Contrôleur. Patron d'architecture séparant données, présentation et logique applicative."), @@ -330,7 +364,9 @@ pdf.table( ['Organisationnelle', 'Réalisation individuelle, 3 mois calendaires', 'CRITIQUE'], ['Organisationnelle', "Pas de budget dédié à la création de contenu", 'MOYENNE'], ['Fonctionnelle', '2 modules obligatoires + 1 au choix (Tracker retenu)', 'CRITIQUE'], + ['Budgétaire', "Budget global du projet plafonné à 75 000 EUR (sujet)", 'CRITIQUE'], ['Budgétaire', 'Stack open-source uniquement (pas de licence payante)', 'MOYENNE'], + ['Temporelle', "Livraison de la version testée sous 12 mois (sujet)", 'FORTE'], ], col_widths=[35, 130, 25], ) @@ -455,7 +491,33 @@ pdf.bullet( # ─────────────── 4. Cahier des charges — Analyse ─────────────── pdf.add_page() pdf.h1(4, 'Cahier des charges — Analyse') -pdf.h2('4.1 Acteurs identifiés') +pdf.h2('4.1 Parties prenantes et communication') +pdf.paragraph( + "Au-delà des acteurs du système, le projet mobilise plusieurs parties prenantes dont les attentes et " + "les canaux d'échange structurent la conduite du projet. Le commanditaire valide les livrables en comité " + "de pilotage ; l'apprenant (maîtrise d'œuvre) restitue son avancement via le dossier et la soutenance ; " + "les contenus sont produits par des professionnels de santé et hébergés chez un prestataire HDS sous " + "le contrôle de la CNIL." +) +pdf.table( + headers=['Partie prenante', 'Rôle / intérêt', 'Attentes', 'Canal de communication'], + rows=[ + ['Ministère (commanditaire)', "Finance et valide le projet", + "Conformité santé publique, RGPD, image institutionnelle", "Comités de pilotage, validation des livrables"], + ["Apprenant (maîtrise d'œuvre)", "Conçoit et développe la solution", + "Cadrage clair, périmètre stable", "Dossier, revues d'avancement, soutenance"], + ['Utilisateurs finaux', "Usage quotidien de la plateforme", + "Simplicité, confidentialité, accessibilité", "Retours in-app, enquêtes de satisfaction"], + ['Professionnels de santé', "Rédigent et modèrent les contenus", + "Outils d'administration fiables", "Back-office, charte éditoriale"], + ['Hébergeur HDS', "Héberge les données de santé", + "Conformité technique, disponibilité (SLA)", "Contrat de service, supervision"], + ['CNIL / DPO', "Contrôlent la conformité RGPD", + "Registre des traitements, sécurité", "Registre, analyses d'impact (AIPD)"], + ], + col_widths=[42, 40, 58, 50], +) +pdf.h2('4.2 Acteurs identifiés') pdf.table( headers=['Acteur', 'Description', 'Périmètre fonctionnel'], rows=[ @@ -472,7 +534,7 @@ pdf.table( col_widths=[35, 60, 90], ) -pdf.h2('4.2 Personas') +pdf.h2('4.3 Personas') personas = [ ("Claire — Utilisatrice (Visiteur → Membre)", "35 ans, responsable marketing à Lille. Mère célibataire de 2 enfants. Stressée par le travail, " @@ -493,7 +555,7 @@ for nom, desc in personas: pdf.multi_cell(0, 5, ' ' + desc) pdf.ln(1) -pdf.h2('4.3 Opportunités et pérennité') +pdf.h2('4.4 Opportunités et pérennité') pdf.bullet( "Évolutivité : architecture découplée (API REST + 2 clients web/mobile) permettant l'ajout futur " "des modules Diagnostic, Respiration, Activités sans réécriture." @@ -557,8 +619,7 @@ pdf.ln(2) pdf.figure(_os.path.join(ASSETS, 'mockup_inscription.png'), 62, caption="Maquette - écran d'inscription (consentement RGPD obligatoire)") -# ─── Module 2 — Informations -pdf.add_page() +# ─── Module 2 — Informations (enchaîne après le module Comptes) pdf.h2("5.2 Module 'Informations' (obligatoire)") pdf.h3("Écrans principaux") pdf.bullet("Page publique liste : grille de cartes (titre, extrait 120 caractères, image, date).") @@ -579,24 +640,27 @@ pdf.table( ], col_widths=[20, 170], ) +pdf.figure(_os.path.join(ASSETS, 'mockup_informations.png'), 88, + caption="Maquette - liste publique des pages d'information + back-office admin") # ─── Module 3 — Tracker pdf.h2("5.3 Module 'Tracker d'émotions' (au choix)") pdf.paragraph( "Le module Tracker permet à l'utilisateur d'enregistrer son état émotionnel via un wizard en 3 étapes, " "de consulter son journal, et de visualiser des rapports analytiques sur 4 périodes (semaine, mois, trimestre, année). " - "Les émotions sont structurées en 2 niveaux (7 émotions de base + 33 sous-émotions précises)." + "Les émotions sont structurées en 2 niveaux (6 émotions de base + 36 sous-émotions précises), " + "conformément au référentiel défini dans le sujet." ) pdf.h3("Wizard d'ajout de saisie (3 étapes)") pdf.block_callout( "Étape 1 — Sélection de l'émotion de base (niveau 1)", - "L'utilisateur choisit parmi 7 émotions fondamentales : Joie, Tristesse, Colère, Peur, Dégoût, Surprise, Amour. " + "L'utilisateur choisit parmi 6 émotions fondamentales : Joie, Colère, Peur, Tristesse, Surprise, Dégoût. " "Chaque émotion est représentée par une couleur et un icône distinctifs.", color=COULEUR_SECONDAIRE ) pdf.block_callout( "Étape 2 — Sous-émotion (niveau 2) + intensité 1-10", - "Selon l'émotion choisie, 4 à 6 sous-émotions plus précises sont proposées (ex: Joie → Sérénité, Enthousiasme, Fierté, Gratitude). " + "Selon l'émotion choisie, 6 sous-émotions plus précises sont proposées (ex: Joie -> Fierté, Contentement, Enchantement, Excitation, Émerveillement, Gratitude). " "L'intensité est ajustée via un slider de 1 (très faible) à 10 (très forte).", color=COULEUR_BLEU ) @@ -644,7 +708,7 @@ pdf.paragraph( "Le MCD utilise le formalisme Merise (entités, associations, cardinalités). 8 entités principales sont " "modélisées : Utilisateur, Rôle, Tracker, Émotion, SaisieTracker, Feed, ContactUrgence, Audit." ) -pdf.figure(_os.path.join(ASSETS, 'mcd.png'), 150, +pdf.figure(_os.path.join(ASSETS, 'mcd.png'), 165, caption="Modèle Conceptuel de Données (Merise) - cardinalités et hiérarchie d'émotions") pdf.h2("7.1 Cardinalités principales") @@ -781,7 +845,8 @@ pdf.table( ) pdf.h2('10.3 Mesures de sécurité techniques') pdf.bullet("Chiffrement en transit : HTTPS strict (HSTS), TLS 1.3 minimum.") -pdf.bullet("Chiffrement au repos : AES-256 sur le volume PostgreSQL, secrets dans .env hors-versioning.") +pdf.bullet("Chiffrement au repos : chiffrement du volume PostgreSQL (AES-256) prévu en production HDS. " + "À ce stade, les mots de passe sont hachés (bcrypt) et les secrets sont stockés hors-versioning (.env).") pdf.bullet("Hash mot de passe : bcrypt 12 rounds (configurable selon serveur).") pdf.bullet("Authentification : JWT signé (HS256), expiration 60min, refresh 14j, throttle login 5/min.") pdf.bullet("Autorisation : middleware role-based (jwt.auth + role:administrateur), rate limit admin 60/min.") @@ -796,7 +861,7 @@ pdf.table( headers=['Risque', 'Impact', 'Probabilité', 'Mitigation'], rows=[ ['Fuite données de santé', 'CRITIQUE', 'Faible', - "Chiffrement AES-256, HDS, audits trimestriels, minimisation données."], + "Hachage bcrypt, chiffrement volume AES-256 prévu en prod HDS, audits trimestriels, minimisation données."], ['Dérive contenus (conseil médical dangereux)', 'FORT', 'Moyen', "Modération admin obligatoire avant publication. Avertissement légal en pied de page."], ['Perte de données utilisateur', 'FORT', 'Faible', @@ -827,7 +892,6 @@ pdf.table( ['Sécurité', 'Audit pénétration', 'Annuel (tiers indépendant)'], ['Accessibilité', 'RGAA niveau', 'AA'], ['Ergonomie', 'Dark Mode', "Natif iOS / Android / Web"], - ['Internationalisation', 'Langues supportées', 'FR (v1), EN (v2)'], ], col_widths=[30, 80, 80], ) @@ -850,7 +914,7 @@ pdf.paragraph( "et démontre la faisabilité technique des choix présentés." ) -pdf.ln(6) +pdf.ln(1) pdf.set_font('Helvetica', 'I', 9) pdf.set_text_color(*COULEUR_GRIS_MOYEN) pdf.cell(0, 6, 'Sources : consignes CESI INFCDAAL1, Santé Publique France 2023, CNIL — Guide RGPD santé.', diff --git a/generate_diagrams.py b/generate_diagrams.py index 9aec759..668a2fa 100644 --- a/generate_diagrams.py +++ b/generate_diagrams.py @@ -212,9 +212,9 @@ def diagram_mcd(): ca = (p0[0] + (p1[0] - p0[0]) * 0.16, p0[1] + (p1[1] - p0[1]) * 0.16) cb = (p0[0] + (p1[0] - p0[0]) * 0.84, p0[1] + (p1[1] - p0[1]) * 0.84) for (cx, cy), card in ((ca, card_a), (cb, card_b)): - w = c.text_w(card, 10, bold=True) + 8 - c.box(cx - w / 2, cy - 9, w, 18, fill=WHITE, outline=GREEN_D, width=1, radius=5) - c.text(cx, cy, card, 10, GREEN_D, bold=True, anchor='mm') + w = c.text_w(card, 13, bold=True) + 12 + c.box(cx - w / 2, cy - 12, w, 24, fill=WHITE, outline=GREEN_D, width=2, radius=6) + c.text(cx, cy, card, 13, GREEN_D, bold=True, anchor='mm') c.pill(mx, my, verb, 11, GREEN) # liens (cardinalités Merise : (min,max) côté de chaque entité) @@ -233,8 +233,8 @@ def diagram_mcd(): c.line(ex + ew + 45, ey - 5, ex + ew / 2, ey - 5, GREEN_D, 2) c.line(ex + ew / 2, ey - 5, ex + ew / 2, ey, GREEN_D, 2) c.pill(ex + ew + 45, ey + 18, 'hiérarchie', 10, GREEN) - c.text(ex + ew + 50, ey + 40, '0,n', 9, GREEN_D, bold=True, anchor='lm') - c.text(ex + ew / 2 + 8, ey - 12, '0,1', 9, GREEN_D, bold=True, anchor='lm') + c.text(ex + ew + 52, ey + 40, '0,n', 12, GREEN_D, bold=True, anchor='lm') + c.text(ex + ew / 2 + 10, ey - 13, '0,1', 12, GREEN_D, bold=True, anchor='lm') # dessin des entités (au-dessus des liens) for name, (x, y, w, attrs) in entities.items(): @@ -538,7 +538,7 @@ def mockup_wizard(): c.ellipse(ix + 28, y + 170, 13, 13, fill=(255, 215, 0), outline=(225, 185, 0), width=2) c.text(ix + 52, y + 170, "Joie", 14, GREY_D, bold=True, anchor='lm') # sous-émotions - subs = ['Sérénité', 'Gratitude', 'Fierté', 'Espoir', 'Bonheur', 'Enthousiasme'] + subs = ['Fierté', 'Contentement', 'Enchantement', 'Excitation', 'Émerveillement', 'Gratitude'] for i, s in enumerate(subs): sx = ix + (i % 2) * 140 sy = y + 215 + (i // 2) * 50 @@ -598,6 +598,48 @@ def mockup_rapports(): c.save('mockup_rapports.png') +def mockup_informations(): + c = Canvas(620, 760) + title_bar(c, 14, 14, 592, "Maquette - Informations (pages de contenu)", fill=GREEN_D) + x, y, w, h = 40, 80, 540, 650 + # fenêtre navigateur + c.box(x, y, w, h, fill=WHITE, outline=GREY_D, width=3, radius=14) + c.box(x, y, w, 40, fill=GREY_L, outline=GREY_L, radius=14) + c.rect(x, y + 22, w, 18, fill=GREY_L) + for i, col in enumerate([(255, 95, 86), (255, 189, 46), (39, 201, 63)]): + c.ellipse(x + 22 + i * 22, y + 20, 7, 7, fill=col, outline=col) + c.text(x + w / 2, y + 20, "cesizen.fr / informations", 10, GREY_D, anchor='mm') + ix = x + 28 + c.text(ix, y + 68, "Santé mentale - Ressources", 16, BLUE, bold=True, anchor='lm') + c.text(ix, y + 92, "Articles et conseils validés par nos professionnels", 10, GREY, anchor='lm') + # cartes articles (liste publique) + articles = [ + ("Comprendre le stress", ["Mécanismes du stress et signaux", "d'alerte à reconnaître au quotidien."]), + ("5 exercices anti-anxiété", ["Respiration et ancrage pour apaiser", "une montée d'anxiété."]), + ("Bien dormir, mieux vivre", ["L'impact du sommeil sur la santé", "mentale et routines de repos."]), + ("Quand consulter ?", ["Repères pour identifier le moment", "d'aller voir un professionnel."]), + ] + cy0 = y + 118 + for i, (titre, lignes) in enumerate(articles): + cardx = ix + (i % 2) * 258 + cardy = cy0 + (i // 2) * 152 + c.box(cardx, cardy, 240, 132, fill=GREY_LL, outline=GREY_L, width=1, radius=12) + c.box(cardx, cardy, 240, 40, fill=BLUE_L, outline=BLUE_L, radius=12) + c.rect(cardx, cardy + 22, 240, 18, fill=BLUE_L) + c.text(cardx + 14, cardy + 20, titre, 11, BLUE, bold=True, anchor='lm') + for j, ln in enumerate(lignes): + c.text(cardx + 14, cardy + 62 + j * 19, ln, 9, INK, anchor='lm') + c.text(cardx + 14, cardy + 112, "12 mai 2026 · Lire ->", 8, GREEN_D, bold=True, anchor='lm') + # bandeau back-office admin + ay = cy0 + 320 + c.box(ix, ay, w - 56, 40, fill=(255, 248, 200), outline=YELLOW, width=2, radius=10) + c.text(ix + 14, ay + 20, "Back-office admin : créer / modifier / publier · slug auto · " + "modération avant mise en ligne", 9, GREY_D, anchor='lm') + c.text(x + w / 2, y + h - 14, "RG-INF-01 slug auto · RG-INF-02 brouillon/publié · RG-INF-06 modération", + 8, GREY, anchor='mm') + c.save('mockup_informations.png') + + # ════════════════════════════════════════════════════════════════════ def main(): print("Génération des schémas CESIZen ->", OUT_DIR) @@ -608,6 +650,7 @@ def main(): diagram_mvc() mockup_inscription() mockup_wizard() + mockup_informations() mockup_rapports() print("Terminé.") diff --git a/generate_slides.py b/generate_slides.py index 34f5aaf..7357b59 100644 --- a/generate_slides.py +++ b/generate_slides.py @@ -229,7 +229,7 @@ cols = [ ]), ("1 module AU CHOIX (retenu)", BLUE, [ "Tracker d'émotions : journal, saisies, rapports périodiques.", - "Hiérarchie : 7 émotions de base + 33 sous-émotions.", + "Hiérarchie : 6 émotions de base + 36 sous-émotions (référentiel du sujet).", ]), ("Modules ÉCARTÉS", GREY, [ "Diagnostic de stress.", @@ -326,7 +326,7 @@ bullets(s, [ "Journal de bord : consultation, modification, suppression des saisies.", "Rapports analytiques sur 4 périodes : semaine, mois, trimestre, année.", "Statistiques : intensité moyenne, émotion dominante, répartition, évolution.", - "Hiérarchie configurable par l'admin : 7 émotions + 33 sous-émotions.", + "Hiérarchie configurable par l'admin : 6 émotions + 36 sous-émotions.", "Web (graphiques Recharts) et mobile (Expo) synchronisés via l'API.", ], Inches(0.7), Inches(1.45), Inches(7.0), Inches(5.3), size=16, gap=10) image_fit(s, "mockup_wizard.png", Inches(7.9), Inches(1.35), Inches(2.5), Inches(5.3)) @@ -383,7 +383,7 @@ rect(s, Inches(0.8), Inches(4.1), Inches(3.6), Inches(0.55), GREEN_D) tb, tf = textbox(s, Inches(0.95), Inches(4.13), Inches(3.4), Inches(0.5), MSO_ANCHOR.MIDDLE) set_par(tf.paragraphs[0], "Mesures de sécurité", 15, WHITE, bold=True, space_after=0) bullets(s, [ - "Chiffrement en transit (HTTPS/TLS 1.3) et au repos (AES-256).", + "Chiffrement en transit (HTTPS/TLS 1.3) ; bcrypt sur les mots de passe, AES-256 au repos prévu en prod HDS.", "Authentification JWT signée, expiration 60 min, throttle login.", "Hébergement certifié HDS (Scaleway / OVH Healthcare).", "Journalisation : table audits trace toute action admin sensible.", diff --git a/mobile/lib/colors.ts b/mobile/lib/colors.ts index 9b6df6e..a350df7 100644 --- a/mobile/lib/colors.ts +++ b/mobile/lib/colors.ts @@ -19,11 +19,10 @@ export const Colors = { }, emotions: { joie: '#FFD700', - tristesse: '#4169E1', colere: '#DC143C', peur: '#9932CC', - degout: '#228B22', + tristesse: '#4169E1', surprise: '#FF8C00', - amour: '#FF69B4', + degout: '#228B22', }, };