# BewPro — Arquitectura tecnica del CMS modular multitenant
> Documento tecnico de referencia | Revision: 2026-03-21

---

## Proposito

Este documento describe la arquitectura tecnica de CD-System, el motor detras de BewPro. Sirve como referencia para:
- Entender como se ensambla un producto (core + demo + modulos)
- Saber donde esta cada cosa en el codebase
- Tomar decisiones tecnicas informadas sobre escalabilidad

---

## 1. Modelo de datos: 1 codebase → N productos → N×M proyectos

```
CD-System (1 codebase)
    → 21 core presets (combinaciones de demo + modulos)
        → 145 shop products (presentaciones de mercado)
            → N proyectos provisionados (1 DB por proyecto)
```

### Las 4 capas

```
Capa 4: Datos del Proyecto
    └── BD propia por proyecto (multitenant via DB_DATABASE en .env)
    └── Tabla settings: key-value para config de sitio y sistema
    └── Tablas de modulos: services, projects, faqs, blog, etc.

Capa 3: Modulos funcionales
    └── 15 modulos: blog, services, projects, gallery, faqs, team,
        references, products, menu, news, newsletter, about, contact,
        project-setup, translations
    └── Se activan/desactivan por proyecto via settings
    └── Cada modulo: Model + Controller + Views + Routes + Seeder

Capa 2: Demo (template visual)
    └── 16 demos disponibles
    └── Define: header, footer, welcome, about, contact, skin, CSS
    └── Los modulos se adaptan al demo via CSS + page-header partial

Capa 1: Nucleo CD-Base
    └── Laravel 9 + Porto theme
    └── Services: SiteConfigService, CdSystemConfigService
    └── Helpers: is_module_active(), get_dynamic_navigation(), etc.
    └── Admin panel: gestion de contenido por modulo
    └── Provisioning: bewpro:provision, bewpro:new
```

---

## 2. Multitenant: aislamiento por base de datos

Cada proyecto tiene su propia base de datos MySQL. El switch se hace via `DB_DATABASE` en `.env`.

```
bp-bewpro          → bewpro.com (el marketplace)
bp-cd              → lacompaniadigital.com (Compania Digital)
bp-schujman        → schujman.bewpro.com
bp-distrito        → distritotucuman.com
...
```

### Configuracion por proyecto

| Que | Donde | Ejemplo |
|-----|-------|---------|
| Demo activo | `settings.cd-system.theme.demo` | `demo-accounting-1` |
| Skin activo | `settings.cd-system.theme.skin` | `skin-accounting-1` |
| Modulos activos | `settings.cd-system.modules.{mod}.active` | `1` o `0` |
| Nav de modulos | `settings.cd-system.modules.{mod}.navigation.header` | `1` o `0` |
| Nombre del sitio | `settings.site.name` | `Compañia Digital` |
| Contacto | `settings.site.contact.*` | email, phone, address |
| Redes sociales | `settings.site.social_media.*` | instagram, whatsapp, etc. |
| Assets (logos) | `settings.site.assets.*` | paths a logo, favicon, og-image |
| SEO | `settings.site.seo.*` | keywords, description, schema |

### Cache por proyecto

```
Cache key: cd_system_config_db_{md5(DB_DATABASE)}
```

Cada proyecto tiene su cache aislado. TTL: 24 horas.

---

## 3. Sistema de demos: como un template visual se integra con los modulos

### Principio fundamental

> **El demo controla la estetica. El modulo controla la funcionalidad. Nunca al reves.**

### Archivos que componen un demo

```
public/template/css/
├── skins/skin-{name}.css               ← Paleta de colores (CSS variables)
└── demos/demo-{name}.css               ← Estilos + global overrides

resources/views/
├── layout/front/
│   ├── headers/demo-{name}.blade.php   ← Header con nav dinamica
│   ├── footers/demo-{name}.blade.php   ← Footer con nav + contacto
│   └── partials/
│       └── page-header-{name}.blade.php ← Page header compartido (16 existentes)
│
└── modules/cd-base/frontend/demos/demo-{name}/
    ├── welcome.blade.php               ← Homepage (integra modulos)
    ├── about.blade.php                 ← Pagina empresa
    └── contact.blade.php               ← Pagina contacto
```

### Las 3 capas de adaptacion visual

