# Contenido pilar para SEO (Track 3) Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Publicar 5 páginas pilar de contenido SEO en `credifygo.com` (español, Colombia-first, sin "pagadiario"/"gota a gota") que capturen demanda de búsqueda y conviertan a `/registro`, sobre un layout Blade compartido extraído de la landing.

**Architecture:** Se extrae el "chrome" hoy embebido en `welcome.blade.php` (877 líneas, standalone) a un layout compartido de 2 niveles — `layouts/public.blade.php` (head + GA + `@vite` + `<style>` + nav/footer) y `layouts/article.blade.php` (SEO por página + breadcrumb + FAQ + CTA desde datos del controlador). La landing se refactoriza para consumir `layouts.public`; las 5 páginas de contenido son vistas Blade finas que solo aportan la prosa (`@section('article')`). Un `ContentController` provee title/description/faqs/JSON-LD por página; el JSON-LD se arma como array PHP → `json_encode` (sin `@verbatim`, evita el bug de Blade). Verificación por `ContentPagesTest` (smoke + guard de marca) + render + screenshots.

**Tech Stack:** Laravel 13 / PHP 8.3, Blade (layouts anidados, componentes anónimos), Tailwind v4 (`@vite`), PHPUnit 11 (atributos). Deploy **full** (build + ship de assets, por el content-scan de Tailwind).

**Spec:** `docs/superpowers/specs/2026-07-30-seo-contenido-pilar-design.md`

**Gotchas (memoria del proyecto):**
- **Blade parser:** el JSON-LD va por `json_encode` de un array PHP; NO meter `@context`/`{{ }}` crudos. El copy no debe contener `@` ni `{{` sin escapar. (credify-blade-verbatim-gotcha)
- **Tailwind v4 content-scan:** las utilidades nuevas se purgan si el glob no cubre `resources/views/**`; verificar tras `npm run build`. (CLAUDE.md)
- **PHPStan preflight:** `phpstan analyse --level=5 app/` antes de push (el `ContentController` es código nuevo). (credify-ci-phpstan-preflight)
- **Tests:** comparten la BD dev `credify`, seguros por `DatabaseTransactions`. (credify-test-db)
- **Commits desde WSL** (`/var/www/html/credify`), no incluir `.claude/`. (credify-wsl-workflow)

---

## File Structure

```
resources/views/
  layouts/public.blade.php      CREATE  chrome: head + GA + @vite + <style> + <x-public-nav/> + @yield('content') + <x-public-footer/>
  layouts/article.blade.php     CREATE  @extends('layouts.public'); SEO + breadcrumb + @yield('article') + FAQ + CTA (desde $title/$description/$url/$faqs/$schema)
  components/public-nav.blade.php    CREATE  navbar (movido de welcome 258-289) + item "Recursos"
  components/public-footer.blade.php CREATE  footer (movido de welcome 837-857) + columna "Recursos"
  content/
    software-para-prestamos.blade.php               CREATE  #1
    software-de-cobranza.blade.php                  CREATE  #2
    gestion-de-cartera.blade.php                    CREATE  #3
    como-administrar-negocio-de-prestamos.blade.php CREATE  #4
    control-de-prestamos-excel.blade.php            CREATE  #5
  welcome.blade.php             MODIFY  pasa a @extends('layouts.public') (conserva su SEO + cuerpo + sales-bot)
app/Http/Controllers/ContentController.php  CREATE  5 métodos + helper seo()
routes/web.php                MODIFY  grupo de 5 rutas
public/sitemap.xml            MODIFY  +5 URLs
tests/Feature/ContentPagesTest.php  CREATE  smoke SEO + guard de marca
CHANGELOG.md                  MODIFY
```

---

### Task 1: Layout compartido + componentes nav/footer + refactor de la landing

Extrae el chrome de `welcome.blade.php` y hace que la landing lo consuma. Al terminar, la landing debe renderizar **idéntica**.

**Files:**
- Create: `resources/views/layouts/public.blade.php`
- Create: `resources/views/components/public-nav.blade.php`
- Create: `resources/views/components/public-footer.blade.php`
- Modify: `resources/views/welcome.blade.php`

- [ ] **Step 1: Crear el componente nav**

Mover **verbatim** el bloque `<header>…</header>` actual de `welcome.blade.php` (líneas **258-289**) a un componente anónimo. Créalo con ese contenido exacto (léelo del archivo; no lo reescribas de memoria):

`resources/views/components/public-nav.blade.php` = el `<header class="fixed …"> … </header>` tal cual está en welcome 258-289.

- [ ] **Step 2: Crear el componente footer**

Mover **verbatim** el bloque `<footer>…</footer>` actual (líneas **837-857**) a:

`resources/views/components/public-footer.blade.php` = el `<footer class="bg-slate-950 …"> … </footer>` tal cual.

- [ ] **Step 3: Crear el layout public**

`resources/views/layouts/public.blade.php`. Copia el `<head>` **compartido** de welcome (líneas 1-254) EXCEPTO las etiquetas SEO por página, que se reemplazan por slots. Estructura exacta:

```blade
<!DOCTYPE html>
<html lang="es" class="scroll-smooth">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-2S01G726KE"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());
        gtag('config', 'G-2S01G726KE');
    </script>

    <title>@yield('title', 'Credify GO! — Software para negocios de microcrédito en Colombia')</title>
    @yield('meta')
    @stack('jsonld')

    <meta name="theme-color" content="#04130e">
    <link rel="icon" type="image/svg+xml" href="/pwa-icons/icon-192.svg">
    <link rel="apple-touch-icon" href="/pwa-icons/icon-512.svg">

    @vite(['resources/css/app.css'])
    <style>
        {{-- Pega aquí, tal cual, el contenido del bloque <style> de welcome (líneas 120-253, sin las etiquetas <style>/</style>) --}}
    </style>
</head>
<body class="bg-[#04130e] text-slate-100 antialiased font-sans overflow-x-hidden">
<x-public-nav />

@yield('content')

<x-public-footer />
@stack('scripts')
</body>
</html>
```

