mission-tab deletemission
This commit is contained in:
parent
9824e54843
commit
aafe4d7035
253
MISSION_INTEGRATION_IDS_ISSUE_FIX.md
Normal file
253
MISSION_INTEGRATION_IDS_ISSUE_FIX.md
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
# Fix: IDs d'Intégration Vides lors de la Suppression
|
||||||
|
|
||||||
|
## 🔍 Problème Identifié
|
||||||
|
|
||||||
|
Lors de la suppression d'une mission, N8N reçoit des IDs vides :
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"missionId": "cd0225cf-8dfd-4bf0-a20a-6aa9c04ebb42",
|
||||||
|
"name": "Creation",
|
||||||
|
"repoName": "",
|
||||||
|
"leantimeProjectId": 0,
|
||||||
|
"documentationCollectionId": "",
|
||||||
|
"rocketchatChannelId": "",
|
||||||
|
"giteaRepositoryUrl": null,
|
||||||
|
"outlineCollectionId": null,
|
||||||
|
"rocketChatChannelId": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause** : Les IDs retournés par N8N lors de la création ne sont **pas sauvegardés en base**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Analyse du Problème
|
||||||
|
|
||||||
|
### Flow Actuel
|
||||||
|
|
||||||
|
```
|
||||||
|
1. POST /api/missions → Crée mission en Prisma
|
||||||
|
2. Upload logo dans Minio
|
||||||
|
3. POST N8N webhook → N8N crée intégrations
|
||||||
|
4. N8N → POST /mission-created (avec IDs)
|
||||||
|
5. ❌ Endpoint cherche mission par name + creatorId (peut échouer)
|
||||||
|
6. ❌ IDs jamais sauvegardés
|
||||||
|
7. ❌ Lors de suppression → IDs vides
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problèmes Identifiés
|
||||||
|
|
||||||
|
1. **Recherche de mission fragile** : L'endpoint `/mission-created` cherche par `name` + `creatorId`, ce qui peut échouer si :
|
||||||
|
- Plusieurs missions ont le même nom
|
||||||
|
- Le nom a changé
|
||||||
|
- Le creatorId ne correspond pas exactement
|
||||||
|
|
||||||
|
2. **missionId non envoyé** : On n'envoie pas le `missionId` à N8N, donc N8N ne peut pas le renvoyer
|
||||||
|
|
||||||
|
3. **N8N ne renvoie peut-être pas missionId** : Même si on l'envoie, N8N doit le renvoyer dans `/mission-created`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Solutions Implémentées
|
||||||
|
|
||||||
|
### 1. Envoyer missionId à N8N
|
||||||
|
|
||||||
|
**Fichier** : `app/api/missions/route.ts`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const n8nData = {
|
||||||
|
...body,
|
||||||
|
missionId: mission.id, // ✅ Send missionId so N8N can return it
|
||||||
|
creatorId: userId,
|
||||||
|
logoPath: logoPath,
|
||||||
|
logoUrl: logoUrl,
|
||||||
|
config: { ... }
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avantage** : N8N peut maintenant renvoyer le `missionId` dans `/mission-created`
|
||||||
|
|
||||||
|
### 2. Améliorer la Recherche de Mission
|
||||||
|
|
||||||
|
**Fichier** : `app/api/missions/mission-created/route.ts`
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Prefer missionId if provided, otherwise use name + creatorId
|
||||||
|
let mission;
|
||||||
|
|
||||||
|
if (body.missionId) {
|
||||||
|
// ✅ Use missionId if provided (more reliable)
|
||||||
|
mission = await prisma.mission.findUnique({
|
||||||
|
where: { id: body.missionId }
|
||||||
|
});
|
||||||
|
} else if (body.name && body.creatorId) {
|
||||||
|
// Fallback to name + creatorId (for backward compatibility)
|
||||||
|
mission = await prisma.mission.findFirst({
|
||||||
|
where: {
|
||||||
|
name: body.name,
|
||||||
|
creatorId: body.creatorId
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'desc' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Avantages** :
|
||||||
|
- ✅ Recherche par `missionId` (plus fiable)
|
||||||
|
- ✅ Fallback vers `name` + `creatorId` (rétrocompatibilité)
|
||||||
|
- ✅ Gestion d'erreurs améliorée
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Format de Requête N8N → /mission-created
|
||||||
|
|
||||||
|
### Format Recommandé (avec missionId)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"missionId": "cd0225cf-8dfd-4bf0-a20a-6aa9c04ebb42",
|
||||||
|
"name": "Creation",
|
||||||
|
"creatorId": "user-id",
|
||||||
|
"gitRepoUrl": "https://gite.slm-lab.net/alma/creation",
|
||||||
|
"leantimeProjectId": "123",
|
||||||
|
"documentationCollectionId": "collection-456",
|
||||||
|
"rocketchatChannelId": "channel-789"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Format de Fallback (sans missionId)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "Creation",
|
||||||
|
"creatorId": "user-id",
|
||||||
|
"gitRepoUrl": "https://gite.slm-lab.net/alma/creation",
|
||||||
|
"leantimeProjectId": "123",
|
||||||
|
"documentationCollectionId": "collection-456",
|
||||||
|
"rocketchatChannelId": "channel-789"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Action Requise dans N8N
|
||||||
|
|
||||||
|
### Modifier le Node "Save Mission To API"
|
||||||
|
|
||||||
|
Le node N8N doit inclure `missionId` dans le body :
|
||||||
|
|
||||||
|
**Avant** :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "{{ name }}",
|
||||||
|
"creatorId": "{{ creatorId }}",
|
||||||
|
"gitRepoUrl": "{{ gitRepo.html_url }}",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Après** :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"missionId": "{{ missionId }}", // ✅ Ajouter missionId
|
||||||
|
"name": "{{ name }}",
|
||||||
|
"creatorId": "{{ creatorId }}",
|
||||||
|
"gitRepoUrl": "{{ gitRepo.html_url }}",
|
||||||
|
"leantimeProjectId": "{{ leantimeProject.result[0] }}",
|
||||||
|
"documentationCollectionId": "{{ docCollection.data.id }}",
|
||||||
|
"rocketchatChannelId": "{{ rocketChatChannel.channel._id }}",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Où trouver missionId dans N8N** :
|
||||||
|
- Il est dans les données initiales : `{{ $node['Process Mission Data'].json.missionId }}`
|
||||||
|
- Ou dans le body original : `{{ $json.missionId }}`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Tests
|
||||||
|
|
||||||
|
### Test 1: Vérifier missionId est envoyé à N8N
|
||||||
|
|
||||||
|
1. Créer une mission
|
||||||
|
2. Vérifier les logs :
|
||||||
|
```
|
||||||
|
Sending to N8N: { missionId: "...", ... }
|
||||||
|
```
|
||||||
|
3. ✅ `missionId` doit être présent
|
||||||
|
|
||||||
|
### Test 2: Vérifier N8N renvoie missionId
|
||||||
|
|
||||||
|
1. Vérifier les logs N8N
|
||||||
|
2. Vérifier que le node "Save Mission To API" inclut `missionId`
|
||||||
|
3. ✅ `missionId` doit être dans le body envoyé à `/mission-created`
|
||||||
|
|
||||||
|
### Test 3: Vérifier IDs sont sauvegardés
|
||||||
|
|
||||||
|
1. Créer une mission
|
||||||
|
2. Vérifier les logs :
|
||||||
|
```
|
||||||
|
=== Mission Created Webhook Received ===
|
||||||
|
Looking up mission by ID: ...
|
||||||
|
Mission updated successfully: { ... }
|
||||||
|
```
|
||||||
|
3. Vérifier en base :
|
||||||
|
```sql
|
||||||
|
SELECT id, name, giteaRepositoryUrl, leantimeProjectId,
|
||||||
|
outlineCollectionId, rocketChatChannelId
|
||||||
|
FROM Mission
|
||||||
|
WHERE id = '...';
|
||||||
|
```
|
||||||
|
4. ✅ Les IDs doivent être présents
|
||||||
|
|
||||||
|
### Test 4: Vérifier Suppression
|
||||||
|
|
||||||
|
1. Supprimer une mission avec IDs sauvegardés
|
||||||
|
2. Vérifier les logs :
|
||||||
|
```
|
||||||
|
Sending deletion data to N8N: {
|
||||||
|
repoName: "creation",
|
||||||
|
leantimeProjectId: 123,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
3. ✅ Les IDs doivent être présents (pas vides)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Checklist
|
||||||
|
|
||||||
|
- [x] Envoyer `missionId` à N8N lors de la création
|
||||||
|
- [x] Améliorer recherche de mission dans `/mission-created`
|
||||||
|
- [ ] **Modifier N8N workflow pour inclure `missionId` dans `/mission-created`**
|
||||||
|
- [ ] Tester création avec `missionId`
|
||||||
|
- [ ] Tester sauvegarde des IDs
|
||||||
|
- [ ] Tester suppression avec IDs sauvegardés
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Action Immédiate Requise
|
||||||
|
|
||||||
|
**Modifier le workflow N8N** pour inclure `missionId` dans le node "Save Mission To API" :
|
||||||
|
|
||||||
|
1. Ouvrir le workflow N8N `NeahMissionCreate`
|
||||||
|
2. Trouver le node "Save Mission To API"
|
||||||
|
3. Ajouter `missionId` dans le body :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"missionId": "={{ $node['Process Mission Data'].json.missionId }}",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
4. Sauvegarder et activer le workflow
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Date**: $(date)
|
||||||
|
**Version**: 1.1
|
||||||
|
**Fichiers Modifiés**:
|
||||||
|
- `app/api/missions/route.ts` (ajout missionId dans n8nData)
|
||||||
|
- `app/api/missions/mission-created/route.ts` (recherche par missionId)
|
||||||
|
|
||||||
@ -53,31 +53,45 @@ export async function POST(request: Request) {
|
|||||||
console.log('Received mission-created data:', JSON.stringify(body, null, 2));
|
console.log('Received mission-created data:', JSON.stringify(body, null, 2));
|
||||||
|
|
||||||
// Validation des champs requis
|
// Validation des champs requis
|
||||||
if (!body.name || !body.creatorId) {
|
// Prefer missionId if provided, otherwise use name + creatorId
|
||||||
|
let mission;
|
||||||
|
|
||||||
|
if (body.missionId) {
|
||||||
|
// ✅ Use missionId if provided (more reliable)
|
||||||
|
console.log('Looking up mission by ID:', body.missionId);
|
||||||
|
mission = await prisma.mission.findUnique({
|
||||||
|
where: { id: body.missionId }
|
||||||
|
});
|
||||||
|
} else if (body.name && body.creatorId) {
|
||||||
|
// Fallback to name + creatorId (for backward compatibility)
|
||||||
|
console.log('Looking up mission by name + creatorId:', {
|
||||||
|
name: body.name,
|
||||||
|
creatorId: body.creatorId
|
||||||
|
});
|
||||||
|
mission = await prisma.mission.findFirst({
|
||||||
|
where: {
|
||||||
|
name: body.name,
|
||||||
|
creatorId: body.creatorId
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: 'desc' // Prendre la plus récente
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
console.error('Missing required fields:', {
|
console.error('Missing required fields:', {
|
||||||
|
hasMissionId: !!body.missionId,
|
||||||
hasName: !!body.name,
|
hasName: !!body.name,
|
||||||
hasCreatorId: !!body.creatorId
|
hasCreatorId: !!body.creatorId
|
||||||
});
|
});
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ error: 'Missing required fields: name and creatorId' },
|
{ error: 'Missing required fields: missionId OR (name and creatorId)' },
|
||||||
{ status: 400 }
|
{ status: 400 }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trouver la mission par name + creatorId
|
|
||||||
// On cherche la mission la plus récente avec ce nom et ce créateur
|
|
||||||
const mission = await prisma.mission.findFirst({
|
|
||||||
where: {
|
|
||||||
name: body.name,
|
|
||||||
creatorId: body.creatorId
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
createdAt: 'desc' // Prendre la plus récente
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!mission) {
|
if (!mission) {
|
||||||
console.error('Mission not found:', {
|
console.error('Mission not found:', {
|
||||||
|
missionId: body.missionId,
|
||||||
name: body.name,
|
name: body.name,
|
||||||
creatorId: body.creatorId
|
creatorId: body.creatorId
|
||||||
});
|
});
|
||||||
|
|||||||
@ -370,8 +370,10 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
const n8nData = {
|
const n8nData = {
|
||||||
...body,
|
...body,
|
||||||
|
missionId: mission.id, // ✅ Send missionId so N8N can return it in /mission-created
|
||||||
creatorId: userId,
|
creatorId: userId,
|
||||||
logoPath: logoPath,
|
logoPath: logoPath,
|
||||||
|
logoUrl: logoUrl, // ✅ Send logo URL for N8N to use
|
||||||
config: {
|
config: {
|
||||||
N8N_API_KEY: process.env.N8N_API_KEY,
|
N8N_API_KEY: process.env.N8N_API_KEY,
|
||||||
MISSION_API_URL: process.env.NEXT_PUBLIC_API_URL
|
MISSION_API_URL: process.env.NEXT_PUBLIC_API_URL
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user