# Arquitectura de Assets con Cloudinary

## 🎯 Objetivo

Implementar una solución **escalable** para gestionar assets de miles de proyectos usando **Cloudinary** en lugar del filesystem local.

## ✅ Ventajas

### Escalabilidad
- ✅ **Sin límites de espacio**: Cloudinary maneja el almacenamiento
- ✅ **Sin archivos físicos**: No necesitas copiar assets al servidor
- ✅ **CDN automático**: Cloudinary sirve assets desde CDN global
- ✅ **Optimización automática**: Compresión, formatos modernos, etc.

### Propagación del Sistema
- ✅ **Código limpio**: No hay assets físicos en el repositorio
- ✅ **Actualizaciones sin conflictos**: Cada proyecto tiene sus assets en Cloudinary
- ✅ **Fácil migración**: Solo necesitas cambiar DB_DATABASE

## 🏗️ Arquitectura

### Estructura en Cloudinary

```
Cloudinary/
├── muma/
│   └── assets/
│       ├── logo.png
│       ├── favicon.ico
│       └── og-image.png
├── cokecolombres/
│   └── assets/
│       ├── logo.png
│       └── favicon.ico
└── proyecto3/
    └── assets/
        └── ...
```

### Flujo de Datos

```
1. assets.json (JSON con metadata)
   ↓
2. AssetsSeeder (sube a Cloudinary)
   ↓
3. Tabla assets (guarda public_id + secure_url)
   ↓
4. SiteDataSeeder (resuelve URLs desde assets)
   ↓
5. Tabla settings (guarda URLs de Cloudinary)
   ↓
6. SiteConfigServiceProvider (carga en config)
   ↓
7. Views (usan config('site.assets.main_logo'))
```

## 📋 Implementación

### 1. Servicio: ProjectAssetService

**Ubicación**: `app/Services/ProjectAssetService.php`

**Funcionalidades**:
- `uploadAsset()`: Sube asset a Cloudinary
- `getUrlFromPublicId()`: Genera URL desde public_id
- `deleteAsset()`: Elimina asset de Cloudinary
- `migrateLocalAssetsToCloudinary()`: Migra assets locales a Cloudinary

**Ejemplo**:
```php
$result = ProjectAssetService::uploadAsset(
    public_path('cd-project/assets/logo.png'),
    'logo.png'
);
// Retorna: ['public_id' => 'muma/assets/logo', 'secure_url' => 'https://...']
```

### 2. Seeder: AssetsSeeder

**Ubicación**: `database/seeders/AssetsSeeder.php`

**Funcionalidad**:
- Lee `assets.json`
- Si tiene `public_id` y `secure_url`, los usa (ya está en Cloudinary)
- Si no, intenta subir desde ruta local
- Guarda en tabla `assets` con `public_id` y `secure_url`

**Ejemplo de assets.json**:
```json
{
  "assets": [
    {
      "name": "logo.png",
      "path": "cd-project/assets/logo.png",
      "type": "logo",
      "public_id": "muma/assets/logo",
      "secure_url": "https://res.cloudinary.com/.../logo.png",
      "description": "Logo principal"
    }
  ]
}
```

### 3. Seeder: SiteDataSeeder

**Ubicación**: `database/seeders/SiteDataSeeder.php`

**Funcionalidad**:
- Lee `site-data.json`
- Resuelve URLs de assets desde tabla `assets`
- Si asset tiene `secure_url`, usa esa URL
- Si no, mantiene ruta local como fallback
- Guarda en tabla `settings`

**Ejemplo de site-data.json**:
```json
{
  "assets": {
    "main_logo": "cd-project/assets/logo.png"
  }
}
```

**Se resuelve a**:
```json
{
  "assets": {
    "main_logo": "https://res.cloudinary.com/.../logo.png"
  }
}
```

### 4. Modelo: Asset

**Ubicación**: `app/Models/Asset.php`

**Campos**:
- `name`: Nombre del archivo
- `path`: Ruta local (referencia)
- `type`: Tipo de asset (logo, favicon, etc.)
- `public_id`: ID de Cloudinary
- `secure_url`: URL completa de Cloudinary
- `description`, `width`, `height`: Metadata

## 🔄 Flujo de Trabajo

### Setup Inicial de Proyecto

1. **Preparar assets locales**:
   ```bash
   # Colocar assets en public/cd-project/assets/
   public/cd-project/assets/logo.png
   public/cd-project/assets/favicon.ico
   ```

2. **Configurar assets.json**:
   ```json
   {
     "assets": [
       {
         "name": "logo.png",
         "path": "cd-project/assets/logo.png",
         "type": "logo"
       }
     ]
   }
   ```

