NeahNew/MISSIONS_CENTRALE_WORKFLOW_ANALYSIS.md
2026-01-04 12:51:58 +01:00

25 KiB

Analyse Complète : Pages Missions et Centrale - Workflow Complet

📋 Table des Matières

  1. Vue d'ensemble
  2. Architecture des Pages
  3. Workflow de Navigation
  4. Workflow de Création de Mission
  5. Workflow de Consultation
  6. API Routes
  7. Base de Données
  8. Intégrations Externes
  9. Stockage de Fichiers
  10. Composants Réutilisables

🎯 Vue d'ensemble

Page "Centrale"

  • Route: /missions
  • Nom dans le menu: "Centrale"
  • Accès: Rôles entrepreneurship ou admin (défini dans components/main-nav.tsx)
  • Description: Centre d'Administration et de Pilotage (CAP) - Interface principale pour gérer les missions

Page "Missions"

  • Route principale: /missions
  • Sous-routes:
    • /missions - Liste des missions de l'utilisateur
    • /missions/new - Création d'une nouvelle mission
    • /missions/[missionId] - Détails d'une mission
    • /missions/[missionId]/edit - Édition d'une mission

Page "Mission Tab" (Tableau des Missions)

  • Route: /mission-tab
  • Description: Vue publique de toutes les missions disponibles
  • Sous-routes:
    • /mission-tab - Liste de toutes les missions
    • /mission-tab/[missionId] - Détails d'une mission (vue publique)

🏗️ Architecture des Pages

1. Layout Principal - Missions (app/missions/layout.tsx)

Structure:

┌─────────────────────────────────────────┐
│  Sidebar (CAP) - Fond rose clair       │
│  ┌───────────────────────────────────┐ │
│  │ CAP                               │ │
│  │ Centre d'Administration et de    │ │
│  │ Pilotage                          │ │
│  └───────────────────────────────────┘ │
│  • Mes Missions (/missions)            │
│  • Nouvelle Mission (/missions/new)   │
└─────────────────────────────────────────┘
│  Contenu Principal (children)          │
└─────────────────────────────────────────┘

Fonctionnalités:

  • Sidebar fixe avec navigation
  • Fond rose clair (bg-pink-50) pour la sidebar
  • Fond blanc pour le contenu principal
  • Navigation active highlightée

2. Page Liste des Missions (app/missions/page.tsx)

Fonctionnalités:

  • Affichage en grille (responsive: 1/2/3 colonnes)
  • Recherche par nom, niveau, type, ODD scope
  • Filtrage en temps réel
  • Cartes de mission avec:
    • Logo (ou initiales si pas de logo)
    • Nom de la mission
    • Badge niveau (A/B/C/S) avec couleurs
    • Icône ODD (Objectifs de Développement Durable)
    • Services associés
    • Description (intention) tronquée
    • Date de création
    • Bouton "Voir détails"

API utilisée: GET /api/missions

  • Retourne uniquement les missions où l'utilisateur est:
    • Créateur (creatorId)
    • Ou membre (missionUsers)

3. Page Création de Mission (app/missions/new/page.tsx)

Composant principal: MissionsAdminPanel

  • Formulaire multi-onglets (5 onglets)
  • Navigation séquentielle avec boutons Précédent/Suivant

4. Page Détails Mission (app/missions/[missionId]/page.tsx)

Fonctionnalités:

  • Affichage complet des informations
  • Logo de la mission
  • Grille d'informations (Type, Donneur d'ordre, Durée, Niveau, Participation, ODD)
  • Description complète
  • Liste des documents/attachments
  • Profils recherchés
  • Services
  • Bouton de suppression (si créateur ou admin)

API utilisée: GET /api/missions/[missionId]

5. Page Mission Tab (app/mission-tab/page.tsx)

Différences avec /missions:

  • Affiche TOUTES les missions (pas de filtre utilisateur)
  • API utilisée: GET /api/missions/all
  • Vue publique pour découvrir toutes les missions disponibles

🔄 Workflow de Navigation

Accès à la Centrale

1. Utilisateur connecté avec rôle "entrepreneurship" ou "admin"
   ↓
2. Menu déroulant utilisateur (MainNav)
   ↓
