mission-tab
This commit is contained in:
parent
eb71deca88
commit
6cf131921b
162
CAPROVER_NGINX_FIX.md
Normal file
162
CAPROVER_NGINX_FIX.md
Normal file
@ -0,0 +1,162 @@
|
||||
# Fix Nginx CapRover - Erreur "upstream sent too big header"
|
||||
|
||||
## 🔍 Problème
|
||||
|
||||
Erreur 502 avec message Nginx :
|
||||
```
|
||||
upstream sent too big header while reading response header from upstream
|
||||
```
|
||||
|
||||
**Cause** : Le cookie de session NextAuth (JWT avec tokens Keycloak) dépasse 4KB, la limite par défaut de Nginx.
|
||||
|
||||
## ✅ Solution : Modifier la configuration CapRover
|
||||
|
||||
### Option 1 : Via CapRover Dashboard (RECOMMANDÉ)
|
||||
|
||||
1. **Aller dans CapRover Dashboard**
|
||||
2. **Sélectionner votre app** (hub.slm-lab.net)
|
||||
3. **Aller dans "HTTP Settings"**
|
||||
4. **Cliquer sur "Edit Nginx Configuration"** (si disponible)
|
||||
5. **OU aller dans "App Configs" → "nginx"**
|
||||
|
||||
### Option 2 : Modifier le template Nginx directement
|
||||
|
||||
Si vous avez accès au serveur CapRover, modifier le template dans :
|
||||
- `/captain/templates/nginx.conf` (template principal)
|
||||
- OU créer un override dans votre app
|
||||
|
||||
## 📝 Configuration à Ajouter
|
||||
|
||||
**Dans le bloc `location /`**, ajouter ces directives **AVANT** `proxy_pass` :
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
# ============================================
|
||||
# FIX: Augmenter la limite des headers pour NextAuth
|
||||
# ============================================
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Timeouts (pour éviter les timeouts)
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# Configuration proxy existante
|
||||
proxy_pass $upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket support (si activé)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 Configuration Complète Modifiée
|
||||
|
||||
Voici le bloc `location /` complet avec les corrections :
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
# FIX: Headers trop grands pour NextAuth
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# Proxy configuration
|
||||
proxy_pass $upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# WebSocket (si activé)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 Méthode via CapRover Dashboard
|
||||
|
||||
### Si CapRover permet l'édition Nginx :
|
||||
|
||||
1. **Dashboard CapRover** → Votre app
|
||||
2. **"App Configs"** → **"nginx"**
|
||||
3. **Ajouter dans "Custom Nginx Configuration"** :
|
||||
|
||||
```nginx
|
||||
location / {
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
}
|
||||
```
|
||||
|
||||
4. **Sauvegarder** → CapRover regénère la config
|
||||
|
||||
### Si CapRover ne permet pas l'édition :
|
||||
|
||||
**Option A** : Modifier le template CapRover (avancé)
|
||||
- Accéder au serveur CapRover
|
||||
- Modifier `/captain/templates/nginx.conf`
|
||||
- Redémarrer CapRover
|
||||
|
||||
**Option B** : Créer un fichier de configuration personnalisé
|
||||
- Créer un fichier dans votre app
|
||||
- L'inclure dans la config Nginx
|
||||
|
||||
## 🔄 Après Modification
|
||||
|
||||
1. **Vérifier la config Nginx** :
|
||||
```bash
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
2. **Recharger Nginx** :
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
# OU si CapRover gère Nginx
|
||||
docker exec captain-nginx nginx -s reload
|
||||
```
|
||||
|
||||
3. **Tester la connexion** :
|
||||
- Se connecter via Keycloak
|
||||
- Vérifier que l'erreur 502 ne se produit plus
|
||||
|
||||
## 📊 Explication
|
||||
|
||||
**Avant** :
|
||||
- Limite par défaut Nginx : 4KB pour les headers
|
||||
- Cookie NextAuth : ~4-7KB (JWT avec tokens Keycloak)
|
||||
- Résultat : ❌ Erreur 502
|
||||
|
||||
**Après** :
|
||||
- Limite augmentée : 32KB pour les headers
|
||||
- Cookie NextAuth : ~4-7KB
|
||||
- Résultat : ✅ Fonctionne
|
||||
|
||||
## ⚠️ Note Importante
|
||||
|
||||
Si vous modifiez le template CapRover directement, **vos modifications seront écrasées** lors d'une mise à jour de CapRover.
|
||||
|
||||
**Recommandation** : Utiliser la méthode "Custom Nginx Configuration" dans CapRover si disponible, ou documenter vos modifications pour les réappliquer après mise à jour.
|
||||
|
||||
---
|
||||
|
||||
**Document créé le** : $(date)
|
||||
**Priorité** : HAUTE - Résout l'erreur 502
|
||||
|
||||
930
MISSIONS_CENTRALE_WORKFLOW_ANALYSIS.md
Normal file
930
MISSIONS_CENTRALE_WORKFLOW_ANALYSIS.md
Normal file
@ -0,0 +1,930 @@
|
||||
# Analyse Complète : Pages Missions et Centrale - Workflow Complet
|
||||
|
||||
## 📋 Table des Matières
|
||||
1. [Vue d'ensemble](#vue-densemble)
|
||||
2. [Architecture des Pages](#architecture-des-pages)
|
||||
3. [Workflow de Navigation](#workflow-de-navigation)
|
||||
4. [Workflow de Création de Mission](#workflow-de-création-de-mission)
|
||||
5. [Workflow de Consultation](#workflow-de-consultation)
|
||||
6. [API Routes](#api-routes)
|
||||
7. [Base de Données](#base-de-données)
|
||||
8. [Intégrations Externes](#intégrations-externes)
|
||||
9. [Stockage de Fichiers](#stockage-de-fichiers)
|
||||
10. [Composants Réutilisables](#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**:
|
||||
```typescript
|
||||
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**:
|
||||
```typescript
|
||||
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**
|
||||
```typescript
|
||||
prisma.mission.create({
|
||||
data: { name, oddScope, niveau, intention, ... }
|
||||
})
|
||||
```
|
||||
|
||||
2. **Création des MissionUsers (gardiens + volontaires)**
|
||||
```typescript
|
||||
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**
|
||||
```typescript
|
||||
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**:
|
||||
```typescript
|
||||
{
|
||||
OR: [
|
||||
{ creatorId: userId },
|
||||
{ missionUsers: { some: { userId } } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Retour**:
|
||||
```json
|
||||
{
|
||||
"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**:
|
||||
```typescript
|
||||
{
|
||||
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**:
|
||||
```json
|
||||
{
|
||||
"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`)
|
||||
|
||||
```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
|
||||
|
||||
```prisma
|
||||
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
|
||||
|
||||
```prisma
|
||||
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**:
|
||||
```typescript
|
||||
{
|
||||
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**:
|
||||
```typescript
|
||||
{
|
||||
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):
|
||||
```typescript
|
||||
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
|
||||
|
||||
155
NGINX_HEADER_SIZE_FIX.md
Normal file
155
NGINX_HEADER_SIZE_FIX.md
Normal file
@ -0,0 +1,155 @@
|
||||
# Fix Erreur 502 - Headers trop grands (Nginx)
|
||||
|
||||
## 🔍 Problème Identifié
|
||||
|
||||
**Erreur Nginx** :
|
||||
```
|
||||
upstream sent too big header while reading response header from upstream
|
||||
```
|
||||
|
||||
**Cause** : Le cookie de session NextAuth est trop grand (> 4KB par défaut dans Nginx). Le JWT contient :
|
||||
- `accessToken` (Keycloak) - ~1-2KB
|
||||
- `refreshToken` (Keycloak) - ~1-2KB
|
||||
- `idToken` (Keycloak) - ~1-2KB
|
||||
- Données utilisateur (roles, etc.) - ~500B-1KB
|
||||
- **Total** : ~4-7KB, ce qui dépasse la limite Nginx par défaut
|
||||
|
||||
## ✅ Solutions
|
||||
|
||||
### Solution 1 : Augmenter la limite Nginx (RECOMMANDÉ)
|
||||
|
||||
**Fichier** : Configuration Nginx (généralement `/etc/nginx/sites-available/hub.slm-lab.net` ou similaire)
|
||||
|
||||
**Ajouter dans le bloc `server` ou `location`** :
|
||||
```nginx
|
||||
server {
|
||||
# ... autres configs ...
|
||||
|
||||
# Augmenter la taille maximale des headers
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Spécifiquement pour les headers de réponse
|
||||
proxy_headers_hash_max_size 512;
|
||||
proxy_headers_hash_bucket_size 128;
|
||||
|
||||
# ... reste de la config ...
|
||||
}
|
||||
```
|
||||
|
||||
**OU** pour une solution plus simple, ajouter seulement :
|
||||
```nginx
|
||||
server {
|
||||
# ... autres configs ...
|
||||
|
||||
# Augmenter la limite des headers
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# ... reste de la config ...
|
||||
}
|
||||
```
|
||||
|
||||
**Puis redémarrer Nginx** :
|
||||
```bash
|
||||
sudo nginx -t # Vérifier la config
|
||||
sudo systemctl reload nginx # Ou sudo service nginx reload
|
||||
```
|
||||
|
||||
### Solution 2 : Réduire la taille du JWT (ALTERNATIVE)
|
||||
|
||||
Si on ne peut pas modifier Nginx, on peut réduire la taille du JWT en ne stockant pas tous les tokens.
|
||||
|
||||
**Modification** : `app/api/auth/options.ts`
|
||||
|
||||
**Option A** : Ne pas stocker `idToken` dans le JWT (si pas nécessaire)
|
||||
```typescript
|
||||
// Dans JWT callback
|
||||
token.idToken = account.id_token ?? ''; // ❌ Supprimer cette ligne
|
||||
```
|
||||
|
||||
**Option B** : Stocker seulement les tokens nécessaires
|
||||
```typescript
|
||||
// Stocker seulement accessToken et refreshToken
|
||||
// idToken peut être récupéré depuis Keycloak si nécessaire
|
||||
```
|
||||
|
||||
**Note** : Cette solution réduit la fonctionnalité. La Solution 1 est préférable.
|
||||
|
||||
## 🔧 Configuration Nginx Complète Recommandée
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name hub.slm-lab.net;
|
||||
|
||||
# ... SSL config ...
|
||||
|
||||
# Augmenter les limites pour les gros headers NextAuth
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
location / {
|
||||
proxy_pass http://172.16.0.102:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Headers pour NextAuth
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 Vérification
|
||||
|
||||
**Après modification Nginx** :
|
||||
|
||||
1. **Tester la config** :
|
||||
```bash
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
2. **Recharger Nginx** :
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
3. **Tester la connexion** :
|
||||
- Se connecter via Keycloak
|
||||
- Vérifier que l'erreur 502 ne se produit plus
|
||||
- Vérifier les logs Nginx pour confirmer
|
||||
|
||||
## 🎯 Cause Technique
|
||||
|
||||
NextAuth crée un cookie JWT qui contient :
|
||||
- Le JWT encrypté avec `NEXTAUTH_SECRET`
|
||||
- Le JWT contient tous les tokens Keycloak
|
||||
- La taille totale peut dépasser 4KB
|
||||
|
||||
Nginx a une limite par défaut de 4KB pour les headers de réponse. Quand Next.js essaie de renvoyer un cookie > 4KB, Nginx rejette avec "upstream sent too big header".
|
||||
|
||||
## ✅ Solution Immédiate
|
||||
|
||||
**Action** : Modifier la configuration Nginx pour augmenter `large_client_header_buffers` à au moins `4 32k` ou `8 16k`.
|
||||
|
||||
**Impact** : Résout immédiatement l'erreur 502.
|
||||
|
||||
---
|
||||
|
||||
**Document créé le** : $(date)
|
||||
**Priorité** : HAUTE - C'est la cause de l'erreur 502
|
||||
|
||||
@ -85,11 +85,20 @@ export async function GET(request: Request) {
|
||||
// Get total count
|
||||
const totalCount = await prisma.mission.count({ where });
|
||||
|
||||
// Transform logo paths to public URLs
|
||||
const missionsWithPublicUrls = missions.map(mission => ({
|
||||
...mission,
|
||||
logo: mission.logo ? `/api/missions/image/${mission.logo}` : null
|
||||
}));
|
||||
// Transform missions to include public URLs (same format as /api/missions)
|
||||
const missionsWithPublicUrls = missions.map(mission => {
|
||||
console.log('Processing mission logo:', {
|
||||
missionId: mission.id,
|
||||
logo: mission.logo,
|
||||
constructedUrl: mission.logo ? `/api/missions/image/${mission.logo}` : null
|
||||
});
|
||||
|
||||
return {
|
||||
...mission,
|
||||
logoUrl: mission.logo ? `/api/missions/image/${mission.logo}` : null,
|
||||
logo: mission.logo, // Keep original logo path
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
missions: missionsWithPublicUrls,
|
||||
|
||||
136
caprover-nginx-template-fixed.conf
Normal file
136
caprover-nginx-template-fixed.conf
Normal file
@ -0,0 +1,136 @@
|
||||
<%
|
||||
if (s.forceSsl) {
|
||||
%>
|
||||
server {
|
||||
|
||||
listen 80;
|
||||
|
||||
server_name <%-s.publicDomain%>;
|
||||
|
||||
# Used by Lets Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root <%-s.staticWebRoot%>;
|
||||
}
|
||||
|
||||
# Used by CapRover for health check
|
||||
location /.well-known/captain-identifier {
|
||||
root <%-s.staticWebRoot%>;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 302 https://$http_host$request_uri;
|
||||
}
|
||||
}
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
|
||||
server {
|
||||
|
||||
<%
|
||||
if (!s.forceSsl) {
|
||||
%>
|
||||
listen 80;
|
||||
<%
|
||||
}
|
||||
if (s.hasSsl) {
|
||||
%>
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
ssl_certificate <%-s.crtPath%>;
|
||||
ssl_certificate_key <%-s.keyPath%>;
|
||||
<%
|
||||
}
|
||||
if (s.logAccessPath) {
|
||||
%>
|
||||
access_log <%-s.logAccessPath%>;
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
client_max_body_size 500m;
|
||||
|
||||
server_name <%-s.publicDomain%>;
|
||||
|
||||
# 127.0.0.11 is DNS set up by Docker, see:
|
||||
# https://docs.docker.com/engine/userguide/networking/configure-dns/
|
||||
# https://github.com/moby/moby/issues/20026
|
||||
resolver 127.0.0.11 valid=10s;
|
||||
# IMPORTANT!! If you are here from an old thread to set a custom port, you do not need to modify this port manually here!!
|
||||
# Simply change the Container HTTP Port from the dashboard HTTP panel
|
||||
set $upstream http://172.16.0.102:3000;
|
||||
|
||||
location / {
|
||||
|
||||
<%
|
||||
if (s.redirectToPath) {
|
||||
%>
|
||||
return 302 <%-s.redirectToPath%>$request_uri;
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
|
||||
<%
|
||||
if (s.httpBasicAuthPath) {
|
||||
%>
|
||||
auth_basic "Restricted Access";
|
||||
auth_basic_user_file <%-s.httpBasicAuthPath%>;
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
# ============================================
|
||||
# FIX: Augmenter la limite des headers pour NextAuth
|
||||
# Résout l'erreur "upstream sent too big header"
|
||||
# ============================================
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Timeouts pour éviter les timeouts
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
proxy_pass $upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
<%
|
||||
if (s.websocketSupport) {
|
||||
%>
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_http_version 1.1;
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
|
||||
<%
|
||||
}
|
||||
%>
|
||||
|
||||
}
|
||||
|
||||
# Used by Lets Encrypt
|
||||
location /.well-known/acme-challenge/ {
|
||||
root <%-s.staticWebRoot%>;
|
||||
}
|
||||
|
||||
# Used by CapRover for health check
|
||||
location /.well-known/captain-identifier {
|
||||
root <%-s.staticWebRoot%>;
|
||||
}
|
||||
|
||||
error_page 502 /captain_502_custom_error_page.html;
|
||||
location = /captain_502_custom_error_page.html {
|
||||
root <%-s.customErrorPagesDirectory%>;
|
||||
internal;
|
||||
}
|
||||
}
|
||||
|
||||
32
nginx-config-fix.conf
Normal file
32
nginx-config-fix.conf
Normal file
@ -0,0 +1,32 @@
|
||||
# Configuration Nginx pour corriger l'erreur "upstream sent too big header"
|
||||
# À ajouter dans votre configuration Nginx pour hub.slm-lab.net
|
||||
|
||||
server {
|
||||
# ... votre config existante ...
|
||||
|
||||
# ============================================
|
||||
# FIX: Augmenter la limite des headers
|
||||
# ============================================
|
||||
# Ces directives augmentent la taille maximale des headers
|
||||
# pour permettre les gros cookies NextAuth (JWT avec tokens Keycloak)
|
||||
|
||||
# Taille des buffers pour les headers
|
||||
proxy_buffer_size 16k;
|
||||
proxy_buffers 8 16k;
|
||||
proxy_busy_buffers_size 32k;
|
||||
|
||||
# Limite pour les gros headers clients (et réponses)
|
||||
large_client_header_buffers 4 32k;
|
||||
|
||||
# Hash tables pour les headers (optionnel mais recommandé)
|
||||
proxy_headers_hash_max_size 512;
|
||||
proxy_headers_hash_bucket_size 128;
|
||||
|
||||
# Timeouts (pour éviter les timeouts pendant le traitement)
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
|
||||
# ... reste de votre config ...
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user