# BewPro — Guía de Provisionado

## Validado: 2026-03-28

---

## 1. Visión general

BewPro provisiona sitios web a partir de **3 datos mínimos**:
```
EMAIL + TÍTULO + PRODUCTO
```

El sistema resuelve el producto a un core preset (demo + módulos), crea la DB, migra 62 tablas, siembra datos base y sube assets. En ~30 segundos el sitio está online.

---

## 2. Comandos

### 2.1 bewpro:new — Provisión rápida
```bash
php artisan bewpro:new EMAIL "TÍTULO" PRODUCTO [opciones]
```

| Argumento | Descripción | Ejemplo |
|-----------|-------------|---------|
| EMAIL | Email del admin del proyecto | juan@empresa.com |
| TÍTULO | Nombre del sitio / negocio | "Mi Restaurante" |
| PRODUCTO | Shop slug o core slug | restaurant-bar |

| Opción | Default | Descripción |
|--------|---------|-------------|
| --dry-run | false | Muestra plan sin ejecutar |
| --no-email | false | No envía credenciales por email |
| --skip-assets | false | No sube assets a Cloudinary |
| --db=NOMBRE | bp-{slug} | Nombre de DB custom |
| --password=PASS | random 12 chars | Password custom |

### 2.2 bewpro:provision — Provisión completa desde JSON
```bash
php artisan bewpro:provision PATH_AL_JSON [opciones]
```

| Opción | Descripción |
|--------|-------------|
| --dry-run | Muestra plan sin ejecutar |
| --fresh | DROP + re-migrate (destructivo) |
| --skip-migrate | Salta migraciones (si DB ya existe) |
| --skip-assets | No sube assets a Cloudinary |
| --skip-content | No siembra contenido de módulos |

### 2.3 bewpro:products — Catálogo
```bash
php artisan bewpro:products              # Tabla de cores + conteo variantes
php artisan bewpro:products --all        # Los 145 shop products
php artisan bewpro:products agency       # Variantes de un core
```

---

## 3. Flujo interno (11 pasos)

```
bewpro:new EMAIL TÍTULO PRODUCTO
│
├─ Paso 0: Resolver producto
│  └─ catalog.json → core slug → core/{slug}.json
│
├─ Paso 1: Switch database
│  └─ CREATE DATABASE IF NOT EXISTS `bp-{slug}`
│
├─ Paso 2: Migraciones
│  └─ 62 tablas (users, settings, services, posts, faqs, etc.)
│
├─ Paso 3: Config cd-system
│  └─ demo + skin + fonts + módulos activos → tabla settings
│
├─ Paso 4: Datos base
│  └─ Permisos (52+) + Roles (6) + Users (admin + master)
│
├─ Paso 5: Datos del sitio
│  └─ name, contact, social_media, SEO, OG, assets paths → settings
│
├─ Paso 6: Analytics
│  └─ Google Analytics config → settings
│
├─ Paso 7: Assets
│  └─ cd-project/assets/* → Cloudinary → URLs en settings
│
├─ Paso 8: Content defaults
│  └─ defaults/*.json → project-data/ (services, faqs, blog, etc.)
│
├─ Paso 9: Seed módulos
│  └─ Por cada módulo activo: seeder lee JSON → inserta en DB
│
├─ Paso 10: Seed CdBase
│  └─ Carousel, homepage defaults
│
└─ Paso 11: Clear cache
   └─ config, view, cache, SiteConfig, CdSystemConfig
```

---

## 4. Resolución de producto

```
SLUG recibido
    │
    ├─ Buscar en catalog.json (145 entries)
    │   ├─ Encontrado → devuelve [core_slug, nombre]
    │   └─ No encontrado → asumir que ES un core slug
    │
    └─ Cargar core/{core_slug}.json
        ├─ Existe → usar como preset
        └─ No existe → ERROR: "Core preset not found"
```

### Ejemplo: `yoga-instructor`
```
catalog.json → { "core": "nutritionist", "name": "Yoga Instructor" }
core/nutritionist.json → { "demo": "demo-insurance", "modules": ["services","blog","gallery","faqs"] }
```

---

## 5. Qué se crea en cada provisión

| Elemento | Cantidad | Fuente |
|----------|----------|--------|
| Tablas | 62 | Migraciones |
| Roles | 6 | RolesSeeder |
| Permisos | 52+ | PermissionsSeeder |
| Users | 2-3 | UsersSeeder + ProjectsUsersSeeder |
| Settings | 110+ | SettingsSeeder + config writers |
| Services | 3 | defaults/services.json |
| FAQs | 8 | defaults/faqs.json |
| Blog posts | 2 | defaults/blog.json |
| Gallery | 3 | defaults/gallery.json |
| Team | 2 | defaults/team.json |
| Projects | 3 | defaults/projects.json |

