mission-tab deletemission
This commit is contained in:
parent
4141f51550
commit
4543e4fb8a
342
N8N_DELETION_WORKFLOW_MAPPING.md
Normal file
342
N8N_DELETION_WORKFLOW_MAPPING.md
Normal file
@ -0,0 +1,342 @@
|
||||
# Mapping N8N Workflow - Mission Deletion
|
||||
|
||||
## 📋 Vue d'Ensemble
|
||||
|
||||
Ce document décrit le mapping entre les données de notre API et le format attendu par le workflow N8N `NeahMissionDelete_Pro`.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Workflow N8N - Structure
|
||||
|
||||
### Nodes du Workflow
|
||||
|
||||
1. **Webhook Delete** : Reçoit POST sur `/mission-delete`
|
||||
2. **Process Delete Data** : Transforme les données d'entrée
|
||||
3. **Get Keycloak Token** : Obtient un token d'authentification
|
||||
4. **Delete Gitea Repo** : Supprime le repository Gitea (continueOnFail: true)
|
||||
5. **Close Leantime Project** : Ferme le projet Leantime (continueOnFail: true)
|
||||
6. **Delete Outline Collection** : Supprime la collection Outline (continueOnFail: true)
|
||||
7. **Close RocketChat Channel** : Ferme le canal RocketChat (continueOnFail: true)
|
||||
8. **Combine Results** : Combine les résultats de toutes les suppressions
|
||||
9. **Save Deletion To API** : Envoie les résultats à l'API
|
||||
|
||||
---
|
||||
|
||||
## 📊 Mapping des Données
|
||||
|
||||
### Données Envoyées par Notre API
|
||||
|
||||
```typescript
|
||||
{
|
||||
missionId: string,
|
||||
name: string,
|
||||
repoName: string, // Extrait de giteaRepositoryUrl
|
||||
leantimeProjectId: number | null,
|
||||
documentationCollectionId: string, // Mappé depuis outlineCollectionId
|
||||
rocketchatChannelId: string, // Mappé depuis rocketChatChannelId
|
||||
// Champs originaux conservés pour référence
|
||||
giteaRepositoryUrl: string | null,
|
||||
outlineCollectionId: string | null,
|
||||
rocketChatChannelId: string | null,
|
||||
penpotProjectId: string | null,
|
||||
config: {
|
||||
N8N_API_KEY: string,
|
||||
MISSION_API_URL: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Données Attendues par N8N (Process Delete Data)
|
||||
|
||||
Le node "Process Delete Data" transforme les données en :
|
||||
|
||||
```javascript
|
||||
{
|
||||
missionData: {
|
||||
repoName: input.repoName || '',
|
||||
leantimeId: input.leantimeProjectId || 0,
|
||||
collectionId: input.documentationCollectionId || '',
|
||||
rocketChatRoomId: input.rocketchatChannelId || ''
|
||||
},
|
||||
config: {
|
||||
GITEA_API_URL: "https://gite.slm-lab.net/api/v1",
|
||||
GITEA_API_TOKEN: "...",
|
||||
GITEA_OWNER: "alma",
|
||||
LEANTIME_API_URL: "https://agilite.slm-lab.net",
|
||||
LEANTIME_API_TOKEN: "...",
|
||||
ROCKETCHAT_API_URL: "https://parole.slm-lab.net/",
|
||||
ROCKETCHAT_AUTH_TOKEN: "...",
|
||||
ROCKETCHAT_USER_ID: "...",
|
||||
OUTLINE_API_URL: "https://chapitre.slm-lab.net/api",
|
||||
OUTLINE_API_TOKEN: "...",
|
||||
MISSION_API_URL: "https://hub.slm-lab.net",
|
||||
KEYCLOAK_BASE_URL: "https://connect.slm-lab.net",
|
||||
KEYCLOAK_REALM: "cercle",
|
||||
KEYCLOAK_CLIENT_ID: "lab",
|
||||
KEYCLOAK_CLIENT_SECRET: "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Transformations Effectuées
|
||||
|
||||
### 1. Extraction du Nom du Repository Gitea
|
||||
|
||||
**Problème** : Notre base stocke `giteaRepositoryUrl` (URL complète), mais N8N attend `repoName` (nom seul)
|
||||
|
||||
**Solution** : Extraction du nom depuis l'URL
|
||||
|
||||
```typescript
|
||||
// Format possible:
|
||||
// - https://gite.slm-lab.net/alma/repo-name
|
||||
// - https://gite.slm-lab.net/api/v1/repos/alma/repo-name
|
||||
|
||||
let repoName = '';
|
||||
if (mission.giteaRepositoryUrl) {
|
||||
try {
|
||||
const url = new URL(mission.giteaRepositoryUrl);
|
||||
const pathParts = url.pathname.split('/').filter(Boolean);
|
||||
repoName = pathParts[pathParts.length - 1] || '';
|
||||
} catch (error) {
|
||||
// Fallback: extraction regex
|
||||
const match = mission.giteaRepositoryUrl.match(/\/([^\/]+)\/?$/);
|
||||
repoName = match ? match[1] : '';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Exemples** :
|
||||
- `https://gite.slm-lab.net/alma/mission-abc` → `mission-abc`
|
||||
- `https://gite.slm-lab.net/api/v1/repos/alma/mission-xyz` → `mission-xyz`
|
||||
|
||||
### 2. Mapping des Champs
|
||||
|
||||
| Notre Base de Données | N8N Attend | Transformation |
|
||||
|----------------------|------------|----------------|
|
||||
| `giteaRepositoryUrl` | `repoName` | Extraction du nom depuis URL |
|
||||
| `leantimeProjectId` | `leantimeProjectId` | Direct (converti en number) |
|
||||
| `outlineCollectionId` | `documentationCollectionId` | Direct mapping |
|
||||
| `rocketChatChannelId` | `rocketchatChannelId` | Direct mapping (lowercase 'c') |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Actions N8N par Service
|
||||
|
||||
### 1. Gitea Repository
|
||||
|
||||
**Node** : "Delete Gitea Repo"
|
||||
- **Méthode** : DELETE
|
||||
- **URL** : `{{ GITEA_API_URL }}/repos/{{ GITEA_OWNER }}/{{ repoName }}`
|
||||
- **Headers** : `Authorization: token {{ GITEA_API_TOKEN }}`
|
||||
- **ContinueOnFail** : `true` (continue même si échoue)
|
||||
|
||||
**Résultat attendu** : Status 204 (No Content) = succès
|
||||
|
||||
### 2. Leantime Project
|
||||
|
||||
**Node** : "Close Leantime Project"
|
||||
- **Méthode** : POST
|
||||
- **URL** : `{{ LEANTIME_API_URL }}/api/jsonrpc`
|
||||
- **Headers** : `X-API-Key: {{ LEANTIME_API_TOKEN }}`
|
||||
- **Body** :
|
||||
```json
|
||||
{
|
||||
"method": "leantime.rpc.Projects.Projects.patch",
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"id": {{ leantimeId }},
|
||||
"params": { "status": "closed" }
|
||||
}
|
||||
}
|
||||
```
|
||||
- **ContinueOnFail** : `true`
|
||||
|
||||
**Note** : Le projet est **fermé** (status: "closed"), pas supprimé
|
||||
|
||||
### 3. Outline Collection
|
||||
|
||||
**Node** : "Delete Outline Collection"
|
||||
- **Méthode** : POST
|
||||
- **URL** : `{{ OUTLINE_API_URL }}/api/collections.delete`
|
||||
- **Headers** : `Authorization: Bearer {{ OUTLINE_API_TOKEN }}`
|
||||
- **Body** : `{ "id": "{{ collectionId }}" }`
|
||||
- **ContinueOnFail** : `true`
|
||||
|
||||
**Résultat attendu** : Status 200 = succès
|
||||
|
||||
### 4. RocketChat Channel
|
||||
|
||||
**Node** : "Close RocketChat Channel"
|
||||
- **Méthode** : POST
|
||||
- **URL** : `{{ ROCKETCHAT_API_URL }}/api/v1/channels.close`
|
||||
- **Headers** :
|
||||
- `X-Auth-Token: {{ ROCKETCHAT_AUTH_TOKEN }}`
|
||||
- `X-User-Id: {{ ROCKETCHAT_USER_ID }}`
|
||||
- **Body** : `{ "roomId": "{{ rocketChatRoomId }}" }`
|
||||
- **ContinueOnFail** : `true`
|
||||
|
||||
**Note** : Le canal est **fermé**, pas supprimé
|
||||
|
||||
---
|
||||
|
||||
## 📤 Réponse N8N
|
||||
|
||||
### Format de Réponse (Combine Results)
|
||||
|
||||
```javascript
|
||||
{
|
||||
status: "deleted",
|
||||
timestamp: "2024-01-01T12:00:00.000Z",
|
||||
details: {
|
||||
gitea: true || "already_deleted",
|
||||
leantime: true || false,
|
||||
outline: true || false,
|
||||
rocketchat: true || false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Envoi à l'API (Save Deletion To API)
|
||||
|
||||
Le workflow envoie ensuite les résultats à :
|
||||
- **URL** : `{{ MISSION_API_URL }}/mission-deleted`
|
||||
- **Méthode** : POST
|
||||
- **Headers** : `Authorization: Bearer {{ Keycloak Token }}`
|
||||
- **Body** :
|
||||
```json
|
||||
{
|
||||
"status": "archived",
|
||||
"results": {
|
||||
"gitea": true,
|
||||
"leantime": true,
|
||||
"outline": true,
|
||||
"rocketchat": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Points d'Attention
|
||||
|
||||
### 1. Gestion des Erreurs
|
||||
|
||||
- Tous les nodes de suppression ont `continueOnFail: true`
|
||||
- Si une suppression échoue, le workflow continue avec les autres
|
||||
- Les résultats indiquent quelles suppressions ont réussi/échoué
|
||||
|
||||
### 2. Différences de Comportement
|
||||
|
||||
- **Gitea** : Suppression complète du repository
|
||||
- **Leantime** : Fermeture (status: "closed"), pas suppression
|
||||
- **Outline** : Suppression complète de la collection
|
||||
- **RocketChat** : Fermeture du canal, pas suppression
|
||||
|
||||
### 3. Extraction du Repo Name
|
||||
|
||||
- L'extraction doit gérer différents formats d'URL
|
||||
- Si l'extraction échoue, `repoName` sera vide
|
||||
- Le workflow N8N gérera le cas où `repoName` est vide
|
||||
|
||||
### 4. Mapping des Champs
|
||||
|
||||
- **documentationCollectionId** : Mappé depuis `outlineCollectionId`
|
||||
- **rocketchatChannelId** : Mappé depuis `rocketChatChannelId` (attention au 'c' minuscule)
|
||||
- **leantimeProjectId** : Converti en number (0 si null)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Debugging
|
||||
|
||||
### Logs à Surveiller
|
||||
|
||||
1. **Extraction repo name** :
|
||||
```
|
||||
Extracted repo name from URL: { url: "...", repoName: "..." }
|
||||
```
|
||||
|
||||
2. **Données envoyées à N8N** :
|
||||
```
|
||||
Sending deletion data to N8N: { ... }
|
||||
```
|
||||
|
||||
3. **Résultat N8N** :
|
||||
```
|
||||
N8N Deletion Workflow Result: { success: true, results: {...} }
|
||||
```
|
||||
|
||||
### Vérifications
|
||||
|
||||
1. **Repo name extrait correctement** ?
|
||||
- Vérifier les logs d'extraction
|
||||
- Format attendu : nom simple sans URL
|
||||
|
||||
2. **Mapping des champs correct** ?
|
||||
- `documentationCollectionId` = `outlineCollectionId`
|
||||
- `rocketchatChannelId` = `rocketChatChannelId`
|
||||
|
||||
3. **N8N a reçu les données** ?
|
||||
- Vérifier les logs N8N
|
||||
- Vérifier le webhook a été appelé
|
||||
|
||||
---
|
||||
|
||||
## 📝 Exemple Complet
|
||||
|
||||
### Données en Base
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: "abc-123",
|
||||
name: "Mission Example",
|
||||
giteaRepositoryUrl: "https://gite.slm-lab.net/alma/mission-example",
|
||||
leantimeProjectId: "123",
|
||||
outlineCollectionId: "collection-456",
|
||||
rocketChatChannelId: "channel-789"
|
||||
}
|
||||
```
|
||||
|
||||
### Données Envoyées à N8N
|
||||
|
||||
```typescript
|
||||
{
|
||||
missionId: "abc-123",
|
||||
name: "Mission Example",
|
||||
repoName: "mission-example", // Extrait de l'URL
|
||||
leantimeProjectId: 123, // Converti en number
|
||||
documentationCollectionId: "collection-456", // Mappé
|
||||
rocketchatChannelId: "channel-789", // Mappé (lowercase 'c')
|
||||
giteaRepositoryUrl: "https://gite.slm-lab.net/alma/mission-example",
|
||||
outlineCollectionId: "collection-456",
|
||||
rocketChatChannelId: "channel-789",
|
||||
config: {
|
||||
N8N_API_KEY: "...",
|
||||
MISSION_API_URL: "https://hub.slm-lab.net"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Données Traitées par N8N
|
||||
|
||||
```javascript
|
||||
{
|
||||
missionData: {
|
||||
repoName: "mission-example",
|
||||
leantimeId: 123,
|
||||
collectionId: "collection-456",
|
||||
rocketChatRoomId: "channel-789"
|
||||
},
|
||||
config: { ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Document généré le** : $(date)
|
||||
**Version** : 1.0
|
||||
**Workflow N8N** : NeahMissionDelete_Pro
|
||||
**Webhook URL** : https://brain.slm-lab.net/webhook-test/mission-delete
|
||||
|
||||
@ -332,17 +332,41 @@ export async function DELETE(
|
||||
console.log('=== Starting N8N Deletion Workflow ===');
|
||||
const n8nService = new N8nService();
|
||||
|
||||
// Extract repo name from giteaRepositoryUrl if present
|
||||
// Format: https://gite.slm-lab.net/alma/repo-name or https://gite.slm-lab.net/api/v1/repos/alma/repo-name
|
||||
let repoName = '';
|
||||
if (mission.giteaRepositoryUrl) {
|
||||
try {
|
||||
const url = new URL(mission.giteaRepositoryUrl);
|
||||
// Extract repo name from path (last segment)
|
||||
const pathParts = url.pathname.split('/').filter(Boolean);
|
||||
repoName = pathParts[pathParts.length - 1] || '';
|
||||
console.log('Extracted repo name from URL:', { url: mission.giteaRepositoryUrl, repoName });
|
||||
} catch (error) {
|
||||
console.error('Error extracting repo name from URL:', error);
|
||||
// If URL parsing fails, try to extract from the string directly
|
||||
const match = mission.giteaRepositoryUrl.match(/\/([^\/]+)\/?$/);
|
||||
repoName = match ? match[1] : '';
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare data according to N8N workflow expectations
|
||||
// The workflow expects: repoName, leantimeProjectId, documentationCollectionId, rocketchatChannelId
|
||||
const n8nDeletionData = {
|
||||
missionId: mission.id,
|
||||
name: mission.name,
|
||||
leantimeProjectId: mission.leantimeProjectId,
|
||||
repoName: repoName, // N8N expects repoName, not giteaRepositoryUrl
|
||||
leantimeProjectId: mission.leantimeProjectId || 0,
|
||||
documentationCollectionId: mission.outlineCollectionId || '', // N8N expects documentationCollectionId
|
||||
rocketchatChannelId: mission.rocketChatChannelId || '', // N8N expects rocketchatChannelId (lowercase 'c')
|
||||
// Keep original fields for reference
|
||||
giteaRepositoryUrl: mission.giteaRepositoryUrl,
|
||||
outlineCollectionId: mission.outlineCollectionId,
|
||||
rocketChatChannelId: mission.rocketChatChannelId,
|
||||
giteaRepositoryUrl: mission.giteaRepositoryUrl,
|
||||
penpotProjectId: mission.penpotProjectId,
|
||||
config: {
|
||||
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 || 'https://hub.slm-lab.net'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user