Aller au contenu

Service Handlers Telegram

Les Service Handlers sont une famille de 4 sub-workflows N8N appelés par l’Orchestrateur Telegram une fois qu’une intention utilisateur a été détectée. Chacun encapsule un domaine fonctionnel (chat général, Odoo, Docker, administration N8N) et expose une interface stable à l’Orchestrateur : on lui passe {service, action, params, chatId, userId, isAdmin}, il retourne {chatId, text, parseMode, keyboard} prêt à être envoyé à Telegram.

WorkflowIDNodesRôle
Service Handler - GeneraleCayuEQg4e8OhW6z10Aide (help) + chat libre avec Claude (chat)
Service Handler - OdooQFvNDnHjV6MIBB7n33Contacts, factures, devis, opportunités, projets, taches, dashboard
Service Handler - DockerlBrSuWWM2WpN1v9I5Dispatcher vers Docker Actions + formatage Telegram
Service Handler - N8N (parent)lwY2qomOWjrx0EP86Gate admin + délégation au sub-workflow
SH N8N Action Executor (sub)HpILpcfY8Z6OJq9b37Workflows, executions, datatables, triggers (extrait via #279)

Sub-workflows métier

Service Handlers

general

odoo / projet

docker

n8n

Telegram Trigger

Orchestrateur Telegram

IA Router · détection d'intent

Route by Service

SH General · 10n

SH Odoo · 33n

SH Docker · 5n

SH N8N · 6n

CLI Ollama · /api/generate

13 nodes Odoo natifs

Docker Actions

SH N8N Action Executor · 37n

Send Telegram Message


ProblèmeSans handlers dédiésAvec Service Handlers
Couplage Orchestrateur/métierL’Orchestrateur grossit à chaque action ajoutéeLe routage reste ~5 outputs ; le métier vit ailleurs
Permissions disperséesCheck isAdmin répété partoutGate centralisée dans chaque handler sensible
Tests cassantsTester Odoo nécessite de simuler tout le pipeline TelegramSub-workflow appelable isolément avec un payload
ÉvolutivitéAjouter /projet ou des actions N8N gonfle un workflow déjà critiqueLe handler concerné absorbe la croissance

Le Service Handler - N8N faisait initialement 40 nodes : gate admin + 15 actions (list_workflows, toggle, executions, datatables, triggers…). Trois symptômes ont déclenché le refactoring vers un parent fin + sub-workflow lourd :

SymptômeCause
Re-tests complets à chaque ajoutModifier une action obligeait à retester le gate admin
Pagination + callback partoutLa logique pagination était dupliquée entre listes
Lecture difficile40 nodes dans un même canvas masquait le Switch d’actions

Le découpage produit 6 nodes en parent (Trigger → Check Admin → Is Admin? → Restore Input → Execute Sub → Return) et 37 nodes dans SH N8N Action Executor qui orchestre les 15 actions N8N.

L’ajout des commandes /projet a porté SH Odoo de 27 à 33 nodes : 3 nouveaux Switch outputs (list_projects, create_project, project_status), 5 nodes Odoo natifs supplémentaires, et un Code node d’agrégation pour le dashboard projet. C’est la limite haute supportable avant un découpage analogue à #279 ; cf. section “Et si ?”.

Tous les handlers respectent les mêmes invariants :

InvariantImplémentation
Trigger uniqueExecute Workflow Trigger avec inputSource: passthrough
Send TypingIndicateur d’activité Telegram pendant l’attente
Format ResponseSortie standard {chatId, text, parseMode, keyboard.pattern}
Long messageSplit / pagination si > 4096 caractères
onError: continueRegularOutputSur les nodes externes (Odoo, HTTP) pour formatter les erreurs proprement

WorkflowIDNodesRôle
Service Handler - GeneraleCayuEQg4e8OhW6z10Help statique + chat Claude via CLI Ollama
Service Handler - OdooQFvNDnHjV6MIBB7n3313 actions Odoo (contacts, factures, projets, dashboard)
Service Handler - DockerlBrSuWWM2WpN1v9I5Dispatch vers Docker Actions + keyboards contextuels
Service Handler - N8NlwY2qomOWjrx0EP86Gate admin + appel sub-workflow
SH N8N Action ExecutorHpILpcfY8Z6OJq9b37Exécution réelle des actions N8N (extrait #279)

SH N8N · 6n

Check Admin · DT GET

Is Admin?

Restore Input Data

Call SH N8N Action Executor · 37n

SH Docker · 5n

Parse Docker Params

Call Docker Actions

Format Response · keyboard pattern

SH Odoo · 33n

Check Admin

Route by Action · 13 outputs

3x Search Contact + Merge + Dedup

IF Invoice Status

Switch Period · week/month/all

3 Odoo queries + Aggregate

Format Response

SH General · 10n

Send Typing

Route by Action

Generate Help Msg

Call Claude /api/generate

Format Response

Execute Workflow Trigger

service · action · params · chatId · isAdmin

Les actions Odoo et N8N sont sensibles (mutation de données, exécution de workflows). Les deux handlers interrogent la même Data Table Telegram Authorized users (invf2IKyVDyzoBZr) et coupent net en cas d’absence du flag.

ÉtapeComportement
Lookup Telegram Authorized users par telegram_user_idRécupère la ligne utilisateur
is_admin absent ou falseSortie immédiate avec ⛔ Accès réservé aux administrateurs.
is_admin === trueContinue le flux métier
Réponse non-adminparseMode: HTML, keyboard.pattern: no_keyboard

Deux actions : help (réponse statique HTML), et chat (fallback, appel CLI Ollama /api/generate avec model: codex-yolo, session_id généré). Le body de l’appel est sérialisé via JSON.stringify pour échapper guillemets et retours ligne — sans quoi un texte issu de Gemini Vision OCR avec citations cassait le payload (correctif d80e5ce).

Le handler implémente 13 actions via un Switch à 13 outputs + fallback :

ActionModèle OdooParticularité
search_contactres.partner3 recherches parallèles (name / email / phone) + Merge + Dedup
create_contact / update_contactres.partnerUpdate via Custom Resource avec champ dynamique
search_invoiceaccount.moveIF conditionnel sur payment_state
search_quote / search_opportunitysale.order / crm.leadFiltres simples
create_opportunitycrm.leadChamps : name, email, phone, revenue, probability
project_hoursaccount.analytic.lineSwitch Period (week / month / all)
search_project / search_taskproject.project / project.taskCustom Resource + filtre name like
list_projectsproject.projectTous les projets actifs (limit 15)
create_projectproject.projectVia /projet create <nom>
project_status3 modèlesChaîne : Get Project → Tasks → Timesheets → Aggregate Code

Tous les nodes Odoo utilisent le credential Odoo tool admin (xQmHuksl8E7nuwCV), onError: continueRegularOutput, et alwaysOutputData: true (top-level) pour que Format Response s’exécute même sans résultat.

Le handler reste mince car le travail réel est délégué à Docker Actions (SSH vers le VPS, exécution de docker compose). Le node Parse Docker Params traduit l’intent IA Router en paire (dockerAction, dockerStack) :

  • Passthrough si l’action est déjà valide (status, restart, logs, update, start, stop, list-all).
  • Sinon mapping via ACTION_MAP (container_statusstatus, restart_containerrestart…).
  • Mapping container → stack via CONTAINER_TO_STACK (n8nn8n-stack, caddysecurity-stack…).
  • Erreur explicite si action inconnue (au lieu d’un fallback silencieux sur status).

Format Response produit keyboard.pattern parmi standard / critical / list-all / after-action. L’Orchestrateur applique ensuite le bon Switch côté envoi (cf. règle « Reply Markup non expressionable »).

PatternUsageBoutons
standardStack non-critique après status/logsStatus · Restart · Logs · Update · Retour
criticalsecurity-stack (restart/stop/start/update bloqués)Status · Logs · Retour
list-allVue tous containersStatus… · Restart… · Logs… · Retour
after-actionAprès restart/updateStatus · Logs · Restart · Retour

Service Handler - N8N · 6 nodes + sub-workflow 37 nodes

Section intitulée « Service Handler - N8N · 6 nodes + sub-workflow 37 nodes »

Le parent ne fait que (1) gate admin via Data Table, (2) restore input, (3) déléguer à SH N8N Action Executor via Execute Workflow. Le sub-workflow expose 15 actions :

FamilleActions
Workflowslist_workflows (paginé), toggle_workflow
Executionslist_running, list_executions (filtres status), view_execution, retry_execution
Data Tableslist_datatables, view_datatable (paginé), view_row, edit_row, delete_row
Triggers manuelslist_triggers, list_trigger_cat, confirm_trigger, execute_trigger

Les IDs longs (>64 octets pour les callbacks Telegram) sont stockés dans la Data Table n8n_pending_actions avec un short ID 8 chars et un TTL de 5 minutes. Les workflows déclenchables manuellement sont déclarés dans n8n_trigger_whitelist (catégories backup / sync / cleanup / maintenance).

Telegram impose 4096 caractères par message. Trois patterns coexistent :

PatternQuand l’utiliser
TroncatureListes simples, dernier message contient … N résultats
PaginationListes longues type executions ou data tables — boutons ◀️ N/M ▶️
Multi-messageDétails d’exécution avec stack trace — multiMessage: true, keyboard sur le dernier seulement
Data TableIDUtilisée par
Telegram Authorized usersinvf2IKyVDyzoBZrSH Odoo, SH N8N (gate admin)
n8n_trigger_whitelistSH N8N Action Executor (triggers manuels)
n8n_pending_actionsSH N8N Action Executor (short ID ↔ payload)
n8n_datatable_metadataSH N8N Action Executor (tables exposées)

Entrée (depuis l’Orchestrateur) :

{
"service": "odoo",
"action": "search_contact",
"params": { "query": "Dupont" },
"chatId": 123456789,
"userId": 123456789,
"isAdmin": true,
"originalText": "Cherche le contact Dupont"
}

Sortie (vers l’Orchestrateur) :

{
"chatId": 123456789,
"text": "📇 <b>Contacts</b> (2 résultats)...",
"parseMode": "HTML",
"keyboard": { "pattern": "odoo_contacts" }
}

L’Orchestrateur ne lit que text, parseMode, et keyboard.pattern pour router vers le bon node Telegram (la structure du Reply Markup est hardcodée par pattern dans l’UI — N8N ne supporte pas les expressions sur la structure du keyboard, seulement sur les valeurs des boutons).


LimiteImpactMitigation
SH Odoo à 33 nodesLecture du canvas devient pénibleDécoupage prévu (par famille d’actions) sur le modèle de #279
SH General sans mémoireLe chat libre n’a pas d’historique multi-toursConversation Agent dédié pour les conversations multi-turn
SH Docker dépend de SSHToute panne SSH bloque toutes les actions DockerDocker Actions retourne success/error, le handler formate l’erreur
Gate admin = column lookupPas de RBAC fin (juste admin / non-admin)Suffisant pour usage solo, à élargir si multi-utilisateurs
Reply Markup non expressionableChaque pattern nécessite un node Telegram dédiéPattern Switch + keyboards hardcodés (cf. doc telegram orchestrator)

Si SH Odoo dépasse 40 nodes :

  • Découper par famille (SH Odoo Contacts, SH Odoo Projects, SH Odoo Sales) sur le modèle #279
  • Garder le parent comme dispatcher de gate admin + Switch initial
  • Bénéfice : tests indépendants, ajout d’actions sans toucher au reste

Si besoin de permissions plus fines :

  • Ajouter des colonnes à Telegram Authorized users (can_docker, can_odoo, can_n8n)
  • Remplacer le check binaire is_admin par un check capability-based dans chaque handler
  • Garder la rétrocompatibilité : is_admin = true implique toutes les capacités

Si volume de chat Claude augmente :

  • SH General reste single-turn (utilité limitée pour conversation continue)
  • Router proactivement vers Conversation Agent au-delà de N messages dans la même fenêtre
  • Cache de session côté CLI Ollama via Redis (déjà en place)

Si nouveau domaine (ex. monitoring direct) :

  • Créer Service Handler - Monitoring (Prometheus queries, Grafana dashboards)
  • Ajouter un output monitoring dans Route by Service de l’Orchestrateur
  • L’IA Router apprend la nouvelle catégorie via examples dans son prompt