3. Clic sur "Centrale" (href: '/missions')
   ↓
4. Redirection vers /missions
   ↓
5. Layout Missions s'affiche avec sidebar CAP
   ↓
6. Page Liste des Missions (/missions/page.tsx)

Navigation dans la Centrale

┌─────────────────────────────────────────┐
│  Sidebar CAP                            │
│  ├─ Mes Missions (/missions)            │
│  └─ Nouvelle Mission (/missions/new)    │
└─────────────────────────────────────────┘
         │                    │
         │                    │
         ▼                    ▼
┌─────────────────┐  ┌──────────────────┐
│ Liste Missions  │  │ Création Mission │
│                 │  │                  │
│ [Carte Mission] │  │ [Formulaire]     │
│   └─► Détails   │  │                  │
└─────────────────┘  └──────────────────┘
         │
         ▼
┌─────────────────┐
│ Détails Mission │
│                 │
│ [Éditer]        │
│ [Supprimer]     │
└─────────────────┘

🚀 Workflow de Création de Mission

Étape 1: Accès au Formulaire

User → /missions/new → MissionsAdminPanel

Étape 2: Formulaire Multi-Onglets

Onglet 1: General

  • Nom de la mission (requis)
  • Logo (upload)
  • ODD scope (requis) - Sélection parmi 17 ODD
  • Niveau (requis) - A/B/C/S
  • Intention (requis) - Description avec éditeur de texte

Onglet 2: Details

  • Type de mission (requis) - Remote/Onsite/Hybrid
  • Donneur d'ordre (requis) - Individu/ONG/Start-ups
  • Projection (requis) - Short/Medium/Long term
  • Services - Checkboxes (Gite, ArtLab, Calcul)
  • Participation (requis) - Volontaire/Cooptation
  • Profils - Checkboxes (DataIntelligence, Expression, Mediation, Investigation, Coding, Lean)

Onglet 3: Attachments

  • Upload de fichiers (PDF, DOC, DOCX, XLS, XLSX, JPG, JPEG, PNG)
  • Liste des fichiers sélectionnés
  • Upload immédiat vers Minio (bucket 'missions')

Onglet 4: Skills

  • Liste de compétences (non fonctionnel actuellement - placeholders)

Onglet 5: Membres

  • Les Gardiens de l'Intention (3 gardiens requis):
    • Gardien du Temps
    • Gardien de la Parole
    • Gardien de la Mémoire
  • Volontaires (optionnel)
  • Recherche d'utilisateurs ou groupes
  • Assignation de rôles

Étape 3: Validation et Soumission

Validation:

const requiredFields = {
  name: !!missionData.name,
  oddScope: Array.isArray(missionData.oddScope) && missionData.oddScope.length > 0,
  niveau: !!missionData.niveau,
  intention: !!missionData.intention,
  missionType: !!missionData.missionType,
  donneurDOrdre: !!missionData.donneurDOrdre,
  projection: !!missionData.projection,
  participation: !!missionData.participation,
  gardiens: gardienDuTemps !== null && 
            gardienDeLaParole !== null && 
            gardienDeLaMemoire !== null
}

Soumission:

POST /api/missions
Body: {
  name, oddScope, niveau, intention, missionType,
  donneurDOrdre, projection, services, profils,
  participation, guardians, volunteers, logo, attachments
}

Étape 4: Traitement Backend

Séquence d'exécution:

  1. Création de la mission en base de données

    prisma.mission.create({
      data: { name, oddScope, niveau, intention, ... }
    })
    
  2. Création des MissionUsers (gardiens + volontaires)

    prisma.missionUser.createMany({
      data: [
        { missionId, userId, role: 'gardien-temps' },
        { missionId, userId, role: 'gardien-parole' },
        { missionId, userId, role: 'gardien-memoire' },
        { missionId, userId, role: 'volontaire' }, // pour chaque volontaire
      ]
    })
    
  3. Upload du logo vers Minio

    • Path: missions/{missionId}/logo{extension}
    • Bucket: missions
    • Mise à jour du champ logo dans la mission
  4. Upload des attachments vers Minio

    • Path: missions/{missionId}/attachments/{filename}
    • Création des enregistrements Attachment en base
  5. Vérification des fichiers dans Minio

    • Vérifie que tous les fichiers sont bien présents avant de continuer
  6. Déclenchement du workflow N8N

    n8nService.triggerMissionCreation({
      ...missionData,
      creatorId,
      logoPath,
      config: { N8N_API_KEY, MISSION_API_URL }
    })
    
  7. Intégrations externes (via N8N):

    • Création projet Leantime (si applicable)
    • Création collection Outline (si applicable)
    • Création canal RocketChat (si applicable)
    • Création repository Gitea (si applicable)
    • Création projet Penpot (si applicable)
  8. Retour succès/erreur

    • Si succès: Redirection vers /missions
    • Si erreur: Nettoyage des fichiers uploadés + message d'erreur

