# Vale — Master Doc

**Producto**: Vale — empleado AI bilingüe para negocios de servicios
**Owner**: Franco
**Estado**: Locked — listo para desarrollo
**Fecha de creación**: 29 de mayo de 2026
**Última actualización**: 29 de mayo de 2026
**Versión**: 1.0

**Marco del concurso (Build with Gemini XPRIZE)**
- Apertura de submission: 19 de mayo de 2026
- Cierre de submission: 17 de agosto de 2026, 1:00 PM PDT
- Período de evaluación: 18 de agosto – 15 de septiembre de 2026
- Anuncio de ganadores: ~25 de septiembre de 2026
- Categoría objetivo: Small Business Services

---

## 1. Visión

Vale es el primer empleado que cualquier negocio chico de servicios puede pagar: atiende clientes 24/7 en español e inglés, los pone en Google, agenda y recupera la plata que hoy se les escapa. Para dueños Latinos de servicios en USA (barberías, limpieza, clínicas, talleres). Si funciona, el negocio de barrio atiende como uno grande sin contratar a nadie.

---

## 2. Problema y solución

### Problema
Los negocios de servicios pierden clientes cada vez que no contestan un mensaje o llamada (fuera de horario, ocupados, una sola persona haciendo todo). Cada lead sin respuesta se va al competidor. Muchos ni aparecen en Google Maps.

### Solución propuesta
Un empleado AI bilingüe que vive en WhatsApp/web: contesta al instante, califica, agenda, hace follow-up y recupera no-shows y leads fríos. Además pone al negocio en Google (perfil + landing) para que lo encuentren.

### Por qué nosotros
Distribución: llegamos y cerramos al SMB Latino que otros no pueden adquirir (idioma, confianza, red). Eso es el moat real, no la tecnología.

---

## 3. Usuarios y roles

| Rol | Quién es | Qué hace en el sistema | Permisos clave |
|-----|----------|------------------------|----------------|
| Owner | Dueño del negocio (tenant) | Configura a Vale, ve panel, toma conversaciones | Todo dentro de su tenant |
| Staff | Empleado del negocio | Atiende inbox, ve citas | Limitado a su tenant |
| Cliente final | Cliente del negocio | Escribe por WhatsApp/web, agenda | No accede al sistema |
| Super-admin | Operación interna | Onboarding, soporte, métricas globales | Cross-tenant |

---

## 4. Stack técnico

### Frontend
- Dashboard del dueño: vanilla JS + HTML + CSS (tokens del Brand Kit), server-rendered desde PHP.
- Widget de chat web embebible (snippet `<script>`).
- Justificación: stack liviano y conocido para un panel CRUD + inbox.

### Backend
- **PHP 8.2** para dashboard, admin y APIs internas.
- **Agente conversacional**: servicio containerizado en **Google Cloud Run** que recibe webhooks, llama a Gemini y ejecuta acciones vía **Function Calling**.
- API style: REST (JSON).

### Inteligencia (IA)
- **Gemini API** (familia 3, modelo Flash) como cerebro de Vale, con al menos una llamada en producción en la app desplegada.
- **Function Calling**: el agente no solo conversa, ejecuta acciones (`crear_cita()`, `actualizar_perfil_google()`, `enviar_recordatorio()`, `ofrecer_hueco()`). Es el mecanismo central por el que Vale toma decisiones operativas.
- Los servicios y precios del negocio se inyectan en el contexto del prompt (datos chicos, no requieren base vectorial).

### Base de datos
- **MySQL 8**, engine **InnoDB**, charset **utf8mb4_unicode_ci**.
- Multi-tenant: shared DB con `tenant_id`.

### Hosting / Infra
- Dashboard + DB: cPanel/WHM (subdominio, SSL, cron jobs para follow-ups).
- Agente: Cloud Run (autoscale, webhooks).
- Landing generada: Firebase Hosting o Cloud Run.

### Integraciones externas
- **Gemini API** → cerebro + Function Calling.
- **Google Calendar API** → fuente de verdad de la agenda del negocio (Vale lee/escribe ahí).
- **Google Business Profile API** → presencia en Google Maps.
- **Twilio** → WhatsApp + SMS.
- **Stripe** → suscripción + setup fee.

### Dependencias críticas
- Gemini (si cae: encolar + avisar). Twilio (canal). MySQL (estado). Sin estos tres no hay producto.