Nota: el `<style>` (welcome 120-253) va **íntegro** en el layout (léelo del archivo y pégalo dentro del `<style>` del layout).

- [ ] **Step 4: Refactorizar welcome para usar el layout**

Reescribe `welcome.blade.php` para que sea:

```blade
@extends('layouts.public')

@section('title', 'Credify GO! — Digitaliza tu negocio de microcréditos hoy')

@section('meta')
    <meta name="description" content="Software para negocios de microcrédito y cobranza en Colombia: registra cobros desde el celular con o sin internet, controla tu cartera y entrega comprobantes digitales.">
    <link rel="canonical" href="https://credifygo.com/">
    <meta name="robots" content="index, follow, max-image-preview:large">

    <!-- Open Graph -->
    {{-- Mueve aquí las etiquetas OG + Twitter actuales de welcome (líneas ~14-30) tal cual --}}
@endsection

@push('jsonld')
    {{-- Mueve aquí los 3 bloques JSON-LD actuales de welcome (líneas 31-107) TAL CUAL, incluyendo su @verbatim / @endverbatim --}}
@endpush

@section('content')
    {{-- Mueve aquí el cuerpo actual de welcome: TODO lo que hay entre </header> (línea 289)
         y <footer> (línea 837), es decir el hero → … → banda CTA final (líneas 290-836) --}}

    @include('partials.sales-bot')
@endsection
```

Reglas de la mudanza:
- El `<head>` compartido, el `<header>`/nav, el `<footer>` y las etiquetas `<body>`/`</body>`/`</html>` YA NO van en welcome (los aporta el layout).
- Las OG/Twitter (welcome ~14-30) van a `@section('meta')`.
- Los 3 JSON-LD con su `@verbatim` (welcome 31-107) van a `@push('jsonld')` **sin cambios**.
- El cuerpo (290-836) + `@include('partials.sales-bot')` van a `@section('content')`.

- [ ] **Step 5: Build + verificar que la landing renderiza idéntica**

```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in'"
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && php artisan test --filter=ExampleTest 2>&1 | grep -iE 'Tests:|PASS|FAIL|ParseError'"
```
Expected: build sin errores; `ExampleTest` **2 passed** (la landing renderiza sin ParseError).

Render + screenshot para comparar con la landing en vivo (nav, hero, secciones, footer, sales-bot deben verse iguales):
```bash
wsl bash -lc "cd /var/www/html/credify && (php artisan serve --port=8790 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8790/ | grep -oc 'application/ld+json' ; pkill -f 'artisan serve'"
```
Expected: `3` (los 3 JSON-LD siguen presentes). Abrir el preview del navegador en `/` y confirmar visualmente que es idéntica a producción (375/768/1280).

- [ ] **Step 6: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/layouts resources/views/components resources/views/welcome.blade.php && git commit -m 'refactor(landing): extraer layout público + componentes nav/footer'"
```

---

### Task 2: Article layout + ContentController + rutas + test + 5 páginas (skeleton SEO-completo)

Crea la infraestructura de contenido y deja las 5 páginas **vivas, indexables y con SEO completo** (title/description/canonical/OG/JSON-LD/FAQ), con un cuerpo inicial breve. Las Tasks 3-7 expanden la prosa.

**Files:**
- Create: `resources/views/layouts/article.blade.php`
- Create: `app/Http/Controllers/ContentController.php`
- Create: `tests/Feature/ContentPagesTest.php`
- Create: los 5 `resources/views/content/*.blade.php`
- Modify: `routes/web.php`

- [ ] **Step 1: Escribir el test primero (TDD)**

`tests/Feature/ContentPagesTest.php`:

```php
<?php

namespace Tests\Feature;

use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;

class ContentPagesTest extends TestCase
{
    /** @return array<int, array{0: string}> */
    public static function contentRoutes(): array
    {
        return [
            ['/software-para-prestamos'],
            ['/software-de-cobranza'],
            ['/gestion-de-cartera'],
            ['/como-administrar-negocio-de-prestamos'],
            ['/control-de-prestamos-excel'],
        ];
    }

    #[DataProvider('contentRoutes')]
    public function test_content_page_renders_with_seo(string $path): void
    {
        $res = $this->get($path);
        $res->assertOk();
        $res->assertSee('rel="canonical"', false);
        $res->assertSee('application/ld+json', false);
        $res->assertSee('href="https://credifygo.com'.$path.'"', false); // canonical self
    }

    #[DataProvider('contentRoutes')]
    public function test_content_page_has_no_forbidden_brand_terms(string $path): void
    {
        $html = strtolower((string) $this->get($path)->getContent());
        $this->assertStringNotContainsString('pagadiario', $html);
        $this->assertStringNotContainsString('gota a gota', $html);
    }

    public function test_landing_has_no_forbidden_brand_terms(): void
    {
        $html = strtolower((string) $this->get('/')->getContent());
        $this->assertStringNotContainsString('pagadiario', $html);
        $this->assertStringNotContainsString('gota a gota', $html);
    }
}
```

- [ ] **Step 2: Correr el test y verificar que falla**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL|404|not found' | head"
```
Expected: FAIL (las rutas dan 404 — no existen aún).

- [ ] **Step 3: Crear el ContentController**