👀 Workflow de Consultation

Consultation Liste des Missions

Route: /missions ou /mission-tab

Flux:

1. Chargement de la page
   ↓
2. useEffect → fetch('/api/missions') ou fetch('/api/missions/all')
   ↓
3. Affichage du loader
   ↓
4. Réception des données
   ↓
5. Transformation des données:
   - Ajout des logoUrl (si logo existe)
   - Formatage des dates
   - Calcul des couleurs de badges
   - Extraction des infos ODD
   ↓
6. Filtrage par terme de recherche (si présent)
   ↓
7. Affichage en grille

Recherche:

  • Filtre en temps réel sur: nom, niveau, type, ODD scope
  • Pas de requête API supplémentaire (filtrage côté client)

Consultation Détails Mission

Route: /missions/[missionId] ou /mission-tab/[missionId]

Flux:

1. Chargement de la page
   ↓
2. Récupération du missionId depuis les params
   ↓
3. useEffect → fetch(`/api/missions/${missionId}`)
   ↓
4. Affichage du loader
   ↓
5. Réception des données complètes:
   - Mission avec tous les champs
   - Creator (id, email)
   - MissionUsers (avec user details)
   - Attachments (avec publicUrl)
   ↓
6. Transformation:
   - Ajout des logoUrl
   - Formatage des dates
   - Labels pour les types/niveaux
   - URLs publiques pour les attachments
   ↓
7. Affichage des sections:
   - Header avec nom et logo
   - Grille d'informations
   - Description
   - Documents
   - Profils recherchés
   - Services
   - Actions (Éditer/Supprimer)

🔌 API Routes

1. GET /api/missions

Fichier: app/api/missions/route.ts

Fonctionnalité: Liste les missions de l'utilisateur connecté

Filtres:

  • limit (default: 10)
  • offset (default: 0)
  • search (recherche dans name et intention)
  • name (filtre exact)

Where Clause:

{
  OR: [
    { creatorId: userId },
    { missionUsers: { some: { userId } } }
  ]
}

Retour:

{
  "missions": [
    {
      "id": "...",
      "name": "...",
      "logo": "missions/{id}/logo.png",
      "logoUrl": "/api/missions/image/missions/{id}/logo.png",
      "oddScope": ["odd-3"],
      "niveau": "a",
      "missionType": "remote",
      "projection": "short",
      "services": ["Gite"],
      "intention": "...",
      "createdAt": "...",
      "creator": { "id": "...", "email": "..." },
      "missionUsers": [...],
      "attachments": [...]
    }
  ],
  "pagination": {
    "total": 10,
    "offset": 0,
    "limit": 10
  }
}

2. POST /api/missions

Fichier: app/api/missions/route.ts

Fonctionnalité: Crée une nouvelle mission

Body:

{
  name: string;
  oddScope: string[];
  niveau?: string;
  intention?: string;
  missionType?: string;
  donneurDOrdre?: string;
  projection?: string;
  services?: string[];
  profils?: string[];
  participation?: string;
  guardians?: {
    "gardien-temps": string;
    "gardien-parole": string;
    "gardien-memoire": string;
  };
  volunteers?: string[];
  logo?: {
    data: string; // base64
    name?: string;
    type?: string;
  };
  attachments?: Array<{
    data: string; // base64
    name?: string;
    type?: string;
  }>;
}

Retour:

{
  "success": true,
  "mission": { ... },
  "message": "Mission created successfully with all integrations"
}

3. GET /api/missions/[missionId]

