11 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Este repo ya tiene un AGENTS.md con documentación operativa detallada (comandos, gotchas de GHL, paginación, reglas de negocio Monte Providencia). Léelo siempre primero. Este archivo cubre el panorama arquitectónico que no es obvio leyendo un único módulo.
Comandos esenciales
python -m pip install -r requirements.txt— instalar dependencias.python main.py— levanta FastAPI/Uvicorn enhttp://127.0.0.1:8000con reload.start.bat/stop.bat/restart.bat(Windows) — lanzan/matan/reinician la app y liberan el puerto 8000.restart.batdetecta automáticamente si estaba en modo normal o perfil persistente (leegenerated/runtime/last_mode), mata Chromium zombies y limpia batch files huérfanos engenerated/runtime/batch/.python -m py_compile main.py db.py ghl_client.py sync_engine.py script_runner.py paths.py— único "lint" disponible (no hay test/lint/format configurado).- Scripts de utilidad se corren directo:
python scripts\<nombre>.py [args]. La mayoría leengenerated/data/mp_manager.sqlite(víapaths.DB_PATH) y asumen una sync previa. - Variables de entorno:
SYNC_ENGINE_MAX_WORKERS(default 1000, sin tope) — paralelismo de "Sincronizar Todo". La concurrencia efectiva esmin(total_accounts, env_var), así que el default sincroniza todas las cuentas a la vez. El rate limit de GHL es por location, así que paralelizar más cuentas no provoca 429; bajar este valor solo tiene sentido para acotar uso de CPU/red local.SCRIPT_RUNNER_MAX_WORKERS(default 4, máx 20) — paralelismo del runner del dashboard. Subir esto aumenta riesgo de429porque los subprocesos no comparten rate limit.
Arquitectura — el panorama
Patrón general: el repo es un panel de control FastAPI sobre SQLite que cachea datos de varias cuentas (locations) de Go High Level y orquesta scripts Python que pueden auditar o mutar datos directamente en GHL.
Flujo de datos
CSV de tokens ──► sync_engine ──► ghl_client (API GHL) ──► db.py (SQLite)
│
┌────────────────────────┘
▼
main.py (FastAPI) ◄── templates/index.html + static/js
│
▼
script_runner ──► subprocess scripts/*.py ──► (audita en script_audit, muta en GHL)
Módulos núcleo (raíz del repo)
| Módulo | Rol |
|---|---|
main.py |
Punto de entrada FastAPI. Define endpoints, middleware de request_id, manejadores de excepción que escriben a error_log. En startup carga TOKENS_CACHE desde el CSV — los tokens nunca tocan SQLite. |
paths.py |
Fuente única de verdad para rutas en disco. Todo lo generado por la app/scripts (DB, reports, exports, logs, screenshots, sesiones Playwright, snapshots de migración, estado de runtime) vive bajo generated/. Cualquier módulo nuevo debe importar sus paths desde aquí — nunca hardcodear. |
db.py |
Capa SQLite. Define el esquema (accounts, contacts, pipelines, opportunities, workflows, sync_log, error_log) y operaciones de lectura/escritura. Cada save_* por location se hace en una transacción que reemplaza los registros previos de esa location. |
ghl_client.py |
Cliente HTTP de GHL. Implementa rate limiting (110ms entre peticiones por token), reintentos con backoff exponencial para 5xx y lineal para 429, sesión TCP persistente por hilo. Es la fuente de verdad del comportamiento GHL. |
sync_engine.py |
Orquesta sync_account (pipelines → opportunities → contacts → guardado transaccional) y sync_all_accounts (ThreadPoolExecutor con SYNC_ENGINE_MAX_WORKERS). Lee el CSV en cada arranque y sincronización. |
script_runner.py |
Lanza scripts como subprocesos, encola sus logs para SSE, maneja ejecución paralela vs secuencial, asocia cada run a un run_id para auditoría. Sólo expone los scripts listados en SCRIPTS_METADATA. |
script_audit.py |
Sistema de auditoría/rollback paralelo: script_runs, script_change_log, script_run_control. Los scripts mutadores deben registrar cada cambio aquí (estado planned → applied → opcionalmente rolled_back) para que el dashboard pueda revertirlos por run_id. |
error_logging.py |
Centraliza logging técnico. Cada error retorna un error_id que se devuelve al cliente y se persiste en error_log. |
Carpeta generated/
Todos los archivos que produce la app o los scripts viven bajo generated/. La raíz del repo solo contiene código fuente, docs, configs estáticos (CSVs de tokens y verificador) y script_metadata_overrides.json (config viva del dashboard).
generated/
├── data/ mp_manager.sqlite (+ -shm, -wal)
├── reports/ outputs de scripts de auditoría (audit_custom_fields/, duplicados/, drift/, coverage/)
├── exports/ descargas del dashboard (servido vía /api/exports/{filename})
├── logs/ errors.jsonl + script_runs/ para runs futuros
├── migrations/ snapshots pre-destructive de scripts mutadores
├── browser/ session.json (Playwright shared), profile/, screenshots/
├── runtime/ server_info.json, last_mode, batch/ (bulk batches en vuelo)
└── _archive/ basura legacy fechada
Está ignorada en .gitignore y .megaignore. Para añadir un nuevo destino, agregar la constante en paths.py y registrar el directorio en ensure_dirs().
Cuenta principal vs sucursales
El location_id GbKkBpCmKu2QmloKFHy3 es la cuenta de Marca principal (Monte Providencia). Está hardcodeado en sync_engine.parse_accounts_csv y scripts/common.py (BRAND_LOCATION_ID). Todas las demás filas del CSV son sucursales. La sincronización de contactos es bidireccional Marca↔Sucursal; la de oportunidades es unidireccional Sucursal→Marca (la sucursal tiene prioridad). Ver AGENTS.md para las reglas completas.
Custom fields dinámicos
Los IDs de custom fields varían por sucursal. Nunca los hardcodees. Resuélvelos por nombre via los endpoints GET /objects/?locationId=… y GET /objects/{contact|opportunity}?locationId=… (header Version: 2021-04-15). scripts/common.py expone SchemaResolver y FIELD_ALIASES para esto — úsalo en scripts nuevos en vez de reinventar.
Convenciones de scripts
Los scripts viven en scripts/ y se categorizan por nombre:
- Read-only:
audit_*,mp_*_search,analyze_*,find_*,check_*,health_check_*,*_readonly,daily_summary_*. - Mutadores (escriben en GHL):
fix_*,migrate_*,move_*,update_*,sync_contact_*,cleanup_*,reconcile_*,fill_*. Estos deben soportar--dry-runy registrar cambios enscript_auditcon su--run-id. - Todos los scripts comparten utilidades en
scripts/common.py(carga de cuentas, resolver de schemas, normalización de nombres). - Para que un script aparezca en el dashboard hay que agregarlo a
SCRIPTS_METADATAenscript_runner.py(título, descripción, categoría, opciones,mutator: Truesi aplica).
Frontend
templates/index.html + static/js/app.js + static/css/style.css son el SPA. Consume los endpoints /api/* y streamea logs de scripts via SSE en /api/scripts/stream/{task_id}.
Automatización con navegador
scripts/ghl_browser_*.py usan Playwright contra la UI web de GHL para cosas que la API no soporta (renombrar/eliminar workflows, p.ej.). Soportan dos modos de sesión: shared storage_state en generated/browser/session.json (default) o perfil Chrome persistente vía GHL_BROWSER_PROFILE_DIR (más estable, default generated/browser/profile, arrancar con start_persistent_profile.bat). El auto-login con 2FA por correo (IMAP) se configura en .env (ver .env.example).
Antes de tocar estos scripts:
- docs/PLAYWRIGHT_SESSION.md — manejo de sesión, modos, síntomas comunes, cómo reportar errores útilmente.
- docs/PLAYWRIGHT_PATTERNS.md — patrones probados (SPA detection por URL + DOM, OTP en inputs maxlength=1, selectores defensivos, screenshots de debug, validación contra API tras mutaciones,
SessionExpiredErrorpara abortar early en bulks). Incluye plantilla para scripts nuevos y checklist de revisión.
Capa agentica MCP
El proyecto expone un servidor MCP (stdio) en mcp_server/ que Claude Code consume automáticamente vía .mcp.json en la raíz. Da acceso tipado a cuentas, contactos, opps, syncs y al runner genérico run_script que cubre los ~60 scripts no expuestos como tool dedicada. Defaults seguros: toda tool mutadora arranca con apply=False y requiere confirm_token="I-HAVE-USER-CONFIRMATION" para aplicar — forzando confirmación humana explícita. Los runs con apply=True quedan en script_audit y son reversibles desde el dashboard.
- Guía user-facing (cómo aprovecharlo desde Claude Code, recetas y prompts): docs/GUIA_AGENTICA.md.
- Catálogo técnico (contrato, tools, troubleshooting): docs/AGENT_TOOLS.md.
- Manifest autogenerado:
generated/agent/tools_manifest.json. Auditoría de salud:python scripts/audit_agent_readiness.py.
Reglas críticas que no son obvias
- El CSV
Bucéfalo - Mesa de control - API Tokens - MP.csvy los tokens son secretos. No los imprimas en logs ni los persistas en SQLite. - Paginación GHL obligatoria: contactos con
meta.nextPageUrl/startAfter, oportunidades conPOST /opportunities/search. Nunca uses offset pagination niGET /opportunities/. Detalle completo en AGENTS.md. - Marca: Bucéfalo es nuestro CRM. Aunque GHL aparece en el código por necesidad técnica, no lo menciones como producto en interfaces de usuario o documentación destinada a clientes.
- Pipelines sintéticos: si GHL devuelve
[]de pipelines pero hay oportunidades conpipelineId,sync_enginelos reconstruye desde las etapas — no es bug, es fallback. - Antes de modificar GHL: prefiere correr el script en modo
--dry-runy revisar el resumen de auditoría antes de aplicar. - Registro de casos (
docs/casos/): bitácora de operaciones/investigaciones reales, optimizada para recall del agente. Antes de investigar un síntoma nuevo,grepahí por el error/síntoma (quizá ya está resuelto). Después de mutar Bucéfalo o cerrar una investigación con causa raíz, registra el caso (copiadocs/casos/_PLANTILLA.md, agrega fila adocs/casos/INDEX.md). Es complemento de losPLAYBOOK_*(teoría) y la memoria (hechos atómicos).