`app/Http/Controllers/ContentController.php`. Cada método pasa `title/description/url/faqs/schema` a su vista. El helper `seo()` arma el JSON-LD (`@graph` con `Article` + `BreadcrumbList` + `FAQPage`) como array PHP.

```php
<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\View\View;

class ContentController extends Controller
{
    public function softwarePrestamos(): View
    {
        return view('content.software-para-prestamos', $this->seo(
            slug: 'software-para-prestamos',
            title: 'Software para préstamos y microcrédito | Credify GO!',
            heading: 'Software para préstamos y microcrédito',
            description: 'Software para prestamistas: crea créditos, registra abonos desde el celular con o sin internet y controla tu cartera y la mora. Prueba Credify GO! gratis 14 días.',
            faqs: [
                ['q' => '¿Necesito internet para registrar los pagos?', 'a' => 'No. La app funciona sin conexión: registras los abonos en la calle y se sincronizan solos cuando el celular vuelve a tener señal.'],
                ['q' => '¿Sirve para cualquier tipo de crédito?', 'a' => 'Sí. Configuras el monto, el interés, el número de cuotas y la periodicidad (diaria, semanal, quincenal o mensual) según cómo prestes.'],
                ['q' => '¿Puedo tener varios cobradores?', 'a' => 'Sí. Creas usuarios para dueño, supervisor y cobradores, cada uno con permisos y con acceso solo a lo que le corresponde.'],
                ['q' => '¿Cada negocio ve solo su información?', 'a' => 'Sí. Los datos de cada negocio están aislados; nadie ve la cartera ni los clientes de otro.'],
            ],
        ));
    }

    public function softwareCobranza(): View
    {
        return view('content.software-de-cobranza', $this->seo(
            slug: 'software-de-cobranza',
            title: 'Software de cobranza y recaudo · App para cobradores | Credify GO!',
            heading: 'Software de cobranza y recaudo',
            description: 'App de cobranza para tu equipo: la ruta de cobros del día, registro de abonos sin internet y comprobante al instante. Controla el recaudo desde el celular. Prueba gratis.',
            faqs: [
                ['q' => '¿El cobrador puede trabajar sin señal?', 'a' => 'Sí. Registra los abonos sin conexión y todo se sincroniza al reconectar, sin perder ningún dato.'],
                ['q' => '¿El cobrador ve toda la cartera o solo su ruta?', 'a' => 'Solo lo suyo: cada cobrador ve únicamente los clientes y cobros de su ruta.'],
                ['q' => '¿Cómo entrego el comprobante al cliente?', 'a' => 'La app genera un comprobante digital que puedes compartir al instante, por ejemplo por WhatsApp.'],
                ['q' => '¿Puedo ver cuánto recaudó cada cobrador hoy?', 'a' => 'Sí. El dueño y el supervisor ven el recaudo del día por cobrador en tiempo real.'],
            ],
        ));
    }

    public function gestionCartera(): View
    {
        return view('content.gestion-de-cartera', $this->seo(
            slug: 'gestion-de-cartera',
            title: 'Gestión y control de cartera de créditos | Credify GO!',
            heading: 'Gestión y control de cartera de créditos',
            description: 'Controla tu cartera de créditos: saldo por cobrar, mora y recaudo del día en un tablero claro. Toma decisiones con datos. Prueba Credify GO! gratis 14 días.',
            faqs: [
                ['q' => '¿Qué indicadores de cartera puedo ver?', 'a' => 'Saldo por cobrar, recaudo del día, cartera en mora, cartera vencida y la evolución de tu patrimonio.'],
                ['q' => '¿Cómo sé qué créditos están en mora?', 'a' => 'La app marca automáticamente los créditos atrasados y te alerta para que actúes a tiempo.'],
                ['q' => '¿Puedo ver la evolución semana a semana?', 'a' => 'Sí. Con los cortes diarios ves si tu cartera y tu mora mejoran o empeoran frente a la semana anterior.'],
                ['q' => '¿Funciona si tengo cientos de créditos?', 'a' => 'Sí. El tablero resume la cartera completa sin importar cuántos créditos manejes.'],
            ],
        ));
    }

    public function comoAdministrar(): View
    {
        return view('content.como-administrar-negocio-de-prestamos', $this->seo(
            slug: 'como-administrar-negocio-de-prestamos',
            title: 'Cómo administrar un negocio de préstamos: guía práctica | Credify GO!',
            heading: 'Cómo administrar un negocio de préstamos',
            description: 'Guía práctica para administrar un negocio de préstamos: organiza créditos y cobros, controla la mora, cuida tu caja y crece sin perder el control.',
            faqs: [
                ['q' => '¿Puedo empezar con un cuaderno o Excel?', 'a' => 'Al principio sí, pero se queda corto rápido: sin control de mora, sin app móvil y con riesgo de errores. Puedes dar el salto cuando el volumen lo pida.'],
                ['q' => '¿Cómo controlo la mora?', 'a' => 'Registrando cada crédito y su fecha de pago, y revisando a diario quién se atrasó para gestionarlo de inmediato.'],
                ['q' => '¿Cómo sé si de verdad estoy ganando?', 'a' => 'Separando el recaudo (lo que entra) de la ganancia real (intereses menos gastos y cartera perdida). No es lo mismo.'],
                ['q' => '¿Cuándo conviene usar un software?', 'a' => 'Cuando tienes varios clientes o cobradores y el control manual empieza a fallar: ahí un software te da orden y visibilidad.'],
            ],
        ));
    }

    public function excel(): View
    {
        return view('content.control-de-prestamos-excel', $this->seo(
            slug: 'control-de-prestamos-excel',
            title: '¿Llevas tus préstamos en Excel? Pásate a una app | Credify GO!',
            heading: 'Del Excel a una app para tus préstamos',
            description: 'Llevar préstamos en Excel se queda corto: sin app móvil, sin control de mora y con errores. Descubre la alternativa para gestionar créditos y cobros. Prueba gratis.',
            faqs: [
                ['q' => '¿Puedo pasar mis datos del Excel?', 'a' => 'Empezar es rápido: creas tus clientes y créditos activos en pocos minutos y sigues desde ahí, ahora con app móvil y control de mora.'],
                ['q' => '¿Es más caro que Excel?', 'a' => 'Puedes probarlo gratis 14 días. Después eliges un plan según tu tamaño; lo que ahorras en errores y tiempo lo compensa.'],
                ['q' => '¿Necesito saber de tecnología?', 'a' => 'No. Está pensada para usarse desde el celular, sin conocimientos técnicos.'],
                ['q' => '¿Funciona en el celular?', 'a' => 'Sí. Es una app que funciona en el celular incluso sin internet, algo que una hoja de Excel no te da.'],
            ],
        ));
    }

    /**
     * @param  list<array{q: string, a: string}>  $faqs
     * @return array{title: string, description: string, heading: string, url: string, faqs: list<array{q: string, a: string}>, schema: array<string, mixed>}
     */
    private function seo(string $slug, string $title, string $heading, string $description, array $faqs): array
    {
        $url = 'https://credifygo.com/'.$slug;

        $graph = [
            [
                '@type' => 'Article',
                'headline' => $heading,
                'description' => $description,
                'inLanguage' => 'es',
                'mainEntityOfPage' => $url,
                'image' => 'https://credifygo.com/og-image.png',
                'author' => ['@type' => 'Organization', 'name' => 'Credify GO!'],
                'publisher' => [
                    '@type' => 'Organization',
                    'name' => 'Credify GO!',
                    'logo' => ['@type' => 'ImageObject', 'url' => 'https://credifygo.com/og-image.png'],
                ],
            ],
            [
                '@type' => 'BreadcrumbList',
                'itemListElement' => [
                    ['@type' => 'ListItem', 'position' => 1, 'name' => 'Inicio', 'item' => 'https://credifygo.com/'],
                    ['@type' => 'ListItem', 'position' => 2, 'name' => $heading, 'item' => $url],
                ],
            ],
            [
                '@type' => 'FAQPage',
                'mainEntity' => array_map(fn (array $f) => [
                    '@type' => 'Question',
                    'name' => $f['q'],
                    'acceptedAnswer' => ['@type' => 'Answer', 'text' => $f['a']],
                ], $faqs),
            ],
        ];

        $schema = ['@context' => 'https://schema.org', '@graph' => $graph];

        return compact('title', 'description', 'heading', 'url', 'faqs', 'schema');
    }
}
```