Fichier: app/api/missions/[missionId]/route.ts

Fonctionnalité: Récupère les détails d'une mission

Contrôle d'accès:

  • Utilisateur doit être créateur OU membre de la mission

Retour: Mission complète avec relations

4. PUT /api/missions/[missionId]

Fichier: app/api/missions/[missionId]/route.ts

Fonctionnalité: Met à jour une mission

Contrôle d'accès:

  • Créateur OU gardien-temps/gardien-parole

Body: Même structure que POST (tous les champs optionnels)

5. DELETE /api/missions/[missionId]

Fichier: app/api/missions/[missionId]/route.ts

Fonctionnalité: Supprime une mission

Contrôle d'accès:

  • Créateur OU admin uniquement

Actions:

  • Suppression du logo dans Minio
  • Suppression de la mission en base (cascade sur MissionUsers et Attachments)
  • TODO: Rollback N8N (non implémenté)

6. GET /api/missions/all

Fichier: app/api/missions/all/route.ts

Fonctionnalité: Liste TOUTES les missions (pas de filtre utilisateur)

Différences avec /api/missions:

  • Pas de filtre par utilisateur
  • Retourne toutes les missions publiques
  • Utilisé par /mission-tab

7. GET /api/missions/image/[...path]

Fichier: app/api/missions/image/[...path]/route.ts

Fonctionnalité: Sert les images (logos et attachments) depuis Minio

Path: missions/{missionId}/logo.png ou missions/{missionId}/attachments/{filename}

8. POST /api/missions/upload

Fichier: app/api/missions/upload/route.ts

Fonctionnalité: Upload de fichiers (logo ou attachments)

9. GET /api/missions/[missionId]/attachments

Fichier: app/api/missions/[missionId]/attachments/route.ts

Fonctionnalité: Liste les attachments d'une mission

10. POST /api/missions/[missionId]/attachments

Fichier: app/api/missions/[missionId]/attachments/route.ts

Fonctionnalité: Ajoute un attachment à une mission existante

11. DELETE /api/missions/[missionId]/attachments/[attachmentId]

Fichier: app/api/missions/[missionId]/attachments/[attachmentId]/route.ts

Fonctionnalité: Supprime un attachment


🗄️ Base de Données

Modèle Mission (prisma/schema.prisma)

model Mission {
  id                String        @id @default(uuid())
  name              String
  logo              String?       // Path dans Minio
  oddScope          String[]      // Catégories ODD
  niveau            String        // A/B/C/S
  intention         String        // Description
  missionType       String        // remote/onsite/hybrid
  donneurDOrdre     String        // individual/group/organization
  projection        String        // short/medium/long
  services          String[]      // ["Gite", "ArtLab", "Calcul"]
  participation     String?       // volontaire/cooptation
  profils           String[]      // ["DataIntelligence", ...]
  createdAt         DateTime      @default(now())
  updatedAt         DateTime      @updatedAt
  creator           User          @relation(fields: [creatorId], references: [id])
  creatorId         String
  attachments       Attachment[]
  missionUsers      MissionUser[]

  // Intégrations externes
  leantimeProjectId     String?
  outlineCollectionId   String?
  rocketChatChannelId   String?
  giteaRepositoryUrl    String?
  penpotProjectId       String?

  @@index([creatorId])
}

Modèle MissionUser

model MissionUser {
  id          String   @id @default(uuid())
  role        String   // 'gardien-temps', 'gardien-parole', 'gardien-memoire', 'volontaire'
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  mission     Mission  @relation(fields: [missionId], references: [id])
  missionId   String
  user        User     @relation(fields: [userId], references: [id])
  userId      String

  @@unique([missionId, userId, role])
  @@index([missionId])
  @@index([userId])
}

Modèle Attachment

model Attachment {
  id          String   @id @default(uuid())
  filename    String
  filePath    String   // Path dans Minio: missions/{missionId}/attachments/{filename}
  fileType    String   // MIME type
  fileSize    Int
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
  mission     Mission  @relation(fields: [missionId], references: [id])
  missionId   String
  uploader    User     @relation(fields: [uploaderId], references: [id])
  uploaderId  String

  @@index([missionId])
  @@index([uploaderId])
}

🔗 Intégrations Externes

