Ads with Superadmin

Sistema de gestión autónoma de campañas de Google Ads controlado 100% por Claude. Cron diario que analiza, decide y optimiza. Dashboard /superadmin/ads para visibilidad total y control.

Fase 1 Completada Cron Autónomo (Opción B) Fase 10 Extensión $10/día · 3 clusters activos

Objetivo

Construir un sistema de gestión de campañas de Google Ads controlado 100% por Claude, donde un cron autónomo ejecuta diariamente:

  1. Sincronización de métricas desde Google Ads API
  2. Análisis de performance por campaña / ad group / keyword / ad
  3. Toma de decisiones de optimización (bids, keywords, negativos, pausas)
  4. Ejecución de cambios vía Google Ads API
  5. Log de acciones con razonamiento (auditable)

El usuario accede al dashboard /superadmin/ads para visualizar qué hizo Claude, ver métricas en tiempo real y opcionalmente intervenir.

Arquitectura General

┌─────────────────────────────────────────────────────────────┐
│                      GOOGLE ADS API                          │
│           (MCC → Cuenta Testio, OAuth2 + Dev Token)          │
└──────────────────┬──────────────────────────────────────────┘
                   │
         ┌─────────┴──────────┐
         │                    │
   ┌─────▼──────┐       ┌─────▼─────┐
   │ SYNC CRON  │       │ DECISION  │
   │ (diario    │       │ ENGINE    │
   │  8:00 AM)  │       │ (diario   │
   │            │       │  9:00 AM) │
   │ Baja KPIs  │       │           │
   │ → DB       │       │ Claude    │
   └─────┬──────┘       │ SDK       │
         │              │ analiza   │
         ▼              │ → decide  │
   ┌────────────┐       │ → ejecuta │
   │ PostgreSQL │◄──────┤           │
   │ ads_*      │       └─────┬─────┘
   │ tablas     │             │
   └─────┬──────┘             ▼
         │              ┌──────────────┐
         │              │ AUDIT LOG    │
         │              │ + Safety     │
         │              │ Checks       │
         │              └──────────────┘
         │
         ▼
   ┌────────────────────────────┐
   │ /superadmin/ads  (Web UI)  │
   │ Dashboard moderno          │
   └────────────────────────────┘

Safety Rails — No Negociables

Al ser un sistema autónomo que gasta dinero real, estos controles son obligatorios antes del go-live:

Budget cap diario

Config en DB: max_daily_spend_eur. Si se excede, cron pausa todas las campañas automáticamente.

Budget cap mensual

Alerta + pausa si se alcanza el límite mensual configurado.

Límite de cambios/día

Máximo N acciones por ejecución (ej. 10 bids + 5 keywords + 3 pausas).

Ventana de cambios

Pausas y cambios de budget solo entre 8am–10pm (horario Madrid).

Dry-run mode

Toggle que simula acciones sin ejecutarlas. DEFAULT durante fase beta.

Rollback 24h

Toda acción guardada con estado anterior → endpoint para revertir en las siguientes 24h.

Kill switch

Flag global ads_automation_enabled. Si false, cron no toca nada.

Circuit breaker

Si ROAS cae >40% vs semana anterior, pausa automática + alerta email inmediata.

Alertas email

A andresmartinezb92@gmail.com en: pausas automáticas, errores API, límites alcanzados.

Modelo de Datos (Prisma)