- [ ] **Step 4: Registrar las rutas**

En `routes/web.php`, **antes** del grupo `Route::prefix('pwa')` (para no ser absorbidas por el catch-all), añade:

```php
use App\Http\Controllers\ContentController;

/*
| Páginas pilar de contenido SEO (Track 3). Slugs keyword-forward.
*/
Route::controller(ContentController::class)->group(function () {
    Route::get('/software-para-prestamos', 'softwarePrestamos')->name('content.software-prestamos');
    Route::get('/software-de-cobranza', 'softwareCobranza')->name('content.software-cobranza');
    Route::get('/gestion-de-cartera', 'gestionCartera')->name('content.gestion-cartera');
    Route::get('/como-administrar-negocio-de-prestamos', 'comoAdministrar')->name('content.como-administrar');
    Route::get('/control-de-prestamos-excel', 'excel')->name('content.excel');
});
```
(añade el `use` arriba con los demás imports.)

- [ ] **Step 5: Crear el article layout**

`resources/views/layouts/article.blade.php`. Anida sobre `public`, arma SEO/breadcrumb/FAQ/CTA desde las variables del controlador. `@yield('article')` recibe la prosa.

```blade
@extends('layouts.public')

@section('title', $title)

@section('meta')
    <meta name="description" content="{{ $description }}">
    <link rel="canonical" href="{{ $url }}">
    <meta name="robots" content="index, follow, max-image-preview:large">

    <meta property="og:type" content="article">
    <meta property="og:site_name" content="Credify GO!">
    <meta property="og:title" content="{{ $title }}">
    <meta property="og:description" content="{{ $description }}">
    <meta property="og:url" content="{{ $url }}">
    <meta property="og:image" content="https://credifygo.com/og-image.png">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="{{ $title }}">
    <meta name="twitter:description" content="{{ $description }}">
    <meta name="twitter:image" content="https://credifygo.com/og-image.png">
@endsection

@push('jsonld')
    <script type="application/ld+json">{!! json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) !!}</script>
@endpush

@section('content')
    <main class="max-w-3xl mx-auto px-4 pt-28 pb-20">
        <nav aria-label="Ruta de navegación" class="text-sm text-slate-400 mb-8">
            <a href="/" class="hover:text-emerald-400">Inicio</a>
            <span class="mx-2 text-slate-600">›</span>
            <span class="text-slate-300">{{ $heading }}</span>
        </nav>

        <article class="prose-invert">
            <h1 class="text-4xl md:text-5xl font-extrabold tracking-tight text-white leading-tight mb-6">{{ $heading }}</h1>
            @yield('article')
        </article>

        {{-- FAQ (rich snippet vía FAQPage schema) --}}
        <section class="mt-16">
            <h2 class="text-2xl md:text-3xl font-extrabold tracking-tight text-white mb-6">Preguntas frecuentes</h2>
            <div class="space-y-4">
                @foreach ($faqs as $faq)
                    <div class="bg-white/[0.04] border border-white/10 rounded-2xl p-5">
                        <h3 class="font-semibold text-white mb-2">{{ $faq['q'] }}</h3>
                        <p class="text-slate-300 leading-relaxed">{{ $faq['a'] }}</p>
                    </div>
                @endforeach
            </div>
        </section>

        {{-- CTA --}}
        <section class="mt-16 text-center bg-gradient-to-br from-emerald-600 to-emerald-800 rounded-3xl p-10">
            <h2 class="text-2xl md:text-3xl font-extrabold text-white mb-3">Pon en cintura tu negocio de préstamos</h2>
            <p class="text-emerald-50 mb-6">Pruébalo gratis 14 días. Sin tarjeta, sin instalar nada.</p>
            <a href="/registro" class="inline-block bg-white text-emerald-800 font-bold px-8 py-4 rounded-xl hover:bg-emerald-50 transition-colors">Empieza gratis</a>
        </section>
    </main>
@endsection
```

