# Deep dive #5a — JSON imports: audit + canonicalización

**Status**: ✅ Sprint 1 (audit + validator) DONE 2026-05-05. 🟡 Sprint 2 (canonicalización masiva) pendiente — requiere decisiones de copy/marketing.
**Frente master**: #5a NEXT (prereq de #5 Optimizar 250 + #7 IA agent)
**Tiempo invertido**: ~1 hr sprint técnico
**Doc operativo**: este archivo

---

## Por qué este frente

`#5 Optimización de módulos (250 productos)` y `#7 IA agent (onboarding automatizado)` ambos dependen de un **set canónico de imports JSON**. Sin schemas claros:

- Los JSONs evolucionaron orgánicamente con campos opcionales que algunos archivos tienen y otros no
- 24 cores con shapes parcialmente distintos (8/24 con campos faltantes consistentes)
- 2 cores con scope-violation (content embedido en preset técnico)
- 1 archivo con conflict markers de git sin resolver (silencioso — rompería provisión cuando alguien lo intente usar)

Sin canonicalización, escalar a IA agent sería: agente generando JSONs en formato "viejo" inconsistentes. Auditar primero, fixear después.

---

## Inventario actual (auditado 2026-05-05)

### Estructura

```
database/seeders/
├── products/                                        ← 115 archivos
│   ├── alias-matrix.json                            (1)  matriz módulo×industria
│   ├── catalog.json                                 (1)  shop slug → core mapping (121 productos)
│   ├── core-products-copy.json                      (1)  copy de cada core
│   ├── shop-copy.json                               (1)  copy de cada shop product
│   ├── core/
│   │   ├── <slug>.json                              (24) preset técnico por core
│   │   └── seeds/
│   │       ├── faqs-<core>.json                     (21) FAQs por core
│   │       ├── services-<core>.json                 (19)
│   │       ├── blog-<core>.json                     (17)
│   │       ├── config-<core>.json                   (14)
│   │       ├── gallery-<core>.json                  (6)
│   │       ├── projects-<core>.json                 (4)
│   │       ├── testimonials-<core>.json             (2)
│   │       ├── team-<core>.json                     (2)
│   │       ├── references-<core>.json               (1)
│   │       └── menu-<core>.json                     (1)
│
└── project-data/                                    ← 67 archivos
    ├── provision-<slug>.json                        (~20) config completa por tenant
    ├── content-<slug>.json                          (~3)  content específico de tenant
    ├── provision-template.json                      (1)   template para nuevas provisiones
    ├── _config-preset.json                          (1)   preset base
    └── <module>.json                                (~10) defaults: services, gallery, news, menu, etc.
```

---

## Schemas canónicos definidos

### Core preset (`products/core/<slug>.json`)

```yaml
required:
  demo: string                # ej. "demo-restaurant"
  modules: array<string>      # ej. ["services", "blog", "faqs"]
  modules_navigation: object  # { module: { header: bool, footer: bool } }
  skin: string                # "auto" | "skin-X"
  fonts: object               # { primary, secondary, tertiary }
  schema_type: string         # schema.org type (ej. "ProfessionalService")
  header: object              # { cta_button: { active, title, url, target, style } }
  brand_defaults: object      # { colors, fonts, logo_pack }

optional_canonical:
  description: string         # descripción corta del core (para listings)
  tagline: string             # tagline marketero (~10 palabras)
  demo_url: string            # URL al demo público
  seo: object                 # { keywords, ... }

forbidden:
  welcome | about | contact | footer | menu  # debería estar en seeds/, no en preset
```

### Provision config (`project-data/provision-<slug>.json`)

```yaml
required:
  name: string                # nombre del proyecto
  db_name: string             # ej. "bp-cliente"
  demo: string                # ej. "demo-restaurant"
  description: string
  tagline: string
  modules: array<string>
  modules_navigation: object
  skin: string
  fonts: object
  header: object
  contact: object             # { phone, email, address, hours }

optional_canonical:
  schema_type: string
  url: string                 # dominio
  author: string
  social_media: object        # { instagram: {url, active}, facebook, ... }
  analytics: object           # { enabled, tracking_id, ... }
  seo_keywords: string
```

### Seeds (a tipar — TODO Sprint 2)

`faqs-X.json`, `services-X.json`, etc. tienen shapes diferentes según tipo. Documentar cada uno como TODO Sprint 2.

---