> Nota: Solo se siembran los módulos activos del core. Si el core tiene solo `services` y `faqs`, los demás defaults se copian pero no se ejecutan.

---

## 6. Assets requeridos

Antes de provisionar, estos archivos deben existir en `public/cd-project/assets/`:

| Archivo | Uso | Requerido |
|---------|-----|-----------|
| logo.png | Header principal | SÍ |
| logo-alternative.png | Footer / fondos oscuros | SÍ |
| logo-2.png | Loader / secundario | Recomendado |
| favicon.ico | Pestaña del browser | SÍ |
| favicon.svg | Favicon vectorial | Recomendado |
| apple-touch-icon.png | iOS shortcut | Recomendado |

Si faltan archivos, el sistema avisa con warning y continúa. Los assets sin archivo quedan con URL vacía y se pueden cargar después desde admin.

---

## 6.1 Mapeo de assets por producto (nuevo)

Desde abril 2026, `bewpro:new` y `bewpro:provision` pueden resolver assets por carpeta específica de producto/core antes de usar la carpeta global.

### Prioridad de resolución

Para cada asset canónico (`cd-project/assets/logo.png`, etc.), el sistema busca en este orden:

1. `public/cd-project/assets/demos/{demo-slug}/`
2. `public/cd-project/assets/{demo-slug}/`
3. `public/cd-project/assets/{core-slug}/`
4. `public/cd-project/assets/{product-slug}/` + aliases
5. fallback: `public/cd-project/assets/` (raíz)

Si el archivo existe en una carpeta superior, se usa ese para la subida a Cloudinary.

### Slugs usados en la resolución

- `core_slug`: se inyecta en `projectData` durante `bewpro:new`.
- `product_slug`: se inyecta en `projectData` durante `bewpro:new`.
- En `bewpro:provision` (JSON manual), si querés forzar resolución por producto, incluir `core_slug` y/o `product_slug`.

### Aliases implementados

Para mapear carpetas existentes que no siempre coinciden con el core:

- `corporative` y `corporate-website` -> `corporate` (y/o `corporate-website` si existe)
- `insurance-advisor` -> `insurance`
- `personal-brand` -> `personal`
- `real-estate` -> `real-state`

Adicionalmente se normalizan sufijos comunes: `-website`, `-advisor`, `-brand`.

### Carpetas validadas en QA

En la ronda QA3 se validó detección explícita de `Asset pack` para:

- `construction` -> `cd-project/assets/construction/`
- `corporate-website` -> `cd-project/assets/corporate-website/`
- `insurance-advisor` -> `cd-project/assets/insurance/`
- `personal-brand` -> `cd-project/assets/personal/`
- `real-estate` -> `cd-project/assets/real-state/`
- `law-firm` / `law-firm-digital` -> `cd-project/assets/law-firm-digital/`

### Importante para servidores (setup scripts)

Si en automatización usás `--skip-assets`, este mapeo NO se ejecuta (porque se salta el paso de assets completo).

Para aplicar assets por producto en provisión automática, ejecutar `bewpro:new` sin `--skip-assets`.

### Nota técnica Cloudinary (fix aplicado)

Se corrigió el cálculo del folder de Cloudinary para usar la DB activa en runtime (conexión actual), evitando que múltiples provisiones suban al mismo folder por leer solo `env('DB_DATABASE')`.

---

## 7. Core presets disponibles (21)

| Core | Demo | Módulos | Schema |
|------|------|---------|--------|
| bp-dinamic | demo-business-consulting | services, faqs | ProfessionalService |
| petite-website | demo-business-consulting | services, faqs | ProfessionalService |
| standard-website | demo-digital-agency-2 | services, faqs, gallery, blog | ProfessionalService |
| sitio-web-profesional | demo-digital-agency-2 | services, gallery, blog, faqs | ProfessionalService |
| insurance-advisor | demo-insurance | services, faqs | InsuranceAgency |
| restaurant-bar | demo-restaurant | menu, gallery, blog, faqs | Restaurant |
| law-firm-digital | demo-law-firm-2 | services, team, blog, references, faqs | LegalService |
| construction | demo-construction | services, projects, gallery, blog, faqs | GeneralContractor |
| real-estate | demo-real-estate | tokko, services, gallery, blog, faqs, projects | RealEstateAgent |
| photography | demo-photography-3 | gallery, blog, projects | ProfessionalService |
| personal-brand | demo-accounting-2 | gallery, blog, projects | Person |
| agency | demo-accounting-1 | services, blog, projects, gallery, team, references | ProfessionalService |
| financial-wealth | demo-insurance | services, blog, references, faqs, team | FinancialService |
| corporative | demo-marketing-1 | services, gallery, projects, faqs | Organization |
| business-catalogue | demo-digital-agency-2 | services, products, faqs, gallery | Store |
| catalogue-ai | demo-digital-agency-2 | products, faqs | Store |
| art-design | demo-architecture-2 | services, gallery, projects, blog, faqs | ProfessionalService |
| nutritionist | demo-insurance | services, blog, gallery, faqs | MedicalBusiness |
| concierge | demo-insurance | services, gallery, projects, blog, products | LocalBusiness |
| foundations-ong | demo-accounting-1 | services, blog, gallery, faqs | NGO |
| website-reseller | demo-digital-agency-2 | products, services, blog, projects, faqs | Store |