- [ ] **Step 6: Crear las 5 vistas de contenido (skeleton)**

Cada una `@extends('layouts.article')` y aporta una intro real breve en `@section('article')`. Ejemplo para `resources/views/content/software-para-prestamos.blade.php`:

```blade
@extends('layouts.article')

@section('article')
    <p class="text-lg text-slate-300 leading-relaxed mb-6">
        Si prestas dinero, sabes que el problema no es prestar: es llevar el control. Un <strong>software para préstamos</strong> te deja crear cada crédito, registrar los abonos desde el celular y ver tu cartera al día, sin cuadernos ni hojas sueltas.
    </p>
@endsection
```

Crea las otras 4 con la misma estructura y una intro real de 2-3 frases acorde a su tema (se expanden en Tasks 3-7):
- `content/software-de-cobranza.blade.php`
- `content/gestion-de-cartera.blade.php`
- `content/como-administrar-negocio-de-prestamos.blade.php`
- `content/control-de-prestamos-excel.blade.php`

- [ ] **Step 7: Correr el test y verificar que pasa**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|PASS|FAIL'"
```
Expected: **PASS** (11 aserciones: 5 SEO + 5 marca + 1 landing).

- [ ] **Step 8: PHPStan + Pint**

```bash
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/Http/Controllers/ContentController.php 2>&1 | tail -5 && vendor/bin/pint app/Http/Controllers/ContentController.php 2>&1 | tail -2"
```
Expected: PHPStan sin errores; Pint OK.

- [ ] **Step 9: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/layouts/article.blade.php resources/views/content app/Http/Controllers/ContentController.php routes/web.php tests/Feature/ContentPagesTest.php && git commit -m 'feat(content): infra de paginas pilar + SEO + test (5 paginas skeleton)'"
```

---

### Task 3: Contenido página #1 — Software para préstamos

Expande `content/software-para-prestamos.blade.php` a ~1.200-1.600 palabras. Keyword primaria: *software para préstamos / prestamistas*. Tono: comercial, claro, práctico.

**Files:**
- Modify: `resources/views/content/software-para-prestamos.blade.php`

- [ ] **Step 1: Escribir el cuerpo**

Dentro de `@section('article')`, tras la intro, redacta estas secciones (H2 = `<h2 class="text-2xl md:text-3xl font-extrabold tracking-tight text-white mt-12 mb-4">`; párrafos = `<p class="text-slate-300 leading-relaxed mb-4">`; listas = `<ul class="list-disc pl-6 text-slate-300 space-y-2 mb-4">`):

- **¿Qué es un software para préstamos y por qué lo necesitas?** — el dolor del control manual (cuaderno/Excel), qué resuelve una herramienta dedicada.
- **Crea y administra tus créditos en minutos** — monto, interés, número de cuotas, periodicidad (diaria/semanal/quincenal/mensual).
- **Registra los abonos desde el celular, con o sin internet** — el diferenciador offline; sincroniza al reconectar.
- **Controla tu cartera y la mora en tiempo real** — saldo por cobrar, recaudo del día, alertas de atraso. Enlace contextual a **/gestion-de-cartera** (`<a href="/gestion-de-cartera" class="text-emerald-400 hover:underline">controlar tu cartera</a>`).
- **Comprobantes digitales que dan confianza** — recibo compartible por WhatsApp.
- **Tu equipo, con permisos** — dueño/supervisor/cobrador; cada uno ve lo suyo. Enlace contextual a **/software-de-cobranza** (workflow del cobrador).
- **¿Para quién es Credify GO!?** — prestamistas independientes, negocios de microcrédito, quien presta a diario/semana en Colombia (y LatAm).

Ejemplos con montos en **COP** (p. ej. "un crédito de $500.000 a 20 cuotas"). Sin "pagadiario"/"gota a gota". No repetir la FAQ (ya la renderiza el layout).