---

## 5. Arquitectura

Monolito PHP para el dashboard + un microservicio de agente en Cloud Run. Multi-tenant (shared DB con `tenant_id`). El chat es síncrono (responder rápido); follow-ups y recuperación son asíncronos vía cron. El agente usa Function Calling para ejecutar acciones. La agenda vive en Google Calendar.

```
[Cliente final]
   |  WhatsApp / Web chat
   v
[Twilio] --webhook--> [Agente Vale en Cloud Run] --> [Gemini API + Function Calling]
                              |
                              |--> [MySQL en cPanel]        (conversaciones, leads, logs)
                              |--> [Google Calendar API]    (agenda, fuente de verdad)
                              +--> [Google Business Profile API]

[Dueño / Staff] --HTTPS--> [Dashboard PHP en cPanel] --> [MySQL]
                                    |
                                    |--> [Stripe]   (billing)
                                    +--> [Cron]     (follow-ups, recuperación)
```

- **Multi-tenant**: `tenant_id` en toda tabla relevante (FK + índice). No opcional.
- **Sync vs async**: respuesta al cliente = sync. Follow-ups/recordatorios/recuperación = cron async.

---

## 6. Modelo de datos

Schema ejecutable. Para el repo conviene extraerlo a `SCHEMA.sql`.