3. **Ejecutar seeders**:
   ```bash
   php artisan migrate
   php artisan db:seed --class=AssetsSeeder
   php artisan db:seed --class=SiteDataSeeder
   ```

4. **Resultado**:
   - Assets subidos a Cloudinary
   - URLs guardadas en DB
   - Sistema listo para usar

### Cambio de Proyecto

1. **Cambiar DB en .env**:
   ```env
   DB_DATABASE=bewpro-otro-proyecto
   ```

2. **Ejecutar seeders** (si es necesario):
   ```bash
   php artisan db:seed --class=AssetsSeeder
   php artisan db:seed --class=SiteDataSeeder
   php artisan config:clear
   ```

3. **Resultado**:
   - Assets del nuevo proyecto cargados desde Cloudinary
   - URLs actualizadas automáticamente
   - Sin necesidad de copiar archivos físicos

## 📝 Actualización de assets.json

### Opción 1: Con public_id y secure_url (Recomendado)

Si ya subiste los assets manualmente a Cloudinary:

```json
{
  "assets": [
    {
      "name": "logo.png",
      "path": "cd-project/assets/logo.png",
      "type": "logo",
      "public_id": "muma/assets/logo",
      "secure_url": "https://res.cloudinary.com/dupf7vvwj/image/upload/v1234567890/muma/assets/logo.png",
      "description": "Logo principal"
    }
  ]
}
```

### Opción 2: Solo con ruta local

Si quieres que AssetsSeeder los suba automáticamente:

```json
{
  "assets": [
    {
      "name": "logo.png",
      "path": "cd-project/assets/logo.png",
      "type": "logo",
      "description": "Logo principal"
    }
  ]
}
```

AssetsSeeder subirá el archivo a Cloudinary y guardará `public_id` y `secure_url`.

## 🔧 Configuración

### Variables de Entorno

```env
CLOUDINARY_CLOUD_NAME=dupf7vvwj
CLOUDINARY_API_KEY=413378447996456
CLOUDINARY_API_SECRET=pslFZxYtoWaGWj4IcvGSb26r1hw
CLOUDINARY_URL=cloudinary://413378447996456:pslFZxYtoWaGWj4IcvGSb26r1hw@dupf7vvwj
```

### Configuración en config/services.php

```php
'cloudinary' => [
    'cloud_name' => env('CLOUDINARY_CLOUD_NAME'),
    'api_key' => env('CLOUDINARY_API_KEY'),
    'api_secret' => env('CLOUDINARY_API_SECRET'),
],
```

## 🎯 Uso en Views

### Obtener URL de Asset

```php
// Desde config (ya resuelto desde DB)
$logoUrl = config('site.assets.main_logo');
// Retorna: "https://res.cloudinary.com/.../logo.png"

// Desde Asset model
$asset = Asset::where('type', 'logo')->first();
$logoUrl = $asset->secure_url;

// Desde ProjectAssetService
$logoUrl = ProjectAssetService::getAssetUrl('main_logo');
```

### En Blade Templates

```blade
{{-- Logo principal --}}
<img src="{{ config('site.assets.main_logo') }}" alt="{{ config('site.name') }}">

{{-- Favicon --}}
<link rel="icon" href="{{ config('site.assets.favicon') }}">

{{-- OG Image --}}
<meta property="og:image" content="{{ config('site.og.image') }}">
```

## ✅ Ventajas vs. Solución Anterior

### Antes (Carpetas por Proyecto)
- ❌ Archivos físicos en servidor
- ❌ Límite de espacio
- ❌ Necesitas copiar assets al cambiar proyecto
- ❌ No escalable para miles de proyectos

### Ahora (Cloudinary)
- ✅ Sin archivos físicos
- ✅ Sin límites de espacio
- ✅ Cambio automático al cambiar DB
- ✅ Escalable para miles de proyectos
- ✅ CDN global automático
- ✅ Optimización automática

## 🚀 Migración de Proyectos Existentes

### Migrar Assets Locales a Cloudinary

```php
// En tinker o comando artisan
$assets = Asset::whereNull('public_id')->get();

foreach ($assets as $asset) {
    if (file_exists(public_path($asset->path))) {
        $result = ProjectAssetService::uploadAsset(
            public_path($asset->path),
            $asset->name
        );
        
        if ($result) {
            $asset->public_id = $result['public_id'];
            $asset->secure_url = $result['secure_url'];
            $asset->save();
        }
    }
}
```

## 📊 Resumen

1. **Assets se suben a Cloudinary** con estructura `{project-name}/assets/{asset-name}`
2. **URLs se guardan en DB** (tabla `assets` y `settings`)
3. **Sistema carga URLs dinámicamente** desde DB al cambiar proyecto
4. **Sin archivos físicos** en el servidor
5. **Escalable** para miles de proyectos sin problemas