```
CAPA 1: CSS (skin + demo CSS con global overrides)
    → Controla TODA la estetica sin tocar HTML
    → El skin define variables (--primary, --secondary, etc.)
    → El demo CSS define layout, tipografia, animaciones
    → Los global overrides convierten clases Porto a la estetica del demo

CAPA 2: Page header (partial compartido)
    → 1 archivo por demo: page-header-{name}.blade.php
    → Registrado en 10 dynamic-headers (1 por modulo)
    → Interface estandar: $pageTitle, $pageLabel, $pageBreadcrumb, $pageSubtitle

CAPA 3: Paginas base (welcome, about, contact)
    → Especificas del demo
    → Integran datos de modulos: $services, $featuredProjects, $featuredFaqs, etc.
    → Datos del sitio via config('site.*')
```

### Donde NO debe haber logica de demo

| Lugar | Por que |
|-------|---------|
| Controladores de modulos | El controlador no debe saber de demos |
| Vistas de modulos (services.blade, show.blade) | Se adaptan via CSS, no via @if(demo) |
| Modelos | Nunca |

### Estado actual de los 16 demos

| Nivel | Demos | Que tienen |
|-------|-------|-----------|
| **A** (3) | accounting-1, digital-agency-2, insurance | Todo: partials + dynamic-headers + welcome dinamico + about/contact generico + CSS overrides |
| **B** (13) | resto | Partials + dynamic-headers + archivos base. Welcome/about/contact pueden tener contenido hardcodeado |

---

## 4. Modulos: como funcionan

### Activacion

```php
// En la DB del proyecto
settings.cd-system.modules.services.active = "1"
settings.cd-system.modules.services.navigation.header = "1"
settings.cd-system.modules.services.navigation.footer = "1"

// Helper para verificar
is_module_active('services') → true/false
is_module_in_nav('services', 'header') → true/false
```

### Modulos disponibles y sus rutas

| Modulo | Ruta index | Ruta detail | Route name |
|--------|-----------|-------------|------------|
| services | `/services` | `/services/{slug}` | `frontend.services.index`, `frontend.services.detail` |
| projects | `/projects` | `/projects/{slug}` | `frontend.projects.index`, `frontend.projects.show` |
| blog | `/blog` | `/blog/{slug}` | `blog.index`, `blog.post` |
| faqs | `/faqs` | — | `faqs.index` |
| gallery | `/gallery` | — | `frontend.gallery.index` |
| products | `/products-catalogue` | `/products-catalogue/{slug}` | `frontend.products.index`, `frontend.products.show` |
| team | `/team` | — | `frontend.team.index` |
| references | `/references` | — | `frontend.references.index` |
| menu | `/menu` | — | `frontend.menu.index` |
| about | `/about` | — | `front.about` |
| contact | `/contact` | — | `front.contact` |

### Datos disponibles en la homepage

El HomepageController pasa estas variables a TODOS los welcome.blade.php:

| Variable | Contenido | Limite |
|----------|-----------|--------|
| `$services` | Servicios activos con categoria | hasta 6 |
| `$featuredProjects` | Proyectos activos con categorias y tags | hasta 6 |
| `$featuredFaqs` | FAQs destacadas (o primeras 5) | hasta 5 |
| `$featuredPosts` | Posts de blog | hasta 3 |
| `$galleryImages` | Imagenes de galeria | hasta 8 |
| `$teamMembers` | Miembros del equipo activos | todos |
| `$featuredReferences` | Referencias/testimonios destacados | todos |
| `$carouselImages` | Imagenes del hero carousel | todas |
| `$featuredProducts` | Productos destacados | hasta 3 |

### Patron para integrar modulos en el welcome

```blade
@if(is_module_active('services') && isset($services) && $services->count() > 0)
    <section>
        @foreach($services->take(3) as $service)
            <h3>{{ $service->title }}</h3>
            <p>{{ $service->subtitle }}</p>
            <a href="{{ route('frontend.services.detail', $service->slug) }}">Ver mas</a>
        @endforeach
    </section>
@endif
```

---

## 5. Provisioning: como se crea un proyecto

### Flujo de provisioning