```sql
-- Negocios que contratan a Vale
CREATE TABLE tenants (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(160) NOT NULL,
    business_type VARCHAR(80) NULL,
    owner_name VARCHAR(120) NULL,
    phone VARCHAR(32) NULL,
    whatsapp_number VARCHAR(32) NULL,
    timezone VARCHAR(48) NOT NULL DEFAULT 'America/New_York',
    locale VARCHAR(8) NOT NULL DEFAULT 'es',
    google_place_id VARCHAR(255) NULL,
    google_calendar_id VARCHAR(255) NULL,
    is_demo TINYINT(1) NOT NULL DEFAULT 0,
    status ENUM('trial','active','past_due','canceled') NOT NULL DEFAULT 'trial',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Usuarios del dashboard (dueño + staff)
CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    email VARCHAR(160) NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    name VARCHAR(120) NULL,
    role ENUM('owner','staff') NOT NULL DEFAULT 'owner',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uq_email (email),
    INDEX idx_tenant (tenant_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Config de Vale por tenant (personalidad y reglas)
CREATE TABLE vale_config (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    greeting TEXT NULL,
    hours_json JSON NULL,
    faq_json JSON NULL,
    booking_rules_json JSON NULL,
    tone VARCHAR(40) NOT NULL DEFAULT 'calido',
    default_locale VARCHAR(8) NOT NULL DEFAULT 'es',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uq_tenant (tenant_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Servicios del negocio (cotizar/agendar) -> se inyectan en el contexto
CREATE TABLE services (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    name VARCHAR(120) NOT NULL,
    duration_min INT UNSIGNED NULL,
    price_min DECIMAL(10,2) NULL,
    price_max DECIMAL(10,2) NULL,
    description VARCHAR(255) NULL,
    active TINYINT(1) NOT NULL DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_tenant (tenant_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Clientes finales
CREATE TABLE contacts (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    name VARCHAR(120) NULL,
    phone VARCHAR(32) NULL,
    channel ENUM('whatsapp','sms','web') NOT NULL DEFAULT 'whatsapp',
    locale VARCHAR(8) NULL,
    opted_out TINYINT(1) NOT NULL DEFAULT 0,
    first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_tenant (tenant_id),
    INDEX idx_tenant_phone (tenant_id, phone),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Conversaciones
CREATE TABLE conversations (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    contact_id BIGINT UNSIGNED NOT NULL,
    channel ENUM('whatsapp','sms','web') NOT NULL DEFAULT 'whatsapp',
    status ENUM('open','booked','lost','closed') NOT NULL DEFAULT 'open',
    handled_by ENUM('ai','human') NOT NULL DEFAULT 'ai',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_tenant_status (tenant_id, status),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Mensajes
CREATE TABLE messages (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    conversation_id BIGINT UNSIGNED NOT NULL,
    direction ENUM('inbound','outbound') NOT NULL,
    sender ENUM('contact','ai','human') NOT NULL,
    body TEXT NULL,
    media_url VARCHAR(512) NULL,
    model_tokens INT UNSIGNED NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_conversation (conversation_id),
    INDEX idx_tenant (tenant_id),
    FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Leads (metrica norte y embudo)
CREATE TABLE leads (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    contact_id BIGINT UNSIGNED NOT NULL,
    conversation_id BIGINT UNSIGNED NULL,
    status ENUM('new','qualified','booked','won','lost') NOT NULL DEFAULT 'new',
    value_estimate DECIMAL(10,2) NULL,
    source VARCHAR(40) NOT NULL DEFAULT 'ai',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_tenant_status (tenant_id, status),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Citas (espejo/cache de Google Calendar)
CREATE TABLE appointments (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    contact_id BIGINT UNSIGNED NOT NULL,
    service_id BIGINT UNSIGNED NULL,
    gcal_event_id VARCHAR(128) NULL,
    scheduled_at DATETIME NOT NULL,
    status ENUM('booked','confirmed','no_show','completed','canceled') NOT NULL DEFAULT 'booked',
    source VARCHAR(40) NOT NULL DEFAULT 'ai',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_tenant_sched (tenant_id, scheduled_at),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE,
    FOREIGN KEY (service_id) REFERENCES services(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Follow-ups / recuperacion (motor diferenciador)
CREATE TABLE followups (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    contact_id BIGINT UNSIGNED NOT NULL,
    type ENUM('reminder','recovery','reactivation','review_request') NOT NULL,
    scheduled_for DATETIME NOT NULL,
    status ENUM('pending','sent','done','skipped') NOT NULL DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_due (status, scheduled_for),
    INDEX idx_tenant (tenant_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (contact_id) REFERENCES contacts(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Suscripciones (Stripe)
CREATE TABLE subscriptions (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NOT NULL,
    stripe_customer_id VARCHAR(64) NULL,
    stripe_subscription_id VARCHAR(64) NULL,
    tier ENUM('pro','business') NULL,
    status VARCHAR(32) NULL,
    current_period_end DATETIME NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uq_tenant (tenant_id),
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Log de eventos del agente (EVIDENCIA: agente operando en produccion)
CREATE TABLE agent_logs (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tenant_id BIGINT UNSIGNED NULL,
    type VARCHAR(48) NOT NULL,
    decision VARCHAR(255) NULL,
    ai_call TINYINT(1) NOT NULL DEFAULT 0,
    tokens INT UNSIGNED NULL,
    payload JSON NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_type_date (type, created_at),
    INDEX idx_tenant (tenant_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

---

## 7. Módulos MVP

1. **Onboarding agéntico** — el agente da de alta el negocio por WhatsApp: pide servicios/fotos/horarios, redacta la descripción de Google y se autoconfigura. El humano interviene solo como QA/excepción. Tablas: `tenants`, `users`, `vale_config`, `services`. Rol: owner / agente.
2. **Inbox / Conversaciones** — la IA atiende; el dueño puede aprobar/corregir y tomar el control **por WhatsApp**. Tablas: `contacts`, `conversations`, `messages`. Rutas: `/inbox`, webhook `/agent/whatsapp`. Roles: owner, staff.
3. **Booking (Google Calendar)** — Vale agenda leyendo/escribiendo en el Google Calendar del negocio (fuente de verdad). Tablas: `appointments`, `services`. Roles: owner, staff, (cliente vía chat).
4. **Follow-up & Recuperación + Decisión autónoma** — persigue no-shows y leads fríos; ofrece sola huecos/incentivos para llenar la agenda. Tablas: `followups`, `leads`. Cron: `/cron/followups`. Rol: sistema.
5. **Presencia Google** — perfil de Business Profile + landing generada. Tablas: `tenants` (`google_place_id`). Rol: owner / super-admin.
6. **Dashboard, Métricas & Modo Demo** — panel con métrica norte + evidencia (`agent_logs`); incluye un tenant **demo** público para que terceros prueben a Vale sin onboardear un negocio real. Tablas: `leads`, `appointments`, `agent_logs`, `tenants.is_demo`. Rutas: `/dashboard`, `/demo`. Roles: owner, staff.
7. **Billing** — Stripe suscripción + setup fee. Tablas: `subscriptions`. Rutas: `/billing`, webhook `/api/stripe`. Rol: owner.

---

## 8. Flujos críticos

```
Flujo 1: Cliente escribe y Vale lo atiende (core)
Trigger: cliente final manda WhatsApp al numero del negocio
1. Twilio dispara webhook -> Agente (Cloud Run)
2. Agente resuelve tenant y busca/crea contact + conversation (DB)
3. Agente arma contexto (vale_config + services + historial) y llama a Gemini
4. Gemini decide (consultar / cotizar / agendar) y, si corresponde, invoca
   una funcion via Function Calling (ej: crear_cita)
