343 lines
9.0 KiB
Markdown
343 lines
9.0 KiB
Markdown
# 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
|
|
|