```
bewpro:provision provision-file.json [--fresh] [--skip-assets] [--skip-content]

Step 1:  Switch Database (crea DB si no existe, conecta)
Step 2:  Run Migrations (62 tablas)
Step 3:  Write cd-system Config (demo + modulos activos)
Step 4:  Seed Base Data (permisos, roles, usuario admin)
Step 5:  Write Site Data (nombre, contacto, SEO, redes sociales)
Step 6:  Write Analytics (Google Analytics)
Step 7:  Process Assets (Cloudinary upload)
Step 8:  Install Content Defaults (copia defaults/*.json → project-data/)
Step 9:  Seed Module Content (services, faqs, projects, blog, etc.)
Step 10: Seed CdBase (carousel, paginas base)
Step 11: Clear Caches
Step 12: Restore original JSONs (backup/restore)
```

### Defaults por modulo

```
database/seeders/project-data/defaults/
├── faqs.json        → 8 FAQs genericas en 2 categorias
├── services.json    → 3 servicios con benefits, process_steps, faq, cta_config
├── blog.json        → 2 posts genericos
├── menu.json        → 4 items en 3 categorias
├── gallery.json     → 3 items placeholder
├── team.json        → 2 miembros placeholder
├── references.json  → 3 referencias placeholder
├── projects.json    → 3 proyectos placeholder
├── products.json    → vacio (se cargan via catalog:seed)
└── cd-base.json     → vacio (carousel manual)
```

### Core presets

```
database/seeders/products/core/
├── insurance-advisor.json    → demo-insurance + services, faqs
├── standard-website.json     → demo-digital-agency-2 + services, faqs, gallery, blog
├── agency.json               → demo-accounting-1 + services, blog, projects, gallery, team, references
├── ... (21 presets total)
```

---

## 6. Navegacion dinamica

### Header

```php
$navigation = get_dynamic_navigation('header');
// Retorna solo modulos activos con navigation.header = true
// Cada item: ['title' => '', 'url' => '', 'active' => true/false]
```

### Footer

```php
$navigation = get_dynamic_navigation('footer');
// Lee de config('site.footer.navegacion_principal')
// Filtra por modulos activos
```

### El header muestra/oculta links automaticamente

Si un proyecto tiene `services` activo pero `blog` inactivo, el header muestra el link a Servicios pero no a Blog. Sin tocar codigo.

---

## 7. Rutas del sistema

### Rutas criticas (tabla de referencia)

| Pagina | Route name | URL |
|--------|-----------|-----|
| Homepage | `front.homepage` o `front.welcome` | `/` |
| About | `front.about` | `/about` |
| Contact | `front.contact` | `/contact` |
| Contact POST | `front.contact.store` | `/contact` (POST) |
| Services index | `frontend.services.index` | `/services` |
| Service detail | `frontend.services.detail` | `/services/{slug}` |
| Projects index | `frontend.projects.index` | `/projects` |
| Project detail | `frontend.projects.show` | `/projects/{slug}` |
| Projects portfolio | `frontend.projects.portfolio` | `/projects/portfolio` |
| FAQs index | `faqs.index` | `/faqs` |
| Blog index | `blog.index` | `/blog` |
| Blog post | `blog.post` | `/blog/{slug}` |
| Newsletter | `front.newsletter.subscribe` | `/newsletter` (POST) |
| Admin login | `login` | `/login` |
| Admin dashboard | `admin.dashboard` | `/admin` |

### Errores comunes de rutas

| Incorrecto | Correcto |
|-----------|----------|
| `route('contact')` | `route('front.contact')` |
| `route('about')` | `route('front.about')` |
| `route('frontend.services.show', $slug)` | `route('frontend.services.detail', $slug)` |

---

## 8. Estructura de archivos clave