5. Agente ejecuta la funcion, guarda message + agent_log (ai_call=1, tokens)
6. Agente responde al cliente via Twilio (identificandose como asistente)
7. Si agenda -> escribe en Google Calendar + appointment + lead (booked)
8. Notifica al dueno
Resultado: cliente atendido y agendado sin humano
Errores: Gemini down -> encolar + avisar; sin slot -> ofrecer alternativas
```

```
Flujo 2: Recuperacion + decision autonoma (diferenciador)
Trigger: cron cada 15 min revisa followups pendientes
1. Cron toma followups con status=pending y scheduled_for <= ahora
2. Gemini arma el mensaje segun type (recovery/reminder/reactivation/review)
3. Si detecta huecos en la agenda, ofrece sola un incentivo para llenarlos
4. Envia via Twilio, marca followup=sent, agent_log
5. Si el cliente responde -> reabre conversation -> Flujo 1
Resultado: no-shows y leads frios vuelven a agendar
Errores: opt-out -> marcar contact.opted_out=1, no volver a contactar
```

```
Flujo 3: Onboarding agentico de un negocio
Trigger: el dueno inicia la conversacion de alta
1. Vale pregunta por WhatsApp: tipo de negocio, servicios, horarios, idioma
2. Agente crea tenant + user + vale_config + services
3. Gemini redacta la descripcion para Google
4. Conecta numero WhatsApp y Google Calendar al tenant
5. Vale queda live y manda un mensaje de prueba al dueno
Resultado: negocio operativo, configurado por la IA
Errores: dato faltante -> Vale repregunta; numero ya usado -> validar
```

```
Flujo 4: Presencia en Google
Trigger: el dueno pide aparecer en Google
1. Agente consulta/crea Google Business Profile -> guarda google_place_id
2. Gemini genera copy del perfil + de la landing
3. Deploy de landing en Firebase Hosting, linkeada al WhatsApp de Vale
Resultado: negocio en Maps con landing que captura por WhatsApp
Errores: verificacion de GBP requiere al dueno -> paso guiado
```

```
Flujo 5: Cobro
Trigger: fin de trial o alta directa
1. Frontend muestra tiers (Pro / Business) + setup fee
2. Stripe Checkout -> cliente paga (no se ingresan tarjetas a mano)
3. Webhook Stripe -> actualiza subscriptions + tenants.status=active
Resultado: tenant pago y activo
Errores: pago fallido -> status=past_due + recordatorio
```

---

## 9. UI/UX guidelines

*(Alimentado por el Brand Kit de Vale — ver `vale-brand-kit.md`.)*

### Paleta
| Uso | Color | Hex |
|-----|-------|-----|
| Primario (CTA) | Barro | `#A8331A` |
| Secundario (acento) | Oro | `#E0A33E` |
| Fondo claro | Crema | `#FBF6EE` |
| Fondo oscuro | Tierra | `#241E1A` |
| Texto | Tinta | `#221C18` |
| Éxito | Verde | `#1E7A4D` |
| Error | Rojo | `#C0392B` |

### Tipografía
- Headings: **Fraunces** (500/600/700).
- Body: **Hanken Grotesk** (400/500/600), base 16px.

### Componentes base
Botones (primario/outline/disabled), inputs con estados, cards de conversación, badge de estado (open/booked/lost), modal de cita, toggle de idioma EN/ES. Estados default/hover/disabled/error.

### Tono visual
Cálido y humano — "hospitalidad de barrio, ejecución profesional".

### Mobile-first
Sí. El dueño vive en el celular. Breakpoints: 360 / 768 / 1024.

---

## 10. Monetización

| Tier | Precio | Incluye | Límite | Pago |
|------|--------|---------|--------|------|
| Trial | $0 | Todo Pro por 7-14 días | 1 número | — |
| Pro | $149/mo | WhatsApp + web, agenda, follow-ups | Volumen base | Stripe |
| Business | $299/mo | WhatsApp + SMS + web, recuperación full, presencia Google | Volumen alto | Stripe |
| Setup | $99-199 (one-time) | Configuración asistida | — | Stripe |