- [ ] **Step 2: Verificar render + longitud + enlaces**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8791 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8791/software-para-prestamos | grep -oE '/gestion-de-cartera|/software-de-cobranza|/registro' | sort -u ; echo '--- palabras ---'; curl -s http://127.0.0.1:8791/software-para-prestamos | sed 's/<[^>]*>//g' | wc -w ; pkill -f 'artisan serve'"
```
Expected: aparecen los 3 enlaces internos; conteo de palabras > 900.

- [ ] **Step 3: Correr el test de marca**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL'"
```
Expected: PASS.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/content/software-para-prestamos.blade.php && git commit -m 'content(#1): software para prestamos (pagina pilar completa)'"
```

---

### Task 4: Contenido página #2 — Software de cobranza

Expande `content/software-de-cobranza.blade.php` a ~1.100-1.500 palabras. Keyword: *software de cobranza / app para cobradores*. Ángulo: el workflow del cobrador en la calle.

**Files:**
- Modify: `resources/views/content/software-de-cobranza.blade.php`

- [ ] **Step 1: Escribir el cuerpo** (misma convención de clases que Task 3)

Secciones H2:
- **El cobro en la calle sin control** — cuaderno, efectivo, el dueño sin visibilidad hasta la noche.
- **La ruta de cobros del día en el celular** — el cobrador ve a quién visitar y cuánto.
- **Registrar el abono en segundos, aunque no haya señal** — offline + sync.
- **Comprobante digital inmediato** — se lo mandas al cliente al momento.
- **El dueño ve el recaudo en tiempo real** — sin esperar el cuadre nocturno. Enlace a **/gestion-de-cartera**.
- **Cada cobrador ve solo su ruta** — permisos por rol. Enlace a **/software-para-prestamos**.
- **Cuadre de caja sin cuentas a mano** — cuánto entró, cuánto entrega.

Ejemplos COP, Colombia-first. Enlace a **/registro** en el cuerpo además del CTA del layout.

- [ ] **Step 2: Verificar render + longitud + enlaces**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8792 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8792/software-de-cobranza | grep -oE '/gestion-de-cartera|/software-para-prestamos|/registro' | sort -u ; curl -s http://127.0.0.1:8792/software-de-cobranza | sed 's/<[^>]*>//g' | wc -w ; pkill -f 'artisan serve'"
```
Expected: 3 enlaces; palabras > 850.

- [ ] **Step 3: Test de marca**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL'"
```
Expected: PASS.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/content/software-de-cobranza.blade.php && git commit -m 'content(#2): software de cobranza (pagina pilar completa)'"
```

---

### Task 5: Contenido página #3 — Gestión de cartera

Expande `content/gestion-de-cartera.blade.php` a ~1.100-1.500 palabras. Keyword: *gestión / control de cartera de créditos*. Ángulo: puente comercial-informacional.

**Files:**
- Modify: `resources/views/content/gestion-de-cartera.blade.php`

- [ ] **Step 1: Escribir el cuerpo** (misma convención)

Secciones H2:
- **Qué es la cartera y por qué controlarla bien** — el dinero en la calle es tu activo.
- **Los indicadores que de verdad importan** — por cobrar, recaudado hoy, mora, cartera vencida, patrimonio.
- **Detecta la mora a tiempo** — alertas de atraso; actuar temprano.
- **Cartera vencida: qué hacer** — priorizar, renegociar, no dejar crecer.
- **¿Tu cartera crece sana?** — tendencia semana a semana (cortes diarios).
- **Cada rol ve lo que le corresponde** — dueño el P&L, cobrador su ruta. Enlaces a **/software-para-prestamos** y **/como-administrar-negocio-de-prestamos**.

Ejemplos COP. Enlace a **/registro** en el cuerpo.

- [ ] **Step 2: Verificar render + longitud + enlaces**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8793 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8793/gestion-de-cartera | grep -oE '/software-para-prestamos|/como-administrar-negocio-de-prestamos|/registro' | sort -u ; curl -s http://127.0.0.1:8793/gestion-de-cartera | sed 's/<[^>]*>//g' | wc -w ; pkill -f 'artisan serve'"
```
Expected: 3 enlaces; palabras > 850.

- [ ] **Step 3: Test de marca**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL'"
```
Expected: PASS.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/content/gestion-de-cartera.blade.php && git commit -m 'content(#3): gestion de cartera (pagina pilar completa)'"
```

---

### Task 6: Contenido página #4 — Cómo administrar un negocio de préstamos

Expande `content/como-administrar-negocio-de-prestamos.blade.php` a ~1.400-1.800 palabras. Keyword: *cómo administrar un negocio de préstamos*. Ángulo: **guía práctica** (informacional, menos vendedor), es el imán de tráfico top-funnel.

**Files:**
- Modify: `resources/views/content/como-administrar-negocio-de-prestamos.blade.php`

- [ ] **Step 1: Escribir el cuerpo** (misma convención; tono de guía numerada)

Secciones H2 (pasos):
- **1. Define reglas claras** — montos, plazos, interés, periodicidad; escríbelas.
- **2. Lleva un registro ordenado de cada crédito** — por qué el cuaderno/Excel falla al crecer. Enlace a **/control-de-prestamos-excel**.
- **3. Organiza el cobro** — frecuencia, rutas, quién cobra.
- **4. Vigila la mora desde el primer día** — el atraso pequeño se vuelve pérdida.
- **5. Cuida tu caja y tu patrimonio** — recaudo ≠ ganancia; separa gastos. Enlace a **/gestion-de-cartera**.
- **6. Delega con control** — equipo, permisos, cada uno ve lo suyo.
- **7. Escala con herramientas** — cuándo dar el salto a un software. Enlace a **/software-para-prestamos**.

Cierre suave hacia `/registro`. Ejemplos COP, Colombia-first, LatAm-friendly.

- [ ] **Step 2: Verificar render + longitud + enlaces**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8794 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8794/como-administrar-negocio-de-prestamos | grep -oE '/control-de-prestamos-excel|/gestion-de-cartera|/software-para-prestamos|/registro' | sort -u ; curl -s http://127.0.0.1:8794/como-administrar-negocio-de-prestamos | sed 's/<[^>]*>//g' | wc -w ; pkill -f 'artisan serve'"
```
Expected: 4 enlaces; palabras > 1100.

- [ ] **Step 3: Test de marca**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL'"
```
Expected: PASS.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/content/como-administrar-negocio-de-prestamos.blade.php && git commit -m 'content(#4): como administrar un negocio de prestamos (guia)'"
```

---

### Task 7: Contenido página #5 — Del Excel a una app

