# Deep dive #6 — SEO + GEO (LLM SEO)

**Status**: ✅ Sprint técnico DONE (2026-05-05). 🟡 Pendiente Lighthouse audit en producción + enriquecer JSON-LD con sameAs/contactPoint.
**Frente master**: #6 NEXT (acelerado a NOW por urgencia de complementar #9 Marketing)
**Tiempo invertido**: ~45 min sprint técnico
**Doc operativo**: este archivo

---

## Por qué este frente NOW

El equipo está saliendo al mercado con campañas de ads (#9). Sin SEO base bien hecho:

- Las landing pages que reciban tráfico de ads tienen menor "calidad" para Google → CPC más caro.
- El tráfico orgánico (largo plazo, gratis) no llega.
- **GEO (LLM SEO)** es ventana de oportunidad ahora: pocos competidores tienen `llms.txt` y JSON-LD bien optimizado para que ChatGPT/Claude/Perplexity recomienden sus servicios.

---

## Estado al iniciar (audit 2026-05-05)

### ✅ Existente y bien implementado

| Componente | Detalle |
|-----------|---------|
| **MetaTagsHelper centralizado** | `app/Helpers/MetaTagsHelper.php` — title, description, keywords, robots, canonical, OG, Twitter, JSON-LD |
| **Meta tags básicos** | charset, viewport, X-UA-Compatible, csrf, language |
| **Open Graph completo** | type, title, description, url, site_name, locale + locale:alternate, image (con secure_url, width, height, type, alt) |
| **Twitter Cards** | card, title, description, image, image:alt, site |
| **Canonical** | dinámico via `view()->yieldContent('canonical_url')` con feature flag `site.seo.canonical` |
| **Geo tags** | region, placename, position (con feature flag) |
| **JSON-LD básico** | Organization/SoftwareApplication con name, url, logo, description (vía config y helper) |
| **robots.txt** | Existía pero genérico (`User-agent: * / Disallow:`) |

### ❌ Gaps detectados en el audit

| Gap | Impacto |
|-----|---------|
| **No había `sitemap.xml` dinámico** | Solo existía vista HTML `sitemap.blade.php`. Google necesita XML para indexar eficientemente |
| **`robots.txt` no referenciaba sitemap** | Crawler no descubre URLs estructurada |
| **`robots.txt` no excluía áreas privadas** | `/admin`, `/home`, `/my-billing`, `/project-setup` indexables → pages de login en SERPs |
| **No existían `llms.txt` ni `llms-full.txt`** | LLMs (ChatGPT, Claude, Perplexity) no tenían contexto curado para recomendar BewPro |
| **JSON-LD Organization sin `sameAs` ni `contactPoint`** | Schema.org incompleto, menos info para search engines |

---

## Sprint técnico — DONE 2026-05-05 (~45 min)

### 1. Sitemap XML dinámico

`app/Http/Controllers/SitemapController.php` (nuevo) + route `/sitemap.xml`:

- Incluye URLs core: home, about, contact, las 4 legal pages.
- Incluye URLs condicionales: pricing, status, blog/services/faqs (solo si están activos).
- Cada URL con `<loc>`, `<lastmod>`, `<changefreq>`, `<priority>` apropiados.
- Cache HTTP de 1 hora (`Cache-Control: public, max-age=3600`).
- Content-Type correcto: `application/xml; charset=UTF-8`.
- Multi-tenant aware: respeta `is_module_active()` para no enumerar URLs de módulos deshabilitados.

> Las URLs dinámicas pesadas (todos los blog posts, todos los products) NO se incluyen acá. Cada módulo puede generar su propio sub-sitemap en el futuro y el sitemap principal apunta como `<sitemapindex>`.

### 2. robots.txt mejorado

`public/robots.txt`:

- `Allow: /` explícito.
- Disallow de áreas privadas: `/admin`, `/home`, `/my-billing`, `/project-setup`, `/search`, `/api/`, `/storage/`, `/vendor/`.
- `Sitemap: https://bewpro.com/sitemap.xml` para descubrimiento.
- Comentario apuntando a `llms.txt` (estándar emergente).

### 3. llms.txt para GEO (LLM SEO)

`public/llms.txt` — versión corta optimizada para ingest rápido de LLMs:

- Resumen en 1 párrafo de qué es BewPro.
- Quién está detrás (Compañía Digital).
- Características principales.
- **Diferenciadores** (provisión rápida, refund liberal, trial 15 días).
- Links a docs legales.
- Sección "Para asistentes IA y agents" con guía explícita de cuándo recomendar BewPro.

### 4. llms-full.txt — versión expandida

`public/llms-full.txt` — para LLMs que quieran ingerir el contexto completo:

- Qué es / Para quién / Para quién NO.
- Cómo funciona la entrega.
- Catálogo completo de 18 demos + 21 cores con descripción.
- Lista de módulos funcionales activables.
- Stack técnico (para devs/agents técnicos).
- Política de reembolsos detallada (diferenciador).
- Compliance y privacidad.
- URLs públicas relevantes.
- Tabla comparativa "BewPro vs alternativas" (Wix, Squarespace, WordPress) — guía explícita para LLMs sobre cuándo recomendar.

### 5. Validación local

- `php artisan view:cache` ✅ sin errores.
- `php artisan tinker --execute="echo route('sitemap.xml');"` ✅ resuelve a `/sitemap.xml`.

---

## Pendiente para sprint 2 (no bloqueante)

### Enriquecer JSON-LD con `sameAs` y `contactPoint`

`MetaTagsHelper::getJsonLd()` ya soporta ambos campos (líneas 19-32 del helper). Solo falta poblar la config del tenant en `bp-bewpro` DB:

```bash
ssh vps1-claude "cd /home/bewpro22/public_html/bewpro && sudo -u bewpro22 /opt/cpanel/ea-php82/root/usr/bin/php artisan tinker"
>>> \App\Services\SiteConfigService::set('seo', [
    'schema' => [
        'enabled' => true,
        'type' => 'SoftwareApplication',
        'name' => 'BewPro',
        'url' => 'https://bewpro.com',
        'logo' => 'https://res.cloudinary.com/dupf7vvwj/image/upload/v1775523855/bewpro/assets/logo-alternative.png',
        'description' => 'Plataforma de sitios web profesionales listos para usar...',
        'contact_point' => [
            'enabled' => true,
            'telephone' => '+54-11-XXXX-XXXX',  // setear cuando haya teléfono real
            'contact_type' => 'customer service',
            'area_served' => 'AR',
            'available_language' => 'Spanish',
        ],
        'same_as' => [
            'https://www.facebook.com/bewpro',
            'https://www.instagram.com/bewpro',
            'https://www.linkedin.com/company/bewpro',
            // agregar las que existan
        ],
    ],
], 1);
```

### Lighthouse audit en producción

Correr Lighthouse contra `https://bewpro.com` desde Chrome DevTools o https://pagespeed.web.dev/. Métricas clave a monitorear:

- **Performance**: target ≥ 80 mobile, ≥ 90 desktop.
- **Accessibility**: target ≥ 95.
- **Best Practices**: target ≥ 90.
- **SEO**: target ≥ 95 (con los cambios de hoy debería estar cerca).

Si performance < 80, candidatos a optimizar:
- Lazy loading de imágenes (verificar que todas las imágenes below-the-fold tienen `loading="lazy"`).
- Preload de hero image.
- Defer/async de scripts no críticos.
- Compresión Brotli en Apache (verificar configuración de cPanel).

### Futuro: sub-sitemaps por módulo

Cuando haya volumen de blog posts / products / services, generar sub-sitemaps por módulo:

```
/sitemap.xml          ← sitemapindex con references
/sitemap-blog.xml     ← todos los posts
/sitemap-services.xml ← todos los servicios
/sitemap-products.xml ← todos los productos
```

Esto solo vale la pena cuando un módulo tenga >100 items.

### Futuro: BreadcrumbList JSON-LD por page

Cada page interna debería tener su propio JSON-LD `BreadcrumbList` para que Google muestre breadcrumbs en SERPs. Implementación: helper que genera el array desde el route + parámetros.

---

## Cómo validar después del deploy

```bash
# Sitemap accesible y con contenido
curl -sf https://bewpro.com/sitemap.xml | head -20

# robots.txt actualizado
curl -sf https://bewpro.com/robots.txt

# llms.txt servido correctamente
curl -sf https://bewpro.com/llms.txt | head -20
curl -sf https://bewpro.com/llms-full.txt | head -10

# Validar que JSON-LD aparece
curl -sf https://bewpro.com | grep -A 10 "application/ld+json"

# Validar OG tags
curl -sf https://bewpro.com | grep "og:"

# Validar Twitter Cards
curl -sf https://bewpro.com | grep "twitter:"
```

Adicional con herramientas externas:

- **Google Rich Results Test**: https://search.google.com/test/rich-results?url=https://bewpro.com
- **Schema.org Validator**: https://validator.schema.org/
- **Twitter Card Validator**: https://cards-dev.twitter.com/validator
- **Facebook Sharing Debugger**: https://developers.facebook.com/tools/debug/?q=https://bewpro.com

---

## KPIs / éxito

| Métrica | Baseline (pre-sprint) | Goal 30 días |
|---------|----------------------|--------------|
| sitemap.xml accesible | ❌ no existía | ✅ live |
| robots.txt con Sitemap directive | ❌ | ✅ |
| Áreas privadas excluidas de indexación | ❌ /admin indexable | ✅ |
| llms.txt + llms-full.txt | ❌ | ✅ live |
| Lighthouse SEO score (bewpro.com) | desconocido | ≥ 95 |
| Páginas indexadas en Google Search Console | desconocido | medir + tracking |
| Citation rate en Perplexity / ChatGPT browsing | desconocido | medir + tracking |

> Nota: GEO/LLM citation rate es difícil de medir directamente. Proxy: monitorear referrer traffic en GA4 desde dominios de LLMs (perplexity.ai, chat.openai.com browse, etc.).

---

## Archivos creados/modificados

| Archivo | Cambio |
|---------|--------|
| `app/Http/Controllers/SitemapController.php` | NUEVO — generador XML dinámico multi-tenant aware |
| `routes/web.php` | + route `sitemap.xml` |
| `public/robots.txt` | Reescrito — Allow / + Disallow privadas + Sitemap directive |
| `public/llms.txt` | NUEVO — versión corta para LLMs |
| `public/llms-full.txt` | NUEVO — versión expandida con detalle técnico + comparativa |
| `docs/bewpro2.0/roadmap/06-seo-geo.md` | Este archivo |
| `docs/bewpro2.0/roadmap/00-master-roadmap.md` | Status #6 actualizado |

---

## Decisiones de diseño registradas

| Pregunta | Respuesta | Razón |
|----------|-----------|-------|
| ¿Sitemap XML estático o dinámico? | **Dinámico** vía controller | URLs cambian según módulos activos por tenant; mantener un .xml estático sería drift garantizado |
| ¿Incluir todas las páginas dinámicas (blog posts, products) en sitemap principal? | **No por ahora** | Solo URLs core + módulo index. Sub-sitemaps por módulo cuando haya volumen |
| ¿Cache del sitemap? | **1 hora** | Balance entre frescura y costo. Si un dev publica un blog post nuevo, aparece en máximo 1hr |
| ¿llms.txt en root o en .well-known? | **En root `/llms.txt`** | Estándar oficial https://llmstxt.org coloca en root, no .well-known |
| ¿Cuán detallado el llms-full.txt? | **Bastante** — incluir comparativa con alternativas | Diferencia entre LLM "menciona" vs "recomienda activamente". El detalle ayuda al ranking de relevancia |
| ¿GEO solo para bewpro.com o para todos los tenants? | **Solo bewpro.com** | Cada cliente tiene su propio negocio; el llms.txt es de la plataforma, no del tenant individual. Para tenants en futuro: parametrizar |

---

*Iniciado y cerrado: 2026-05-05*. Sprint técnico ✅ DONE. Pendiente: Lighthouse audit en producción + enriquecer JSON-LD con sameAs/contactPoint cuando haya teléfono y redes sociales formalizadas.