- Default USD.
- Justificación: no-brainer contra answering service humano ($300-1500/mo) y contra el costo de leads perdidos. El setup fee acelera revenue y filtra serios.
- Prioridad: revenue recurrente de clientes arms-length (cuenta para viabilidad). El revenue de relaciones previas se reporta por separado.

---

## 11. Roadmap por sprints

Calzado al cierre del concurso (17 de agosto de 2026), con buffer final para video, narrativa y evidencia. Principio: **lanzar liviano temprano** — el tiempo en producción es evidencia.

### Sprint 0 — Provisión + piloto (30 May – 1 Jun)
**Objetivo**: infra lista y 1 negocio real atendido (piloto concierge).
**Deliverable**: subdominio arriba; Vale contestando el WhatsApp de 1 negocio.
**Tareas**: repo nuevo; Gemini API key; Cloud Run + Firebase; Twilio sandbox; Stripe test; conseguir 1 negocio piloto.
**Done**: un cliente real recibió respuesta vía el WhatsApp del negocio.

### Sprint 1 — Core inbox (2 – 8 Jun)
**Objetivo**: Vale responde sola por WhatsApp.
**Deliverable**: negocio real recibe respuestas automáticas, guardadas.
**Tareas**: schema base; auth dashboard; webhook Twilio→Cloud Run→Gemini→respuesta; multi-tenant; `agent_logs` instrumentado.
**Done**: un mensaje entrante genera respuesta y queda logueado.

### Sprint 2 — Function Calling + Booking (9 – 15 Jun)
**Objetivo**: Vale agenda sola en Google Calendar.
**Deliverable**: cita agendada por la IA visible en el dashboard. Empezar a capturar footage para el video.
**Tareas**: Function Calling; Google Calendar API; `appointments`, `leads`; dashboard con "citas agendadas/semana".
**Done**: Vale agenda una cita sola y aparece en el panel y en el calendario del dueño.

### Sprint 3 — Recuperación + Presencia + Demo (16 – 22 Jun)
**Objetivo**: motor diferenciador + visibilidad + acceso para jueces.
**Deliverable**: Vale persigue no-shows/leads fríos; negocio en Google; tenant demo público.
**Tareas**: `followups` + cron; oferta autónoma de huecos; Business Profile + landing; modo demo.
**Done**: un no-show recibe follow-up; el negocio aparece en Maps; cualquiera puede probar el demo.

### Sprint 4 — Billing + self-serve (23 – 29 Jun)
**Objetivo**: un negocio puede pagar y quedar live.
**Deliverable**: primer cliente pago arms-length.
**Tareas**: Stripe Checkout + webhook; `subscriptions`; tiers; pulido del onboarding agéntico.
**Done**: un negocio paga y Vale queda activo.

### Sprint 5 — Growth (30 Jun – 10 Ago)
**Objetivo**: usuarios reales + revenue mes a mes.
**Deliverable**: 10-30 negocios onboarded, revenue creciente, testimonios y evidencia.
**Tareas**: adquisición + outreach; iterar calidad de la IA; recolectar evidencia (revenue por mes, costos, marketing spend, logs, contactos de clientes con consentimiento).
**Done**: revenue arms-length documentado por mes + testimonios.

### Sprint 6 — Submission (11 – 17 Ago)
**Objetivo**: entregar al concurso.
**Deliverable**: submission completa antes del 17 Ago, 1pm PDT.
**Tareas**: video de 3 min (Vale decidiendo en producción); narrativa 500-1000 palabras; evidencia financiera y de usuarios; repo limpio compartido para testing/judging.
**Done**: submission enviada y verificada.

---

## 12. Riesgos técnicos

