José Manuel Gómez d58448f698 Add technical documentation (docu.md)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:19:30 +02:00

204 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Leads Optimizer — Documentación técnica
## Qué hace
Agente automatizado que cada día:
1. Sincroniza el catálogo de campañas de Google Ads → Airtable
2. Lee las métricas del mes en curso (coste, conversiones, leads)
3. Analiza el rendimiento de cada campaña
4. Toma una decisión con IA (Claude) sobre qué hacer con el presupuesto
5. Aplica la decisión en Google Ads (o la simula en modo DRY_RUN)
6. Guarda el resultado en Airtable
---
## Modelo de negocio
```
Ingreso = leads_entregados × PPL
Margen = (Ingreso - Gasto Google Ads) / Ingreso
CPA max = PPL × 0.70 → margen mínimo aceptable del 30%
```
- **PPL** (Precio Por Lead): fijo por curso, ponderado por el % de invalidación del centro.
- **Capping mensual**: máximo de leads a entregar por campaña ese mes. Si = 0, sin límite.
---
## Flujo de ejecución (`run.py`)
```
1. Sincronizar campañas Google Ads → Google Ads Campaigns (Airtable)
2. Sincronizar GACampaignMes (estado mensual: coste, conversiones, PPL, cap)
3. Leer campañas activas del mes desde GACampaignMes
4. Detección anticipada:
- courses_with_both: cursos con Search Y PMX simultáneos
- courses_with_leadform: cursos con campaña _leadform activa
5. PRIMERA PASADA: para cada campaña
- Contar leads Airtable (get_leads_this_month_gads)
- Obtener métricas Google Ads (get_campaign_metrics)
- Calcular leads_grupo (para PMX con companion: usa conversiones Google)
- Analizar (analyzer.py) → urgencia, CPA, margen, ritmo
- Decidir (agent.py / Claude) → acción, presupuesto, consejo
6. Actualizar Status en ambas tablas Airtable
7. SEGUNDA PASADA (ordenada por criticidad):
- Imprimir resultado por consola
- Aplicar decisión en Google Ads
- Construir log_text con notas de atribución PMX/leadform
8. Guardar en GACampaignMes: Consejo, Criticidad, Log
9. Guardar ConvLeadsLakeMesFinal + ConvLeadsLakeMesGrupo
```
---
## Módulos
### `analyzer.py`
Calcula métricas derivadas y asigna la **urgencia**.
Entradas: `campaign_config`, `leads_entregados`, `ads_metrics`
| Métrica | Cálculo |
|---------|---------|
| `ratio_leads` | leads / capping |
| `ratio_mes` | día actual / días del mes |
| `ritmo` | ratio_leads ratio_mes (>0 adelantado, <0 atrasado) |
| `cpa_actual` | gasto / leads |
| `margen` | (leads × PPL gasto) / (leads × PPL) |
**Urgencia:**
| Valor | Condición |
|-------|-----------|
| `PAUSAR` | ratio_leads 1.0 (capping lleno) |
| `SPRINT` | Atrasado >15% **y** quedan ≤5 días para fin de mes |
| `ACELERAR` | ritmo < 0.15 |
| `FRENAR` | ritmo > +0.15 |
| `EN_RITMO` | diferencia ≤ 15% |
---
### `agent.py`
Llama a Claude (claude-sonnet-4-20250514) con el resultado del análisis y devuelve una decisión en JSON.
**Reglas de decisión:**
| Urgencia | Rentable | Acción | Parámetro |
|----------|----------|--------|-----------|
| PAUSAR | — | `PAUSAR` | — |
| SPRINT | — | `AUMENTAR_PRESUPUESTO` | ×1.31.5 |
| ACELERAR | ✅ | `AUMENTAR_PRESUPUESTO` | ×1.11.25 |
| ACELERAR | ❌ | `MANTENER` | — |
| FRENAR | — | `REDUCIR_PRESUPUESTO` | ×0.750.9 |
| EN_RITMO | ✅ | `MANTENER` | — |
| EN_RITMO | ❌ | `REDUCIR_PRESUPUESTO` | ×0.85 |
Devuelve: `accion`, `parametro`, `nuevo_budget_diario`, `justificacion`, `consejo`, `alerta`, `confianza`.
---
### `optimizer.py`
Aplica la decisión del agente sobre Google Ads. Si `DRY_RUN=True`, solo imprime lo que haría.
| Acción | Efecto |
|--------|--------|
| `PAUSAR` | Pausa la campaña vía API |
| `AUMENTAR_PRESUPUESTO` / `REDUCIR_PRESUPUESTO` | Ajusta el presupuesto diario |
| `MANTENER` | No hace nada |
---
### `airtable_client.py`
Gestiona toda la comunicación con Airtable.
**Tablas usadas:**
| Tabla | Uso |
|-------|-----|
| `Google Ads Campaigns` | Catálogo de campañas (nombre, CampaignID, PPL, Status) |
| `GACampaignMes` | Estado mensual por campaña (coste, conversiones, leads, consejo, criticidad, log) |
| `Leads Lake` | Leads recibidos (filtrado por campaña y mes) |
| `Cursos` | Relación CursoID ↔ CentroCurso |
| `CentroCurso` | PPL y % invalidación por centro |
| `CursoMes` | Capping mensual por curso |
**Métodos principales:**
- `build_campaign_lookups()` — calcula PPL ponderado y capping mensual para todos los cursos
- `sync_campaigns_from_google_ads()` — crea/actualiza el catálogo de campañas
- `sync_gacampaignmes()` — crea/actualiza registros mensuales de campañas con actividad
- `get_active_gacampaignmes()` — devuelve las campañas del mes en curso
- `get_leads_this_month_gads()` — cuenta leads Airtable para una campaña Google Ads
- `batch_update_gacampaignmes_advice()` — guarda Consejo, Criticidad y Log
- `batch_update_gacampaignmes_final_leads()` — guarda ConvLeadsLakeMesFinal y ConvLeadsLakeMesGrupo
---
### `google_ads_client.py`
Wrapper sobre la API de Google Ads.
- `get_all_campaigns()` — lista todas las campañas no eliminadas
- `get_monthly_metrics_all()` — conversiones y coste del mes para todas las campañas (1 query)
- `get_campaign_metrics()` — métricas detalladas de una campaña concreta
- `set_campaign_budget()` — cambia el presupuesto diario
- `pause_campaign()` — pausa una campaña
---
## Criticidad
Combina urgencia + acción para priorizar el output y el campo `Criticidad` en Airtable:
| Criticidad | Cuándo |
|------------|--------|
| **Crítico** | Urgencia es `PAUSAR` o `SPRINT` |
| **Peligro** | Acción cambia el presupuesto pero urgencia no es crítica |
| **Mantener** | Acción es `MANTENER` |
---
## Casos especiales de atribución
### PMX con companion Search (`courses_with_both`)
Cuando un curso tiene activos simultáneamente `fco_search_NNN_*` y `fco_pmx_NNN_*`, Google puede reatribuir conversiones del Search al PMX.
- La campaña **PMX** usa como `leads_grupo` las **conversiones de Google Ads** (no los leads de Airtable).
- Se añade una nota `⚠️ PMX ATTRIBUTION` en el campo `Log` de la campaña Search.
### Campaña Leadform (`_leadform`)
Las campañas con sufijo `_leadform` capturan leads directamente dentro de Google (sin que el usuario visite la web). Esos leads **nunca llegan a Airtable**.
- Se añade ` LEADFORM` en el `Log` de la propia campaña.
- Las campañas hermanas del mismo curso reciben `⚠️ LEADFORM COMPANION` en su `Log`.
---
## Configuración (`.env`)
```env
AIRTABLE_TOKEN=...
AIRTABLE_BASE_ID=...
GOOGLE_ADS_DEVELOPER_TOKEN=...
GOOGLE_ADS_CLIENT_ID=...
GOOGLE_ADS_CLIENT_SECRET=...
GOOGLE_ADS_REFRESH_TOKEN=...
GOOGLE_ADS_LOGIN_CUSTOMER_ID=...
ANTHROPIC_API_KEY=...
```
`DRY_RUN = True` en `config.py` — cambiar a `False` para aplicar cambios reales en Google Ads.
---
## Logs
Cada ejecución genera un archivo en `logs/YYYYMMDD_HHMMSS.log` con la salida completa.
---
## Ejecutar
```bash
python run.py
```