Expande `content/control-de-prestamos-excel.blade.php` a ~1.100-1.500 palabras. Keyword: *control de préstamos en Excel / plantilla*. Ángulo: comparación, alta conversión (captura al que usa Excel).

**Files:**
- Modify: `resources/views/content/control-de-prestamos-excel.blade.php`

- [ ] **Step 1: Escribir el cuerpo** (misma convención; incluye una tabla comparativa)

Secciones H2:
- **Excel es un buen comienzo… hasta que deja de serlo** — reconocer su valor inicial.
- **Los 5 problemas de llevar préstamos en Excel** — (1) no lo llevas al celular en la calle, (2) no controla la mora solo, (3) errores de fórmula/dedo, (4) un solo usuario / se rompe al compartir, (5) sin respaldo → un archivo perdido es tu negocio perdido.
- **Qué gana tu negocio con una app dedicada** — móvil, offline, mora automática, multiusuario con permisos, respaldo en la nube. Enlace a **/software-para-prestamos**.
- **Excel vs. Credify GO! (comparación)** — tabla:

```blade
<div class="overflow-x-auto my-6">
  <table class="w-full text-left text-slate-300 border border-white/10 rounded-xl">
    <thead class="bg-white/[0.04] text-white">
      <tr><th class="p-3">&nbsp;</th><th class="p-3">Excel</th><th class="p-3">Credify GO!</th></tr>
    </thead>
    <tbody>
      {{-- filas: Uso en el celular, Registro sin internet, Control de mora, Varios cobradores, Comprobante al cliente, Respaldo automático --}}
    </tbody>
  </table>
</div>
```
Rellena 6 filas (Excel: ✗/limitado; Credify GO!: ✓ con detalle).

- **"Pero ya tengo todo en mi Excel"** — empezar es rápido; das el salto sin drama. Enlace a **/como-administrar-negocio-de-prestamos**.

Cierre a `/registro`. Ejemplos COP. Sin "pagadiario"/"gota a gota".

- [ ] **Step 2: Verificar render + longitud + enlaces**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8795 >/dev/null 2>&1 &) ; sleep 3 ; curl -s http://127.0.0.1:8795/control-de-prestamos-excel | grep -oE '/software-para-prestamos|/como-administrar-negocio-de-prestamos|/registro' | sort -u ; curl -s http://127.0.0.1:8795/control-de-prestamos-excel | sed 's/<[^>]*>//g' | wc -w ; pkill -f 'artisan serve'"
```
Expected: 3 enlaces; palabras > 850.

- [ ] **Step 3: Test de marca**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=ContentPagesTest 2>&1 | grep -iE 'Tests:|FAIL'"
```
Expected: PASS.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/content/control-de-prestamos-excel.blade.php && git commit -m 'content(#5): del Excel a una app (pagina pilar completa)'"
```

---

### Task 8: Nav "Recursos" + footer "Recursos" + sitemap

Ahora que las 5 páginas existen, exponerlas en el nav y footer compartidos (mejora crawl + reparte autoridad) y añadirlas al sitemap.

**Files:**
- Modify: `resources/views/components/public-nav.blade.php`
- Modify: `resources/views/components/public-footer.blade.php`
- Modify: `public/sitemap.xml`

- [ ] **Step 1: Añadir "Recursos" al nav**

En `components/public-nav.blade.php`, en el grupo de enlaces de escritorio (junto a los ítems existentes tipo "Precios"/"FAQ"), añade un dropdown "Recursos". Patrón (ajusta las clases al estilo del nav existente):

```blade
<div class="relative group hidden md:block">
    <button class="text-slate-300 hover:text-white transition-colors">Recursos</button>
    <div class="absolute left-0 mt-2 w-72 rounded-2xl bg-[#0b1f17] border border-white/10 shadow-xl p-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition">
        <a href="/software-para-prestamos" class="block px-4 py-2 rounded-lg text-slate-300 hover:bg-white/5 hover:text-white">Software para préstamos</a>
        <a href="/software-de-cobranza" class="block px-4 py-2 rounded-lg text-slate-300 hover:bg-white/5 hover:text-white">Software de cobranza</a>
        <a href="/gestion-de-cartera" class="block px-4 py-2 rounded-lg text-slate-300 hover:bg-white/5 hover:text-white">Gestión de cartera</a>
        <a href="/como-administrar-negocio-de-prestamos" class="block px-4 py-2 rounded-lg text-slate-300 hover:bg-white/5 hover:text-white">Cómo administrar un negocio de préstamos</a>
        <a href="/control-de-prestamos-excel" class="block px-4 py-2 rounded-lg text-slate-300 hover:bg-white/5 hover:text-white">Del Excel a una app</a>
    </div>
</div>
```

- [ ] **Step 2: Añadir columna "Recursos" al footer**

En `components/public-footer.blade.php`, añade una columna/lista con los 5 enlaces (mismo texto y hrefs que el Step 1), con el estilo de enlaces del footer existente.

- [ ] **Step 3: Añadir las 5 URLs al sitemap**

En `public/sitemap.xml`, antes de `</urlset>`, añade una entrada por página:

```xml
    <url>
        <loc>https://credifygo.com/software-para-prestamos</loc>
        <lastmod>2026-07-30</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
    <url>
        <loc>https://credifygo.com/software-de-cobranza</loc>
        <lastmod>2026-07-30</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
    <url>
        <loc>https://credifygo.com/gestion-de-cartera</loc>
        <lastmod>2026-07-30</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
    <url>
        <loc>https://credifygo.com/como-administrar-negocio-de-prestamos</loc>
        <lastmod>2026-07-30</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
    <url>
        <loc>https://credifygo.com/control-de-prestamos-excel</loc>
        <lastmod>2026-07-30</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>