Service N8N (lib/services/n8n-service.ts)

Webhook URL: https://brain.slm-lab.net/webhook/mission-created

Données envoyées:

{
  name, oddScope, niveau, intention, missionType,
  donneurDOrdre, projection, services, participation,
  profils, guardians, volunteers, creatorId,
  config: {
    N8N_API_KEY,
    MISSION_API_URL
  }
}

Workflow N8N déclenche:

  1. Création projet Leantime (si applicable)
  2. Création collection Outline (si applicable)
  3. Création canal RocketChat (si applicable)
  4. Création repository Gitea (si applicable)
  5. Création projet Penpot (si applicable)

Retour:

{
  success: boolean;
  results?: {
    leantimeProjectId?: string;
    outlineCollectionId?: string;
    rocketChatChannelId?: string;
    giteaRepositoryUrl?: string;
    penpotProjectId?: string;
    failedServices?: {
      gitRepo?: boolean;
      leantimeProject?: boolean;
      docCollection?: boolean;
      rocketChatChannel?: boolean;
    }
  };
  error?: string;
}

Rollback (non implémenté):

  • Webhook: https://brain.slm-lab.net/webhook/mission-rollback
  • Appelé lors de la suppression d'une mission

📦 Stockage de Fichiers

Minio Configuration

Endpoint: https://dome-api.slm-lab.net Bucket: missions Credentials: Hardcodés dans lib/mission-uploads.ts (⚠️ à sécuriser)

Structure des Chemins

Logo:

missions/{missionId}/logo{extension}
Exemple: missions/abc-123/logo.png

Attachments:

missions/{missionId}/attachments/{filename}
Exemple: missions/abc-123/attachments/document.pdf

URLs Publiques

Format: /api/missions/image/{path}

Exemples:

  • Logo: /api/missions/image/missions/{missionId}/logo.png
  • Attachment: /api/missions/image/missions/{missionId}/attachments/document.pdf

Fonctions Utilitaires (lib/mission-uploads.ts)

  • getMissionLogoPath() - Génère le chemin du logo
  • getMissionAttachmentPath() - Génère le chemin d'un attachment
  • uploadMissionLogo() - Upload un logo vers Minio
  • uploadMissionAttachment() - Upload un attachment vers Minio
  • deleteMissionLogo() - Supprime un logo (TODO)
  • deleteMissionAttachment() - Supprime un attachment
  • getMissionFileUrl() - Construit l'URL publique
  • ensureMissionsPrefix() - Normalise le chemin

🧩 Composants Réutilisables

1. MissionsAdminPanel (components/missions/missions-admin-panel.tsx)

Fonctionnalités:

  • Formulaire multi-onglets
  • Gestion des gardiens et volontaires
  • Upload de fichiers
  • Validation complète
  • Soumission vers API

Props: Aucune (composant autonome)

State:

  • missionData - Données de la mission
  • selectedServices - Services sélectionnés
  • selectedProfils - Profils sélectionnés
  • gardienDuTemps, gardienDeLaParole, gardienDeLaMemoire - IDs des gardiens
  • volontaires - Array d'IDs de volontaires
  • activeTab - Onglet actif
  • isSubmitting - État de soumission

2. FileUpload (components/missions/file-upload.tsx)

Fonctionnalités:

  • Upload de logo ou attachment
  • Conversion en base64
  • Preview pour les images

Props:

  • type: 'logo' | 'attachment'
  • isNewMission: boolean
  • onFileSelect: (fileData) => void

3. AttachmentsList (components/missions/attachments-list.tsx)

Fonctionnalités:

  • Liste des attachments d'une mission
  • Upload de nouveaux attachments
  • Suppression d'attachments

Props:

  • missionId: string
  • allowUpload: boolean
  • allowDelete: boolean

4. MissionsFrame (components/missions/missions-frame.tsx)

Fonctionnalités: Wrapper iframe (non utilisé actuellement)


🔐 Contrôles d'Accès

Page Centrale (/missions)

  • Rôles requis: entrepreneurship ou admin
  • Vérifié dans components/main-nav.tsx via hasRole()

