# backend/api — Moduli Telegram (M2 Split) > **Refactor M2 — 2 Luglio 2026** > Il monolite `telegram_webhook.py` (2844 righe, 5 hotfix consecutivi) è stato > spezzato in 6 moduli a responsabilità singola. Hotfix futuri toccano **un solo file**. --- ## Grafo delle dipendenze ``` telegram_tg_client.py (stdlib + httpx only) │ ├──► telegram_keyboards.py (solo costanti/dict — zero import interni) │ │ │ ├──► telegram_cmd_monitoring.py │ │ └──► (esposto via telegram_webhook.py) │ │ │ ├──► telegram_cmd_ai.py │ │ └──► (esposto via telegram_webhook.py) │ │ │ └──► telegram_callbacks.py │ ├── importa _cmd_do, _cmd_autofix ... da telegram_cmd_ai │ └── importa _cmd_help, _cmd_status ... da telegram_cmd_monitoring │ └──► telegram_webhook.py (router FastAPI puro — importa da tutti) └──► montato in backend/main.py come _tg_webhook_router ``` --- ## Moduli ### `telegram_tg_client.py` — 276 righe **Ruolo:** Telegram Bot API puro. Layer 0 senza dipendenze interne. | Simbolo | Descrizione | |---------|-------------| | `_get_bot_token()` | Legge `TELEGRAM_BOT_TOKEN` dall'env | | `_log_tg_exc(task)` | Log eccezioni fire-and-forget (Gap-2.6) | | `_fmt_elapsed(sec)` | Formatta durata in human-readable | | `_tg_reply(chat_id, text)` | Invia messaggio con parse_mode=HTML | | `_tg_send(chat_id, text)` | Come reply, ritorna `message_id` | | `_tg_edit(chat_id, msg_id, text)` | Modifica messaggio esistente | | `_tg_photo(chat_id, url, caption)` | Invia foto via URL | | `_tg_typing(chat_id)` | Invia `sendChatAction typing` | | `_tg_react(chat_id, msg_id, emoji)` | Imposta reaction emoji | | `_tg_answer_callback(callback_id)` | Risponde a `callback_query` (≤3s) | **Import:** `asyncio, html, logging, os, time, httpx` --- ### `telegram_keyboards.py` — 109 righe **Ruolo:** Costanti UI e keyboards. Zero logica, zero import interni. | Simbolo | Tipo | Descrizione | |---------|------|-------------| | `_QUICK_PICK_KB` | `dict` | Inline keyboard selezione task rapida | | `_MAIN_KB` | `dict` | Reply keyboard principale | | `_BENCH_ACTION_KB` | `dict` | Keyboard post-benchmark | | `_TASK_MENU_KB` | `dict` | Sub-menu task | | `_STATUS_MENU_KB` | `dict` | Sub-menu stato sistema | | `_PERF_MENU_KB` | `dict` | Sub-menu performance | | `_HEALTH_MENU_KB` | `dict` | Sub-menu health | | `_DEV_MENU_KB` | `dict` | Sub-menu developer | | `_LAST_GOAL` | `dict[int,str]` | Memoria per bottone 🔁 Rifai | | `_BENCH_CACHE` | `dict[int,dict]` | Ultimo run benchmark per chat | | `_after_task_kb(chat_id)` | func | Keyboard dinamica post-task | **Import:** solo `from __future__ import annotations` --- ### `telegram_cmd_monitoring.py` — 456 righe **Ruolo:** Comandi di monitoraggio, stato e diagnostica. | Comando / Funzione | Trigger Telegram | |--------------------|-----------------| | `_cmd_help(chat_id)` | `/start` `/help` `tgw_help` | | `_cmd_logs(chat_id)` | `/logs` `tgw_logs` | | `_cmd_status(chat_id)` | `/stato` `tgw_status` | | `_cmd_commit_summary(chat_id)` | `/commit` `tgw_commits` | | `_cmd_check(chat_id)` | `/salute` `tgw_health` | | `_cmd_tasks(chat_id)` | `/attività` `tgw_tasks` | | `_cmd_git(chat_id, args)` | `/git` `tgw_git` | | `_cmd_coord(chat_id)` | `/coord` `tgw_coord` | | `_cmd_scan_now(chat_id)` | `/scan` `tgw_scan` | | `_cmd_telemetry(chat_id)` | `/telemetria` `tgw_telemetry` | **Import:** stdlib + `telegram_tg_client` + `telegram_keyboards` --- ### `telegram_cmd_ai.py` — 1152 righe **Ruolo:** Comandi AI, LLM e operativi. Modulo più pesante — contiene lo streaming loop. | Comando / Funzione | Trigger Telegram | |--------------------|-----------------| | `_cmd_do(chat_id, goal)` | `/avvia` — lancia task AI con streaming | | `_cmd_autofix(chat_id)` | `/fix` `tgw_autofix` | | `_cmd_nota(chat_id, text)` | `/nota` `tgw_nota` | | `_cmd_cerca(chat_id, query)` | `/cerca` `tgw_cerca` | | `_cmd_meteo(chat_id, city)` | `/meteo` `tgw_meteo` | | `_cmd_riepilogo(chat_id)` | `/riepilogo` `tgw_briefing` | | `_cmd_score(chat_id)` | `/score` `tgw_score` | | `_cmd_bench(chat_id)` | `/bench` `tgw_bench` | | `_cmd_improve(chat_id, target)` | `/migliora` `tgw_improve` | **Import:** stdlib + `telegram_tg_client` + `telegram_keyboards` --- ### `telegram_callbacks.py` — 353 righe **Ruolo:** Smista `callback_query` e `inline_query` in arrivo da Telegram. | Funzione | Descrizione | |----------|-------------| | `_handle_inline(iq, token)` | Risponde alle inline query (`@ARJagent_ap_bot testo`) | | `_handle_callback(cb, token)` | Dispatch per tutti i `callback_data` `tgw_*` / `agent` / `qp_*` | **Import:** `telegram_tg_client` + `telegram_keyboards` + `telegram_cmd_ai` + `telegram_cmd_monitoring` > ⚠️ **Questo modulo crea dipendenze circolari potenziali** — non importare > `telegram_callbacks` da `telegram_cmd_ai` o `telegram_cmd_monitoring`. --- ### `telegram_webhook.py` — 605 righe *(era 2844)* **Ruolo:** Router FastAPI puro. Solo endpoint HTTP, zero logica di business. | Endpoint | Metodo | Descrizione | |----------|--------|-------------| | `/api/telegram/webhook` | POST | Ricezione update getUpdates (polling daemon) | | `/api/telegram/process` | POST | Endpoint alternativo per CF Pages proxy | | `/api/telegram/config/invalidate` | POST | Invalida cache config bot | **Import:** FastAPI + tutti i 5 moduli sopra **Montato in:** `backend/main.py` → `app.include_router(_tg_webhook_router)` --- ## Regole per gli hotfix | Vuoi cambiare... | Tocca solo... | |------------------|---------------| | Aspetto di un bottone / label | `telegram_keyboards.py` | | Risposta a un comando /help, /stato… | `telegram_cmd_monitoring.py` | | Logica task AI / streaming / bench | `telegram_cmd_ai.py` | | Routing dei bottoni inline (tgw_*) | `telegram_callbacks.py` | | Helpers HTTP verso api.telegram.org | `telegram_tg_client.py` | | Routing endpoint FastAPI | `telegram_webhook.py` | --- ## Daemon Node.js (scripts/lib/daemon-callbacks.mjs) Il daemon usa **getUpdates polling** (non webhook registrato). Riceve gli update, li smista ai command handler Python via HTTP interno. Il flusso `callback_data tgw_*` viene elaborato da `telegram_callbacks.py::_handle_callback`. ``` Telegram ──► getUpdates daemon ──► POST /api/telegram/process │ telegram_webhook.py (router) │ ┌───────────┴───────────┐ message? callback_query? │ │ telegram_cmd_*.py telegram_callbacks.py ::_handle_callback ```