model AdsAccount { id String @id @default(cuid()) customerId String @unique mccId String? refreshToken String currency String @default("USD") timezone String @default("America/New_York") maxDailySpend Float @default(10) maxMonthlySpend Float @default(300) automationEnabled Boolean @default(false) dryRunMode Boolean @default(true) createdAt DateTime @default(now()) } model AdsCampaign { id String @id @default(cuid()) externalId String @unique accountId String name String status String budget Float biddingStrategy String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model AdsMetricsDaily { id String @id @default(cuid()) date DateTime campaignId String adGroupId String? keywordId String? impressions Int clicks Int cost Float conversions Float conversionValue Float ctr Float cpc Float @@unique([date, campaignId, adGroupId, keywordId]) @@index([date]) } model AdsAction { id String @id @default(cuid()) executedAt DateTime @default(now()) type String // BID_ADJUST, PAUSE_KEYWORD, ADD_NEGATIVE, PAUSE_CAMPAIGN entityType String // CAMPAIGN, AD_GROUP, KEYWORD, AD entityId String beforeState Json afterState Json reasoning String @db.Text appliedByAI Boolean @default(true) dryRun Boolean reverted Boolean @default(false) } model AdsAlert { id String @id @default(cuid()) createdAt DateTime @default(now()) severity String // INFO, WARNING, CRITICAL type String // BUDGET_CAP, ROAS_DROP, API_ERROR message String resolved Boolean @default(false) }

Fases de Desarrollo

1 Prerequisitos

1–3 días ✅ Completado

Objetivo: Tener acceso técnico a Google Ads API antes de escribir código.

  • Crear Google Ads Manager Account (MCC) y vincular cuenta Testio
  • Solicitar Developer Token (modo test al inicio; aprobación producción ~1–2 días)
  • Crear OAuth2 Client en Google Cloud Console (añadir scope https://www.googleapis.com/auth/adwords)
  • Generar Refresh Token con script helper
  • Configurar conversion tracking: importar GA4 + webhook Stripe (Sign-up / Subscription Start)
  • Guardar credenciales en .env producción (encriptadas)
Deliverable: .env con GOOGLE_ADS_DEVELOPER_TOKEN, CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN, CUSTOMER_ID, MCC_ID.

2 Cliente Google Ads API

2 días Pendiente

Objetivo: Wrapper tipado en el backend para hablar con Google Ads.

  • Instalar google-ads-api (npm)
  • Crear apps/api/src/services/googleAds.ts con getClient, list, getMetrics, pause, bid, negative, etc.
  • Wrapper con dryRun flag en cada método mutador
  • Tests unitarios con mock de la API
  • Migrar schema Prisma (modelos AdsAccount, AdsCampaign, AdsMetricsDaily, AdsAction, AdsAlert)
Deliverable: Servicio que Claude puede usar; primeras queries funcionando en producción contra cuenta real.

3 Sync Cron

1 día Pendiente

Objetivo: Poblar tablas ads_* diariamente con datos frescos.

  • scripts/ads_sync.ts — Descarga métricas últimos 7 días
  • Configurar cron en VPS: 0 8 * * * cd /var/www/project1 && node scripts/ads_sync.js
  • Upsert en ads_metrics_daily (evitar duplicados)
  • Sync de entidades: campañas, ad groups, keywords, ads
  • Log de ejecución + alerta email si falla
Deliverable: DB con datos frescos cada mañana, consultables desde API.

4 Dashboard /superadmin/ads

3–4 días Pendiente

Objetivo: Visibilidad total antes de que Claude toque nada. El dashboard se construye ANTES del motor de decisión.

  • /superadmin/ads — Overview: StatCards (spend hoy/mes, conversions, ROAS, CAC), timeline 30d, semáforo safety rails, alertas activas, últimas 10 acciones
  • /superadmin/ads/campaigns — Tabla con spend, conversions, ROAS, status, budget utilization
  • /superadmin/ads/campaigns/:id — Detalle + ad groups + keywords + ads, timeline, controles manuales
  • /superadmin/ads/actions — Historial completo con razonamiento de Claude + botón "Revertir"
  • /superadmin/ads/settings — Toggles automation/dryRun, inputs caps, kill switch
  • Stack: React + Recharts + Tailwind (consistente con resto del dashboard)
Deliverable: UI completa funcional leyendo datos reales del sync. Aún SIN motor de decisión.

5 Motor de Decisión (Claude Agent SDK)

4–5 días Pendiente

Objetivo: Cron diario a las 9am donde Claude analiza y ejecuta optimizaciones.

  • scripts/ads_optimize.ts — Entry point del cron
  • Instalar @anthropic-ai/claude-agent-sdk
  • Tools MCP que Claude invoca: get_metrics, get_search_terms, pause_keyword, adjust_bid, add_negative, adjust_budget
  • System prompt: rol especialista Google Ads + contexto negocio + reglas + metodología
  • Output estructurado: cada decisión con reasoning guardado en ads_action
  • Primera semana: dryRunMode = true → Claude propone, no ejecuta
  • Post-validación: activar modo live
  • Prompt caching obligatorio (contexto del negocio es estático)
Deliverable: Cron ejecutándose diario. Log de decisiones visible en dashboard. Acciones aplicándose tras validación dry-run.

5.5 Landings Estratégicas Own-Brand

4–5 días Pendiente

Objetivo: Crear landings que hablen de Testio en su propio terreno, no solo como "alternativa a X". La apuesta grande está en la intent problema-aware ("quiero mejorar conversión"), no solo en la competitiva.

  • Refinar Homepage — Potenciar messaging para intent brand/categoría: "A/B testing software", "split testing tool"
  • Landing CRO (EN) — Nueva /cro-tool — "Conversion Rate Optimization Tool" para intent problema-aware
  • Landing CRO (ES) — Nueva /optimizar-conversion — "Optimiza la conversión de tu sitio"
  • Landing Shopify (EN+ES) — Vertical ecommerce para Cluster 4
  • SEO completo: canonical, hreflang, Schema.org, Open Graph
  • Actualizar sitemap.xml + analytics tracking (GA4 + Clarity)
Deliverable: 4 landings nuevas + homepage refinada, todas con tracking de conversión listo.

6 Campañas Iniciales (4 Clusters)

2 días Pendiente

Objetivo: Matriz lean de 3 clusters activos (el 4.º queda pausado hasta validar). Presupuesto inicial conservador: $10/día ≈ $300/mes.

CLUSTER 2 CRO / Problema-aware · $4/día · 🔥 apuesta grande

Intent: "Quiero vender más / mejorar conversión". Volumen alto, menos competido que "A/B testing".

Search — CRO Tool (EN)

Keywords: "conversion rate optimization", "CRO tool", "increase website conversions"

/cro-tool (nueva)
$2/día

Search — Optimizar Conversión (ES)

Keywords: "mejorar conversión web", "optimizar tasa conversión", "aumentar ventas"

/optimizar-conversion (nueva)
$2/día

CLUSTER 3 Competitiva · $4/día

Intent: "Busco alternativa a X". Bajo volumen pero conversión muy alta. Landings ya desplegadas ✅

Search — Google Optimize Alt (EN)

"google optimize alternative/replacement/migration"

/google-optimize-alternative
$2/día

Search — Alternativa Google Optimize (ES)

"alternativa/reemplazo google optimize"

/alternativa-google-optimize
$2/día

CLUSTER 1 Brand / Categoría · $2/día · exploratorio

Intent: "A/B testing software/tool". Budget bajo para validar si conviene escalar.

Search — A/B Testing Software (EN+ES ad groups)

Keywords EN: "a/b testing software", "split testing tool". ES: "herramienta testing ab"

/ (homepage)
$2/día

CLUSTER 4 Verticales · pausado — reactivar cuando CAC permita escalar

WordPress y Shopify quedan esperando hasta validar unit economics con clusters 1-3.

Deliverable: $10/día ≈ $300/mes en 3 clusters activos. Budget escalable desde /superadmin/ads/settings cuando datos justifiquen subida.

7 Monitoring y Alertas

1 día Pendiente

Objetivo: Observabilidad total del sistema autónomo.

  • Email diario 9:15am: resumen de lo que hizo Claude
  • Email inmediato: errores API, circuit breaker, budget cap
  • Endpoint /api/health/ads para uptime
  • Logs estructurados (JSON) a archivo rotativo

8 Iteración y Mejora Continua

Ongoing Pendiente

Objetivo: Evolucionar el sistema con los aprendizajes.

  • Reporting semanal con análisis de tendencias
  • A/B testing de ad copy (irónicamente, usando Testio)
  • Expansión a Performance Max si validamos unit economics
  • Integración con dashboard de conversiones de Stripe (LTV real)

Cronograma Estimado

Fase Duración Acumulado
1. Prerequisitos 3 días (paralelo con Fase 2) día 3
2. Cliente API 2 días día 5
3. Sync Cron 1 día día 6
4. Dashboard Superadmin 4 días día 10
5. Motor Decisión 5 días día 15
5.5. Landings Own-Brand 🆕 4–5 días día 20
6. Campañas iniciales (4 clusters) 2 días día 22
7. Monitoring 1 día día 23
🎯 MVP Live (con dry-run) día 23
Validación dry-run 7 días día 30
🚀 Live Autónomo día 31

Riesgos y Mitigaciones

Riesgo Mitigación
Claude quema presupuesto por mala decisión Safety rails completos: budget cap, límite de cambios, dry-run, circuit breaker
API rate limits Backoff exponencial + batching
Refresh token expira Detección automática + alerta email + re-auth manual
Conversiones mal trackeadas → ROAS falso Doble tracking (GA4 + Stripe webhook) antes de go-live
Cambios simultáneos (usuario + Claude) Lock optimista en ads_action con timestamp
Google suspende cuenta Compliance: no exceder políticas de anuncios, review manual de copy

Decisiones Pendientes

Ubicación del cron

¿VPS actual o servicio separado?

→ Propuesta: VPS actual, crontab con logs rotados

Moneda y presupuesto ✅

USD, $300/mes ($10/día en 3 clusters)

→ Decidido 2026-04-19

Conversion event principal

¿Sign-up (registro) o Trial-start (inicio trial)?

→ Propuesta: Trial-start (mayor valor)

Target ROAS

¿2x? ¿3x? Definir según LTV:CAC objetivo

→ Pendiente definir

Idioma razonamiento Claude

¿ES o EN en los logs de decisiones?

→ Propuesta: ES (dueño del producto)

Próximo Paso Inmediato

Fase 1 completada ✅ — Arrancamos Fase 2

Setup técnico (2026-04-19):

  • ✅ MCC creado: 512-544-2858
  • ✅ Cuenta gestionada vinculada: 703-296-0494 (USD / America/New_York)
  • ✅ Developer Token obtenido (modo TEST, pendiente Basic access de Google 1–2 días)
  • ✅ OAuth Client (Desktop app) + Client Secret + Refresh Token
  • ✅ Credenciales en .env producción
  • ✅ Pipeline validado end-to-end: OAuth refresh + GAQL query real funcionan
  • ✅ Servicio apps/api/src/services/googleAds.ts creado con ping(), getAccountInfo(), listCampaigns()

Fases en paralelo ahora: Fase 2 (cliente API completo) + Fase 5.5 (landings own-brand), luego Fase 3+4 (sync cron + dashboard superadmin).

Stack Técnico

Componente Tecnología
Google Ads SDKgoogle-ads-api (npm)
AI SDK@anthropic-ai/claude-agent-sdk
Modeloclaude-opus-4-7 con prompt caching
Croncrontab del VPS (isolation)
Base de datosPostgreSQL (producción)
UIReact + Tailwind + Recharts
AuthJWT + role SUPERADMIN
Encriptación secretsAES-256 en DB, rotación trimestral