17 KiB
Mapping Complet N8N - Création et Suppression de Mission
📋 Vue d'Ensemble
Ce document décrit le mapping complet entre notre API et les workflows N8N pour la création et la suppression de missions, basé sur les workflows réels partagés.
🔄 Workflow de Création - NeahMissionCreate
Structure du Workflow
Webhook (mission-created)
↓
Process Mission Data
↓
Get Keycloak Token
↓
Process Token
↓
Debug Service Data
↓
Merge Paths
↓
IF Run Integrations
├─ IF Needs Git Repository
│ ├─ Create Git Repository (si Gite ou Calcul)
│ ├─ Create Readme
│ └─ Git Wiki
├─ Create Documentation Collection
├─ Create Leantime Project
│ └─ Leantime Avatar
└─ Create RocketChat Channel
↓
Combine Results
↓
Save Mission To API (POST /mission-created)
↓
Process Results
↓
Respond To Webhook
Données Envoyées par Notre API → N8N
Endpoint : POST https://brain.slm-lab.net/webhook/mission-created
Format :
{
name: string,
oddScope: string[],
niveau: string,
intention: string,
missionType: string,
donneurDOrdre: string,
projection: string,
services: string[],
participation: string,
profils: string[],
guardians: {
"gardien-temps": userId,
"gardien-parole": userId,
"gardien-memoire": userId
},
volunteers: string[],
creatorId: string,
logo: {
data: "data:image/png;base64,...",
name: string,
type: string
},
attachments: Array<{
data: "data:...;base64,...",
name: string,
type: string
}>,
config: {
N8N_API_KEY: string,
MISSION_API_URL: string
}
}
Traitement N8N - Process Mission Data
Le node "Process Mission Data" transforme les données en :
{
missionOriginal: { ... }, // Données originales
missionProcessed: {
name: "Mission Example",
sanitizedName: "mission-example", // Nom nettoyé pour URLs
intention: "...",
description: "...",
startDate: "2024-01-01",
endDate: "2024-01-31",
missionType: "remote",
guardians: { ... },
volunteers: [ ... ],
profils: [ ... ],
services: ["Gite", "ArtLab"], // Détermine quelles intégrations créer
clientId: 2,
rocketChatUsernames: [userId1, userId2, ...], // Gardiens + volontaires
logo: { data: "...", name: "...", type: "..." },
attachments: [ ... ]
},
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",
// ... autres configs
},
creatorId: "user-id"
}
Intégrations Créées par N8N
1. Gitea Repository (Conditionnel)
Condition : services.includes('Gite') || services.includes('Calcul')
Node : "Create Git Repository"
- Méthode : POST
- URL :
{{ GITEA_API_URL }}/user/repos - Body :
{ "name": "{{ sanitizedName }}", "private": true, "auto_init": true, "avatar_url": "{{ logo.data }}" } - Résultat :
{ html_url: "https://gite.slm-lab.net/alma/mission-example" }
Actions supplémentaires :
- Create Readme : Crée un document README dans Outline
- Git Wiki : Configure le wiki externe du repo vers Outline
2. Leantime Project
Node : "Create Leantime Project"
- Méthode : POST
- URL :
{{ LEANTIME_API_URL }}/api/jsonrpc - Body :
{ "method": "leantime.rpc.Projects.Projects.addProject", "jsonrpc": "2.0", "id": 1, "params": { "values": { "name": "{{ name }}", "clientId": {{ clientId }}, "details": "{{ intention }}", "type": "project", "start": "{{ startDate }}", "end": "{{ endDate }}", "status": "open", "psettings": "restricted", "avatar": "{{ logo.data }}" } } } - Résultat :
{ result: [projectId] }(array avec 1 élément)
Action supplémentaire :
- Leantime Avatar : Met à jour l'avatar du projet
3. Outline Collection
Node : "Create Documentation Collection"
- Méthode : POST
- URL :
{{ OUTLINE_API_URL }}/api/collections.create - Body :
{ "name": "{{ sanitizedName }}", "description": "{{ description }}", "permission": "read", "private": true } - Résultat :
{ data: { id: "collection-id", url: "/collection/..." } }
4. RocketChat Channel
Node : "Create RocketChat Channel"
- Méthode : POST
- URL :
{{ ROCKETCHAT_API_URL }}/api/v1/channels.create - Body :
{ "name": "{{ sanitizedName }}", "members": [{{ rocketChatUsernames }}], "readOnly": false, "avatarUrl": "{{ logo.data }}" } - Résultat :
{ channel: { _id: "channel-id", ... } }
Save Mission To API - Retour vers Notre API
Node : "Save Mission To API"
- Méthode : POST
- URL :
{{ MISSION_API_URL }}/mission-created - Headers :
Content-Type: application/jsonAuthorization: Bearer {{ Keycloak Token }}x-api-key: {{ N8N_API_KEY }}
- Body :
{ "name": "{{ name }}", "niveau": "{{ niveau }}", "intention": "{{ intention }}", "description": "{{ description }}", "gitRepoUrl": "{{ gitRepo.html_url }}", "leantimeProjectId": "{{ leantimeProject.result[0] }}", "documentationCollectionId": "{{ docCollection.data.id }}", "rocketchatChannelId": "{{ rocketChatChannel.channel._id }}", "donneurDOrdre": "{{ donneurDOrdre }}", "projection": "{{ projection }}", "missionType": "{{ missionType }}", "creatorId": "{{ creatorId }}" }
⚠️ IMPORTANT : Cet endpoint /mission-created n'existe PAS actuellement dans notre codebase. Il devrait :
- Recevoir les IDs des intégrations créées
- Mettre à jour la mission en base avec ces IDs
- Mapper les champs :
gitRepoUrl→giteaRepositoryUrldocumentationCollectionId→outlineCollectionIdrocketchatChannelId→rocketChatChannelId
🗑️ Workflow de Suppression - NeahMissionDelete_Pro
Structure du Workflow
Webhook Delete (mission-delete)
↓
Process Delete Data
↓
Get Keycloak Token
↓
[En parallèle]
├─ Delete Gitea Repo
├─ Close Leantime Project
├─ Delete Outline Collection
└─ Close RocketChat Channel
↓
Combine Results
↓
Save Deletion To API (POST /mission-deleted)
Données Envoyées par Notre API → N8N
Endpoint : POST https://brain.slm-lab.net/webhook-test/mission-delete
Format :
{
missionId: string,
name: string,
repoName: string, // ✅ Extrait de giteaRepositoryUrl
leantimeProjectId: number | 0, // ✅ Converti en number
documentationCollectionId: string, // ✅ Mappé depuis outlineCollectionId
rocketchatChannelId: string, // ✅ Mappé depuis rocketChatChannelId
// Champs originaux 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
}
}
Traitement N8N - Process Delete Data
Le node "Process Delete Data" transforme les données en :
{
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: "..."
}
}
Actions de Suppression N8N
1. Delete Gitea Repo
Node : "Delete Gitea Repo"
- Méthode : DELETE
- URL :
{{ GITEA_API_URL }}/repos/{{ GITEA_OWNER }}/{{ repoName }} - Headers :
Authorization: token {{ GITEA_API_TOKEN }} - ContinueOnFail :
true - Résultat attendu : Status 204 = succès
2. Close Leantime Project
Node : "Close Leantime Project"
- Méthode : POST
- URL :
{{ LEANTIME_API_URL }}/api/jsonrpc - Body :
{ "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. Delete Outline Collection
Node : "Delete Outline Collection"
- Méthode : POST
- URL :
{{ OUTLINE_API_URL }}/api/collections.delete - Body :
{ "id": "{{ collectionId }}" } - ContinueOnFail :
true - Résultat attendu : Status 200 = succès
4. Close RocketChat Channel
Node : "Close RocketChat Channel"
- Méthode : POST
- URL :
{{ ROCKETCHAT_API_URL }}/api/v1/channels.close - Body :
{ "roomId": "{{ rocketChatRoomId }}" } - ContinueOnFail :
true - Note : Le canal est fermé, pas supprimé
Combine Results
Le node "Combine Results" combine les résultats :
{
status: "deleted",
timestamp: "2024-01-01T12:00:00.000Z",
details: {
gitea: true || "already_deleted",
leantime: true || false,
outline: true || false,
rocketchat: true || false
}
}
Save Deletion To API - Retour vers Notre API
Node : "Save Deletion To API"
- Méthode : POST
- URL :
{{ MISSION_API_URL }}/mission-deleted - Headers :
Authorization: Bearer {{ Keycloak Token }}
- Body :
{ "status": "archived", "results": { "gitea": true, "leantime": true, "outline": true, "rocketchat": true } }
⚠️ IMPORTANT : Cet endpoint /mission-deleted n'existe PAS actuellement dans notre codebase. Il pourrait servir à :
- Confirmer la suppression
- Logger les résultats
- Nettoyer des données supplémentaires si nécessaire
📊 Mapping Complet des Champs
Création (Notre API → N8N → Retour)
| Notre Base | Envoyé à N8N | N8N Crée | Retour N8N | Stocké en Base |
|---|---|---|---|---|
| - | name |
- | name |
name |
| - | services |
Détermine intégrations | - | services |
| - | logo.data |
Avatar/Logo | - | logo (path) |
| - | - | Gitea Repo | gitRepoUrl |
giteaRepositoryUrl |
| - | - | Leantime Project | leantimeProjectId |
leantimeProjectId |
| - | - | Outline Collection | documentationCollectionId |
outlineCollectionId |
| - | - | RocketChat Channel | rocketchatChannelId |
rocketChatChannelId |
Suppression (Notre Base → N8N)
| Notre Base | Extrait/Transformé | Envoyé à N8N | N8N Attend |
|---|---|---|---|
giteaRepositoryUrl |
Extraction nom | repoName |
repoName |
leantimeProjectId |
Converti en number | leantimeProjectId |
leantimeId |
outlineCollectionId |
Direct | documentationCollectionId |
collectionId |
rocketChatChannelId |
Direct | rocketchatChannelId |
rocketChatRoomId |
🔧 Transformations Clés
1. Extraction du Nom du Repository Gitea
Problème : Notre base stocke l'URL complète, N8N attend le nom seul
Solution :
// Format: https://gite.slm-lab.net/alma/mission-example
// ou: https://gite.slm-lab.net/api/v1/repos/alma/mission-example
let repoName = '';
if (giteaRepositoryUrl) {
try {
const url = new URL(giteaRepositoryUrl);
const pathParts = url.pathname.split('/').filter(Boolean);
repoName = pathParts[pathParts.length - 1] || '';
} catch (error) {
const match = giteaRepositoryUrl.match(/\/([^\/]+)\/?$/);
repoName = match ? match[1] : '';
}
}
2. Mapping des Champs
Création :
- N8N retourne
gitRepoUrl→ On stockegiteaRepositoryUrl - N8N retourne
documentationCollectionId→ On stockeoutlineCollectionId - N8N retourne
rocketchatChannelId→ On stockerocketChatChannelId
Suppression :
- On stocke
giteaRepositoryUrl→ On envoierepoName(extrait) - On stocke
outlineCollectionId→ On envoiedocumentationCollectionId - On stocke
rocketChatChannelId→ On envoierocketchatChannelId
3. Conversion de Types
Leantime Project ID :
- Stocké en base :
string | null - Envoyé à N8N :
number | 0(converti) - N8N attend :
number(dansleantimeId)
⚠️ Endpoints Manquants
1. POST /mission-created
Rôle : Recevoir les IDs des intégrations créées par N8N
Format attendu :
POST /mission-created
Headers: {
Authorization: "Bearer {keycloak_token}",
x-api-key: "{N8N_API_KEY}"
}
Body: {
name: string,
niveau: string,
intention: string,
description: string,
gitRepoUrl: string, // À mapper vers giteaRepositoryUrl
leantimeProjectId: string, // À mapper vers leantimeProjectId
documentationCollectionId: string, // À mapper vers outlineCollectionId
rocketchatChannelId: string, // À mapper vers rocketChatChannelId
donneurDOrdre: string,
projection: string,
missionType: string,
creatorId: string
}
Action requise :
- Trouver la mission par
name+creatorId - Mettre à jour avec les IDs retournés
- Mapper les champs correctement
2. POST /mission-deleted
Rôle : Confirmer la suppression (optionnel)
Format attendu :
POST /mission-deleted
Headers: {
Authorization: "Bearer {keycloak_token}"
}
Body: {
status: "archived",
results: {
gitea: boolean,
leantime: boolean,
outline: boolean,
rocketchat: boolean
}
}
Action requise :
- Logger les résultats
- Potentiellement nettoyer des données supplémentaires
🔄 Flow Complet - Vue d'Ensemble
Création
1. Frontend → POST /api/missions
↓
2. Backend crée mission en Prisma
↓
3. Backend upload fichiers Minio
↓
4. Backend → POST N8N webhook (mission-created)
↓
5. N8N crée intégrations (Gitea, Leantime, Outline, RocketChat)
↓
6. N8N → POST /mission-created (⚠️ endpoint manquant)
↓
7. Backend met à jour mission avec IDs (⚠️ non implémenté)
Suppression
1. Frontend → DELETE /api/missions/[id]
↓
2. Backend récupère mission
↓
3. Backend extrait/mappe les données
↓
4. Backend → POST N8N webhook (mission-delete)
↓
5. N8N supprime/ferme intégrations
↓
6. N8N → POST /mission-deleted (⚠️ endpoint manquant)
↓
7. Backend supprime logo Minio
↓
8. Backend supprime attachments Minio
↓
9. Backend supprime mission Prisma (CASCADE)
📝 Notes Importantes
1. Noms de Champs Incohérents
- Création : N8N retourne
gitRepoUrl,documentationCollectionId,rocketchatChannelId - Suppression : N8N attend
repoName,documentationCollectionId,rocketchatChannelId - Notre Base : Stocke
giteaRepositoryUrl,outlineCollectionId,rocketChatChannelId
Solution : Mapping cohérent dans les deux sens
2. Endpoint /mission-created Manquant
Actuellement, les IDs retournés par N8N ne sont PAS sauvegardés en base. Il faudrait :
- Créer l'endpoint
/mission-created - Trouver la mission (par
name+creatorIdoumissionId) - Mettre à jour avec les IDs
3. Services Conditionnels
- Gitea : Créé seulement si
services.includes('Gite') || services.includes('Calcul') - Leantime : Toujours créé
- Outline : Toujours créé
- RocketChat : Toujours créé
4. Gestion d'Erreurs
- Tous les nodes N8N ont
continueOnFail: true - Les erreurs sont loggées mais n'arrêtent pas le workflow
- Les résultats indiquent quelles intégrations ont réussi/échoué
🔍 Points de Debugging
Création
-
Vérifier données envoyées à N8N :
Sending to N8N: { ... } -
Vérifier réponse N8N :
N8N Workflow Result: { success: true, results: {...} } -
Vérifier endpoint /mission-created :
- Doit recevoir les IDs
- Doit mettre à jour la mission
Suppression
-
Vérifier extraction repoName :
Extracted repo name from URL: { url: "...", repoName: "..." } -
Vérifier données envoyées à N8N :
Sending deletion data to N8N: { ... } -
Vérifier réponse N8N :
N8N Deletion Workflow Result: { success: true, results: {...} }
Document généré le : $(date) Version : 1.0 Workflows N8N :
- NeahMissionCreate (création)
- NeahMissionDelete_Pro (suppression)