```

- [ ] **Step 4: Verificar nav/footer/sitemap**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan view:clear && (php artisan serve --port=8796 >/dev/null 2>&1 &) ; sleep 3 ; echo '--- enlaces Recursos en landing ---'; curl -s http://127.0.0.1:8796/ | grep -oE '/software-para-prestamos|/software-de-cobranza|/gestion-de-cartera|/como-administrar-negocio-de-prestamos|/control-de-prestamos-excel' | sort | uniq -c ; echo '--- sitemap ---'; curl -s http://127.0.0.1:8796/sitemap.xml | grep -c '<loc>' ; pkill -f 'artisan serve'"
```
Expected: cada slug aparece ≥2 veces (nav + footer) en la landing; el sitemap tiene **7** `<loc>`.

Abrir el preview y confirmar que el dropdown "Recursos" funciona y el footer lista los 5.

- [ ] **Step 5: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add resources/views/components public/sitemap.xml && git commit -m 'feat(content): nav/footer Recursos + sitemap con 5 paginas pilar'"
```

---

### Task 9: Verificación holística + CHANGELOG + build

**Files:**
- Modify: `CHANGELOG.md`

- [ ] **Step 1: Suite completa + PHPStan + Pint + build**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test 2>&1 | tail -5"
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/ 2>&1 | tail -5"
wsl bash -lc "cd /var/www/html/credify && vendor/bin/pint --test 2>&1 | tail -5"
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in'"
```
Expected: tests verdes, PHPStan sin errores, Pint sin cambios, build OK.

- [ ] **Step 2: Screenshots de las 5 páginas + landing**

Con el preview del navegador, recorrer `/` (idéntica), y las 5 páginas en 375/768/1280: nav "Recursos", breadcrumb, cuerpo, FAQ, CTA, footer. Confirmar tema dark consistente y 0 residuos de marca prohibida.

- [ ] **Step 3: CHANGELOG**

Bajo `## [Sin publicar]` → `### Añadido`, añade una entrada: contenido pilar SEO (Track 3) — 5 páginas (`/software-para-prestamos`, `/software-de-cobranza`, `/gestion-de-cartera`, `/como-administrar-negocio-de-prestamos`, `/control-de-prestamos-excel`) sobre layout Blade compartido extraído de la landing; JSON-LD Article/BreadcrumbList/FAQPage por página vía `json_encode`; nav/footer "Recursos"; sitemap ampliado; `ContentPagesTest` con guard de marca. Ref al spec.

- [ ] **Step 4: Commit**

```bash
wsl bash -lc "cd /var/www/html/credify && git add CHANGELOG.md && git commit -m 'docs(content): CHANGELOG contenido pilar SEO (Track 3)'"
```

---

## Deploy (post-merge, flujo establecido — **full**: Blade + assets)

Tras merge del PR a `main` y realineado de `dev`:
1. `npm run build` en WSL → `public/build` + `public/pwa-sw.js`.
2. scp de `build` + `pwa-sw.js` a prod `/tmp/*.new`; swap atómico (`build.staging`→`build`, `chown www-data`). (credify-prod-vm)
3. En prod: `git pull --ff-only origin main` + `php artisan optimize:clear && optimize && filament:optimize` + `sudo -n systemctl reload php8.3-fpm`.
4. Verificar en prod: cada ruta 200, `curl` de title/canonical/JSON-LD, 0 ocurrencias de "pagadiario"/"gota a gota", 7 `<loc>` en el sitemap. Validar JSON-LD de una página en Rich Results Test. Reenviar/actualizar el sitemap en Google Search Console.

---

## Self-Review (cobertura vs. spec)

- **5 páginas pilar con slugs del mapa:** Tasks 2 (skeleton) + 3-7 (contenido). ✅
- **Approach A — layout compartido + páginas estáticas:** Task 1 (public + nav + footer + refactor welcome) + Task 2 (article). ✅
- **Refactor landing sin regresión:** Task 1 Step 5 (ExampleTest + 3 JSON-LD + screenshot). ✅
- **SEO por página (title/desc/canonical/OG/JSON-LD):** article layout + ContentController::seo() (Task 2). ✅
- **JSON-LD vía `json_encode` (sin @verbatim):** Task 2 Steps 3+5. ✅
- **FAQPage + Article + BreadcrumbList:** helper `seo()` `@graph` (Task 2). ✅
- **Enlazado interno hub&spoke + CTA /registro:** enlaces contextuales en Tasks 3-7 + CTA en article layout. ✅
- **Nav/footer "Recursos" + sitemap:** Task 8. ✅
- **Guard de marca (no pagadiario/gota a gota) automatizado:** `ContentPagesTest` (Task 2 Step 1) + re-check en cada content task. ✅
- **Deploy full (build+ship) por Tailwind scan:** sección Deploy + Task 9 build. ✅
- **PHPStan/Pint preflight:** Task 2 Step 8 + Task 9 Step 1. ✅
- **No-objetivos (sin blog/CMS/6ª página/OG por página/sitemap dinámico):** ninguna task los introduce. ✅

**Placeholder scan:** el contenido de prosa (Tasks 3-7) se especifica por outline detallado + convenciones de clase exactas + enlaces exactos + longitud objetivo; la redacción final es el entregable de autoría (inherente al trabajo de contenido), no un placeholder de código. Infra (Tasks 1, 2, 8) con código exacto.

**Consistencia de tipos:** `ContentController::seo()` devuelve `title/description/heading/url/faqs/schema`; el article layout consume exactamente esas variables; `$faqs` es `list<array{q,a}>` en controller, test y layout. Rutas nombradas `content.*` coinciden entre `routes/web.php` y el controlador. ✅