## Hallazgos del audit (2026-05-05)

### Cores: 24 archivos validados

```
✅ Required: 24/24 cumplen los 8 campos requeridos.

⚠️ Optional canonical (incompleto en 14 cores):
  - creative-agency, financial-wealth, insurance-advisor, nutritionist,
    petite-website, photography, sitio-web-profesional, standard-website,
    website-reseller, agency, bp-dinamic, business-catalogue, catalogue-ai,
    concierge
  → Falta: description, tagline, demo_url, seo

⚠️ Forbidden fields (scope violation, 2 cores):
  - construction-2: tiene welcome, about, contact, footer embedidos
  - restaurant-bar: idem
  → Estos campos deberían estar en seeds/, no en preset técnico

⚠️ Solo demo_url faltante (1 core):
  - construction-2

✅ Score técnico: 100% (todos cumplen required)
🟡 Score canonical: ~33% (8/24 con todos los opcionales canónicos)
```

### Provisions: 21 archivos validados

```
❌ ERRORES (1):
  provision-ofinita.json: JSON inválido — tiene conflict markers de git
  sin resolver (<<<<<<< HEAD ... >>>>>>> c1822e15...). Archivo roto que
  fallaría si alguien intentara usarlo para provisionar.
  ACCIÓN: decisión humana (qué versión preservar) y commit del fix.

⚠️ WARNINGS (19):
  - 6 provisions con varios opcional canonical faltantes
  - Más común: analytics + seo_keywords faltantes (en ~5 provisions)
  - 2 provisions sin url, author, social_media

✅ Score técnico: 95% (1/21 inválido)
🟡 Score canonical: ~70%
```

---

## Tooling

### Comando: `bewpro:validate-json`

`app/Console/Commands/ValidateJsonImports.php` — valida JSONs contra schemas canónicos.

```bash
# Validar todo (cores + provisions)
php artisan bewpro:validate-json

# Solo cores
php artisan bewpro:validate-json --type=cores

# Solo provisions
php artisan bewpro:validate-json --type=provisions

# Un archivo específico
php artisan bewpro:validate-json database/seeders/products/core/insurance-advisor.json

# Auto-fix de warnings (agrega campos opcionales con valores default vacíos)
php artisan bewpro:validate-json --type=cores --fix-warnings
```

**Output**:
- ❌ Errores (campos required faltantes, JSON inválido) — exit code 1.
- ⚠️ Warnings (campos opcional canonical faltantes, scope violations) — exit code 0.
- ✅ Silencio si está limpio.

**Diseño**:
- Schemas como const arrays en el código (no JSON Schema) — más simple, type-checkable, sin dependencias externas.
- Auto-detect del tipo por path (`provision-*` → provision, `/products/core/X.json` → core).
- `--fix-warnings` agrega campos vacíos del tipo correcto (string='', object={}, array=[]) — no destructivo, no llena con copy real.
- Code design extensible para agregar más tipos (seeds, catalog) en Sprint 2.

---

## Plan Sprint 2 (no bloqueante, requiere inputs)

### A — Generar copy faltante para los 14 cores incompletos

Cada core necesita: `description`, `tagline`, `demo_url`, `seo` con keywords.

**Decisión humana**: copy de marketing por industria. No automatizable sin el agente IA.

Mientras tanto: opción `--fix-warnings` agrega campos vacíos para que el shape sea consistente. Marketing/copywriter llena después.

```bash
php artisan bewpro:validate-json --type=cores --fix-warnings
```

### B — Mover content embedido de 2 cores a seeds/

`construction-2` y `restaurant-bar` tienen `welcome/about/contact/footer` en el preset técnico. Mover:

```
products/core/construction-2.json (sin welcome/about/contact/footer)
products/core/seeds/content-construction-2.json (NUEVO con esos 4 campos)
```

Y actualizar el provision logic en `BewproProvisionRunner.php` para leer content desde seeds.

### C — Resolver `provision-ofinita.json` con conflict markers

```bash
# Decidir qué versión queremos:
# - HEAD (la actual del repo cd-system al momento del merge fallido)
# - O la branch que se mergeó (c1822e15)
# - O combinar manualmente

# Inspeccionar:
cat database/seeders/project-data/provision-ofinita.json | head -5

# Resolver con editor o git
git checkout HEAD -- database/seeders/project-data/provision-ofinita.json  # versión 1
# o
git checkout c1822e15 -- database/seeders/project-data/provision-ofinita.json  # versión 2
```