| Riesgo | Probabilidad | Impacto | Mitigación |
|--------|--------------|---------|------------|
| La IA alucina al agendar (hora/fecha/precio) | Media | Alto | Validación server-side de slots; confirmar antes de cerrar; control del dueño por WhatsApp |
| Aislamiento multi-tenant (fuga de datos) | Media | Crítico | `tenant_id` obligatorio + filtro en TODA query; tests de scoping |
| IA confirma sobre un horario que el dueño quería | Media | Alto | Control humano por WhatsApp; reglas de agenda configurables |
| Latencia de respuesta | Media | Medio | Modelo Flash; respuesta interina; timeouts |
| Opt-out / mensajes salientes | Media | Alto (legal) | Respetar STOP; `opted_out`; consentimiento en onboarding |
| Verificación Google Business Profile | Alta | Medio | Paso guiado; no prometer 100% automático |
| Jueces no pueden testear el producto | Media | Alto | Tenant demo público (`/demo`) sin onboarding |
| Dependencia externa cae (Gemini/Twilio) | Baja | Alto | Encolar + reintentar; avisar; degradar elegante |
| Escala 10x | Baja (en 90d) | Medio | Cloud Run autoscale; índices declarados |

---

## 13. Decisiones tomadas

**[29 May 2026] - Gemini con Function Calling como núcleo del agente.**
Por qué: el agente debe ejecutar acciones (agendar, actualizar perfil, recordar), no solo conversar — es la evidencia de "decisiones clave" del concurso.
Alternativas: agente solo conversacional (descartado: sería un contestador caro).

**[29 May 2026] - Onboarding agéntico, no manual.**
Por qué: la configuración manual haría que el producto parezca una agencia de servicios y debilitaría la operación AI-native. El agente configura; el humano es excepción/QA.
Alternativas: setup 100% humano (bueno para vender, malo para el criterio AI-native).

**[29 May 2026] - Google Calendar como fuente de verdad de la agenda.**
Por qué: resuelve el calendario real del dueño sin obligarlo a un dashboard nuevo y suma un producto Google nativo.
Alternativas: tabla interna como única verdad (descartada por fricción para el dueño).

**[29 May 2026] - Multi-tenant (shared DB con `tenant_id`).**
Por qué: SaaS con muchos negocios en una instalación; un deployment por cliente no escala en 90 días.
Alternativas: single-tenant (descartado: insostenible operativamente).

**[29 May 2026] - Arquitectura híbrida (agente en Cloud Run, dashboard/DB en cPanel/MySQL).**
Por qué: cumple el requisito de Google Cloud con el agente y mantiene un panel/DB simples y rápidos de operar.
Alternativas: stack 100% cloud-managed (descartado por timing de 90 días).

**[29 May 2026] - Lanzar liviano temprano (junio).**
Por qué: el tiempo en producción es evidencia de operación continua para los jueces.
Alternativas: launch completo en agosto (descartado: sin historial operativo).

---

## 14. Convenciones de código

- Naming: **snake_case** en DB y PHP, **camelCase** en JS.
- Estructura de carpetas:
```
/vale
  /public          (index.php, assets, widget.js)
  /app
    /controllers
    /models
    /services      (gemini.php, twilio.php, stripe.php, google.php)
    /views
  /agent           (servicio Cloud Run: webhook + Gemini + function calling)
  /cron            (followups.php, reminders.php)
  /config
  /docs
  SCHEMA.sql
  .htaccess
```
- Reglas duras del proyecto:
  - **No usar localStorage.**
  - **Clean URLs** vía `.htaccess`.
  - **Prepared statements siempre** (PDO).
  - **Escapar output** con `htmlspecialchars`.
  - `session_regenerate_id()` en login.
  - **`tenant_id` en toda query** de datos de negocio.
  - Secretos (API keys) en variables de entorno, nunca en el repo.
  - **Vale siempre se identifica como asistente** ante el cliente final.

---

## 15. Próximos pasos

1. **Provisión + piloto** — conseguir 1 negocio piloto y dejar a Vale atendiéndole el WhatsApp, mientras se crean Gemini API key, Cloud Run, Firebase, Twilio y Stripe (test) — Franco / esta semana (Sprint 0).
2. Confirmar dominio + handle y levantar el subdominio del producto — Franco / esta semana.
3. Crear el repo nuevo, cargar `SCHEMA.sql` y los design tokens del Brand Kit — Equipo / inicio Sprint 1.
4. Implementar el webhook del agente (Twilio → Cloud Run → Gemini → respuesta) — Equipo / Sprint 1.
5. Instrumentar `agent_logs` desde el día uno (evidencia de operación en producción) — Equipo / Sprint 1.

---

> **Nota de repo**: este documento conviene partirlo en `MASTER.md` + `SCHEMA.sql` + `ROADMAP.md` para el repositorio.