---

## 8. Content seeds por core

Los cores pueden tener seeds específicos en `database/seeders/products/core/seeds/`:

### 8.1 Config seeds (auto-merge en provisión)

Archivos `config-{core}.json` se mergean automáticamente durante el Paso 4. Contienen valores de welcome/about/contact que se escriben en la tabla settings.

| Archivo | Core | Demo |
|---------|------|------|
| config-standard-website.json | standard-website | demo-digital-agency-2 |
| config-bp-dinamic.json | bp-dinamic | demo-business-consulting |
| config-petite-website.json | petite-website | demo-business-consulting |
| config-real-estate.json | real-estate | demo-real-estate |
| config-art-design.json | art-design | demo-architecture-2 |
| config-construction.json | construction | demo-construction |
| config-corporative.json | corporative | demo-marketing-1 |
| config-creative-agency.json | creative-agency | demo-creative-agency-2 |
| config-insurance-advisor.json | insurance-advisor | demo-insurance |
| config-law-firm-digital.json | law-firm-digital | demo-law-firm-2 |

### 8.2 Module content seeds

| Tipo | Cores que tienen | Formato |
|------|-----------------|---------|
| services-{core}.json | 17 cores | `{ service_categories: [...], services: [...] }` |
| faqs-{core}.json | 16 cores | `{ faq_categories: [...], faqs: [...] }` |
| blog-{core}.json | 16 cores | `{ categories: [...], posts: [...] }` |
| gallery-{core}.json | 1 (corporative) | `{ images: [...] }` |
| projects-{core}.json | 1 (corporative) | `{ categories: [...], projects: [...] }` |
| testimonials-{core}.json | 2 (construction-2, restaurant-bar) | `{ testimonials: [...] }` |

Si un core no tiene seed específico, se usan los defaults genéricos.

---

## 9. Validaciones del sistema

### Campos requeridos (falla sin estos)
- `name` — nombre del sitio
- `db_name` — nombre de la base de datos
- `demo` — template visual (ej: demo-restaurant)

### Validaciones automáticas
- JSON del core preset: validado (json_last_error)
- File::put de users.json: validado (RuntimeException si falla)
- Seeders: try/catch con warning si fallan
- Assets: pre-flight check con warning si faltan

### Lo que NO se valida
- Que el demo tenga blade files (header, footer, welcome, about, contact)
- Que los módulos tengan rutas registradas
- Que las URLs de redes sociales sean válidas
- Que el email sea real

---

## 10. Errores comunes

| Error | Causa | Solución |
|-------|-------|----------|
| "Core preset not found" | Slug no existe como core | Verificar con `bewpro:products` |
| "name is required" | JSON sin campo name | Agregar campo name al JSON |
| "Class not found" en config | Paquete desinstalado con config residual | Agregar guard en config/*.php |
| Assets con URL vacía | Archivos no estaban en cd-project/assets/ | Subir y re-ejecutar con `--skip-migrate` |
| Módulo no aparece en nav | navigation.header = false | Cambiar en DB settings |
| Site en blanco | Demo sin blade files | Crear vistas del demo |

---

## 11. Test de provisionado

### Crear DB de test
```sql
CREATE DATABASE `bp-test`;
```

### Provisionar
```bash
php artisan bewpro:new test@test.com "Test Site" bp-dinamic --no-email
```

### Verificar
```bash
# Cambiar .env → DB_DATABASE=bp-test
php artisan tinker --execute="
echo DB::getDatabaseName();
echo DB::table('settings')->count();
echo DB::table('users')->where('email','test@test.com')->exists() ? 'User OK' : 'User FAIL';
echo DB::table('settings')->where('key','cd-system.theme.demo')->value('value');
"
```

### Limpiar
```sql
DROP DATABASE `bp-test`;
```