**Recomendación**: dado que el archivo no se está usando (sino habría roto la provisión), el approach seguro es **borrarlo** (`git rm`) y regenerarlo desde `provision-template.json` cuando se necesite.

### D — Tipar seeds (faqs, services, blog, config, gallery, projects, etc.)

Cada tipo de seed tiene shape distinto. Documentarlos en este doc + extender el validator para incluirlos.

### E — Validación pre-commit (opcional)

Agregar git pre-commit hook que corra `bewpro:validate-json` y bloquee commits con errors. Sin esto, alguien puede commitear JSON inválido (como pasó con ofinita) sin que se detecte.

```bash
# .git/hooks/pre-commit (versionar como scripts/pre-commit.sh)
#!/bin/bash
php artisan bewpro:validate-json || {
    echo "❌ JSON imports inválidos. Corregí antes de commitear."
    exit 1
}
```

---

## Cómo se usa el validator

### Workflow del dev

```bash
# Antes de commitear cambios en JSONs
php artisan bewpro:validate-json

# Si agregás un core nuevo
php artisan bewpro:validate-json database/seeders/products/core/mi-nuevo-core.json

# Si querés que el shape sea consistente sin tener el copy todavía
php artisan bewpro:validate-json --type=cores --fix-warnings
# → genera campos vacíos. Llenarlos después con copy real.
```

### Workflow del CI (futuro)

Agregar al pipeline de GitHub Actions:

```yaml
# .github/workflows/validate-json.yml (TODO)
on:
  pull_request:
    paths:
      - 'database/seeders/products/**.json'
      - 'database/seeders/project-data/**.json'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with: { php-version: '8.2' }
      - run: composer install --no-dev
      - run: php artisan bewpro:validate-json
```

---

## KPIs / éxito

| Métrica | Baseline (pre-audit) | Goal 30 días |
|---------|---------------------|--------------|
| Validator artisan | ❌ no existía | ✅ live |
| % cores con shape canónico completo | ~33% | ≥ 90% |
| % provisions sin warnings | ~33% | ≥ 80% |
| JSON inválidos en repo | 1 (ofinita) | 0 |
| Tiempo de detectar drift en JSONs | manual / nunca | <1 seg con validator |
| Tipos de seed tipados en validator | 0 | 5+ (faqs, services, blog, config, gallery) |

---

## Decisiones registradas

| Pregunta | Respuesta | Razón |
|----------|-----------|-------|
| ¿Schemas como JSON Schema o como PHP const? | **PHP const** | Más simple, sin dependencia externa, fácil de evolucionar, sin necesidad de tooling JSON Schema. Trade-off: no se puede compartir fácil con frontend, pero hoy no se necesita |
| ¿Auto-fixear los 14 cores faltantes en este sprint? | **No** | El copy real (description, tagline) es decisión de marketing, no técnica. Mejor que el validator marque el gap y un humano (o agente futuro) llene |
| ¿Borrar `provision-ofinita.json` en este sprint? | **No** | Decisión humana — el user decide si la versión vieja vale la pena rescatar. Documentado como pendiente |
| ¿Mover content embedido de construction-2 y restaurant-bar? | **No en este sprint** | Refactor invasivo que requiere actualizar `BewproProvisionRunner.php`. Mejor en sprint dedicado cuando haya bandwidth |
| ¿Hacer del validator un git pre-commit hook? | **Documentado como TODO** | Útil pero requiere coordinación de team (todos los devs deben tener el hook). Mejor en CI primero |
| ¿Validar también catalog.json y alias-matrix.json? | **No por ahora** | Tienen shapes únicos sin variantes. Validar tiene poco ROI; mejor enfocar en cores + provisions que sí varían |

---

## Archivos creados/modificados

| Archivo | Cambio |
|---------|--------|
| `app/Console/Commands/ValidateJsonImports.php` | NUEVO — comando validator extensible con schemas |
| `docs/bewpro2.0/roadmap/05a-json-imports.md` | Este archivo |
| `docs/bewpro2.0/roadmap/00-master-roadmap.md` | Status #5a actualizado |

---

*Iniciado y cerrado: 2026-05-05*. Sprint 1 técnico ✅ DONE. Sprint 2 (canonicalización masiva, mover content, tipar seeds) pendiente — gated by inputs de marketing/copywriter o por #7 IA agent.