API Routes

  • Authentification: Session NextAuth requise
  • GET /api/missions: Missions où user est créateur ou membre
  • GET /api/missions/all: Toutes les missions (authentifié)
  • GET /api/missions/[id]: Créateur ou membre
  • PUT /api/missions/[id]: Créateur ou gardien-temps/gardien-parole
  • DELETE /api/missions/[id]: Créateur ou admin uniquement

📊 Flux de Données Complet

Création de Mission

[Frontend]
  MissionsAdminPanel
    ↓ (soumission)
  POST /api/missions
    ↓
[Backend]
  1. Validation
  2. prisma.mission.create()
  3. prisma.missionUser.createMany()
  4. uploadMissionLogo() → Minio
  5. uploadMissionAttachment() → Minio (pour chaque attachment)
  6. prisma.attachment.create() (pour chaque attachment)
  7. verifyFileExists() (vérification Minio)
  8. n8nService.triggerMissionCreation()
    ↓
[N8N Workflow]
  - Création Leantime
  - Création Outline
  - Création RocketChat
  - Création Gitea
  - Création Penpot
    ↓
[Backend]
  9. Retour succès/erreur
    ↓
[Frontend]
  Redirection → /missions

Consultation de Mission

[Frontend]
  MissionsPage ou MissionDetailPage
    ↓
  fetch('/api/missions') ou fetch('/api/missions/[id]')
    ↓
[Backend]
  1. Vérification session
  2. Query Prisma avec relations
  3. Transformation des paths en URLs publiques
  4. Retour JSON
    ↓
[Frontend]
  Affichage des données

Affichage d'Image

[Frontend]
  <img src="/api/missions/image/missions/{id}/logo.png" />
    ↓
[Backend]
  GET /api/missions/image/[...path]
    ↓
  Lecture depuis Minio
    ↓
  Stream vers client

🎨 Styles et UI

Couleurs des Badges Niveau

  • A (Apprentissage): bg-green-100 text-green-800
  • B (Basique): bg-blue-100 text-blue-800
  • C (Complexe): bg-purple-100 text-purple-800
  • S (Spécial): bg-amber-100 text-amber-800

Layout Sidebar CAP

  • Fond: bg-pink-50
  • Bordure: border-pink-100
  • Largeur: 234px fixe

Grille de Missions

  • Mobile: 1 colonne
  • Tablet: 2 colonnes (md:grid-cols-2)
  • Desktop: 3 colonnes (lg:grid-cols-3)

🐛 Points d'Attention

  1. Credentials Minio hardcodés dans lib/mission-uploads.ts - À déplacer vers variables d'environnement
  2. Rollback N8N non implémenté lors de la suppression
  3. Skills tab non fonctionnel - Placeholders uniquement
  4. Presigned URLs non implémentées - Upload direct uniquement
  5. Gestion d'erreurs N8N - Partielle (continue même si certaines intégrations échouent)

📝 Notes Techniques

Types TypeScript

Mission Interface (utilisée dans les pages):

interface Mission {
  id: string;
  name: string;
  logo?: string;
  logoUrl?: string;
  oddScope: string[];
  niveau: string;
  missionType: string;
  projection: string;
  participation?: string;
  services?: string[];
  profils?: string[];
  intention?: string;
  donneurDOrdre?: string;
  createdAt: string;
  creator: User;
  missionUsers: MissionUser[];
  attachments?: Attachment[];
}

Validation

Côté Frontend: Validation dans MissionsAdminPanel.validateMission() Côté Backend: Validation minimale (name et oddScope requis)

Gestion d'Erreurs

  • Frontend: Toast notifications via useToast()
  • Backend: Retour JSON avec error et details
  • N8N: Retour avec success et failedServices pour erreurs partielles

🔄 Évolutions Possibles

  1. Pagination côté client pour les listes
  2. Filtres avancés (par niveau, type, ODD, etc.)
  3. Recherche full-text dans l'intention
  4. Export des missions (PDF, CSV)
  5. Notifications lors de l'assignation à une mission
  6. Statistiques des missions
  7. Timeline des activités d'une mission
  8. Commentaires sur les missions
  9. États des missions (brouillon, publiée, terminée, etc.)
  10. Permissions granulaires par rôle de gardien

Document généré le: $(date) Version: 1.0 Auteur: Analyse automatique du codebase