```
app/
├── Console/Commands/
│   ├── ProvisionProject.php      ← Base del provisioning (12 steps)
│   ├── ProvisionNew.php          ← bewpro:new (resuelve shop→core)
│   └── ListProducts.php          ← bewpro:products
├── Modules/
│   ├── Services/                 ← Model, Controller, Routes
│   ├── Projects/
│   ├── Blog/
│   ├── CdBase/Faqs/
│   ├── Gallery/
│   ├── Products/
│   ├── TeamMembers/
│   ├── References/
│   ├── Menu/
│   └── Translations/
├── Services/
│   ├── SiteConfigService.php     ← Lee config del sitio desde DB
│   └── CdSystemConfigService.php ← Lee config del sistema desde DB
└── helpers.php                   ← is_module_active(), get_dynamic_navigation(), etc.

config/
├── cd-system.php                 ← Config del sistema (sobrescrito por DB)
└── site.php                      ← Config del sitio (sobrescrito por DB)

database/seeders/
├── project-data/
│   ├── defaults/                 ← 10 JSONs de contenido inicial
│   ├── provision-*.json          ← Archivos de provision por proyecto
│   └── *.json                    ← Datos del proyecto actual
└── products/
    ├── catalog.json              ← 145 shop products → core mapping
    └── core/                     ← 21 presets tecnicos

resources/views/
├── layout/front/
│   ├── master.blade.php          ← Layout base (carga skin + demo CSS)
│   ├── headers/demo-*.blade.php  ← 16 headers
│   ├── footers/demo-*.blade.php  ← 16 footers
│   └── partials/
│       └── page-header-*.blade.php ← 16 page-header partials
├── modules/
│   ├── services/frontend/        ← Vistas compartidas de services
│   ├── projects/frontend/        ← Vistas compartidas de projects
│   ├── blog/frontend/            ← Vistas compartidas de blog
│   └── cd-base/
│       ├── faqs/frontend/        ← Vistas de FAQs
│       └── frontend/demos/       ← 16 carpetas demo-{name}/
│           ├── demo-accounting-1/
│           │   ├── welcome.blade.php
│           │   ├── about.blade.php
│           │   └── contact.blade.php
│           ├── demo-digital-agency-2/
│           └── ... (16 demos)

public/template/css/
├── demos/demo-*.css              ← 16 demo CSS
└── skins/skin-*.css              ← 16 skin CSS
```

---

## 9. Escalabilidad y decisiones de arquitectura

### Por que CSS overrides en vez de vistas por demo

**Problema**: si cada demo tuviera su propia vista de services, projects, blog, etc., tendriamos 16 × 10 = 160 archivos de vista que mantener.

**Solucion**: las vistas de modulos son compartidas. El demo CSS aplica overrides globales que convierten las clases Porto a la estetica del demo. Un solo archivo CSS controla como se ven los 10 modulos en ese demo.

### Por que page-header partials compartidos

**Problema**: el page-header se repetia inline en cada dynamic-header (10 archivos × 16 demos = 160 bloques de HTML duplicado).

**Solucion**: 1 partial por demo. Los 10 dynamic-headers hacen `@include`. Cambiar el estilo del page-header de un demo = editar 1 archivo.

### Por que 1 DB por proyecto (no schema-based multitenancy)

- Aislamiento total: un proyecto no puede acceder a datos de otro
- Backup/restore individual por proyecto
- Performance: cada proyecto tiene indices propios
- Migracion: se puede mover un proyecto a otro servidor sin afectar otros
- Simplicidad: no hay queries con `WHERE tenant_id = X` en todo el codebase

### Por que defaults de contenido en JSON

- Permite que cada proyecto arranque con contenido visible (no vacio)
- Los JSONs son idempotentes: se pueden re-ejecutar sin duplicar datos
- El backup/restore protege los JSONs del proyecto de desarrollo durante el provisioning
- Los seeders soportan campos JSON complejos (benefits, process_steps, faq, cta_config)

---

## 10. Documentacion relacionada

| Documento | Ubicacion | Contenido |
|-----------|-----------|-----------|
| Arquitectura de demos | `docs/demos/arquitectura-demo-modular.md` | Relacion demo-modulo, reglas, niveles |
| Proceso Porto → CMS | `docs/demos/proceso-adaptacion-demo-porto.md` | Como extraer e integrar demos de Porto |
| Checklist de demo | `docs/demos/guia-integracion-demo-modular.md` | Verificacion tecnica paso a paso |
| Plan de lanzamiento | `docs/bewpro2.0/lanzamiento-mercado.md` | Go-live, gaps, bloques de trabajo |
| Programa revendedores | `docs/bewpro2.0/programa-de-revendedores.md` | Modelo de revenue, onboarding |
| SOP Compania Digital | `docs/compania2.0/sop-proceso-de-proyecto.md` | Proceso operativo del revendedor #1 |

---

*Documento generado a partir de la implementacion real del sistema de demos modulares — 2026-03-21*
