# Guía Completa para Crear Módulos en CD-System

Esta guía documenta la estructura completa del módulo **MENU** como ejemplo y plantilla para crear cualquier otro módulo en CD-System.

---

## 📋 Tabla de Contenidos

1. [Estructura de Archivos](#estructura-de-archivos)
2. [Configuración del Módulo](#configuración-del-módulo)
3. [Base de Datos](#base-de-datos)
4. [Modelos](#modelos)
5. [Controladores](#controladores)
6. [Rutas](#rutas)
7. [Vistas](#vistas)
8. [JavaScript](#javascript)
9. [Permisos y Roles](#permisos-y-roles)
10. [Seeders](#seeders)
11. [Integración con el Sistema](#integración-con-el-sistema)
12. [Checklist para Nuevos Módulos](#checklist-para-nuevos-módulos)

---

## 📁 Estructura de Archivos

### Estructura Completa del Módulo MENU

```
cd-system/
├── app/
│   └── Modules/
│       └── Menu/
│           ├── Controllers/
│           │   ├── Admin/
│           │   │   ├── MenuController.php          # CRUD principal de menús
│           │   │   ├── MenuCategoryController.php   # CRUD de categorías
│           │   │   └── MenuProductController.php    # CRUD de productos
│           │   └── Frontend/
│           │       └── MenuController.php          # Controlador público
│           └── Models/
│               ├── Menu.php                        # Modelo principal
│               ├── MenuCategory.php                # Modelo de categorías
│               └── MenuProduct.php                 # Modelo de productos
│
├── database/
│   ├── migrations/
│   │   ├── YYYY_MM_DD_HHMMSS_create_menu_categories_table.php
│   │   ├── YYYY_MM_DD_HHMMSS_create_menus_table.php
│   │   ├── YYYY_MM_DD_HHMMSS_create_menu_products_table.php
│   │   └── YYYY_MM_DD_HHMMSS_create_menu_menu_product_table.php
│   └── seeders/
│       ├── project-data/
│       │   └── menu.json                          # Datos iniciales del módulo
│       ├── MenuPermissionsSeeder.php              # Crear permisos
│       └── AssignMenuPermissionsSeeder.php        # Asignar permisos a roles
│
├── resources/
│   ├── assets/
│   │   └── extended/
│   │       └── js/
│   │           └── custom/
│   │               └── menu/
│   │                   ├── manager.js             # JavaScript principal del manager
│   │                   ├── add.js                 # JavaScript para agregar menús
│   │                   ├── categories/
│   │                   │   ├── add.js
│   │                   │   ├── table.js
│   │                   │   └── update.js
│   │                   └── products/
│   │                       ├── add.js
│   │                       └── edit.js
│   └── views/
│       └── modules/
│           └── menu/
│               ├── admin/
│               │   ├── manager.blade.php           # Vista principal del manager
│               │   ├── index.blade.php            # Vista alternativa
│               │   ├── modals/
│               │   │   ├── add-menu.blade.php
│               │   │   ├── edit-menu.blade.php
│               │   │   ├── add-category.blade.php
│               │   │   ├── edit-category.blade.php
│               │   │   ├── add-product.blade.php
│               │   │   └── edit-product.blade.php
│               │   └── partials/
│               │       ├── menus-tab.blade.php
│               │       ├── categories-tab.blade.php
│               │       └── products-tab.blade.php
│               └── frontend/
│                   └── index.blade.php            # Vista pública del menú
│
├── routes/
│   └── modules/
│       └── menu.php                               # Rutas del módulo
│
└── config/
    ├── cd-system.php                              # Configuración del módulo
    └── demo1/
        └── module-menu.php                        # Configuración del menú del sidebar
```

---

## ⚙️ Configuración del Módulo

### 1. Configuración en `config/cd-system.php`

Agregar la configuración del módulo en la sección `modules`:

```php
'menu' => [
    'active' => false,  // true/false - Activar/desactivar módulo
    'name' => 'Menú',
    'description' => 'Gestión de menús del restaurante',
    'version' => '1.0.0',
    'navigation' => [
        'header' => true,   // Mostrar en header del frontend
        'footer' => false,  // Mostrar en footer del frontend
    ],
],
```

**Ubicación**: `config/cd-system.php` línea ~254

**Nota**: El valor `active` se puede sobrescribir desde `database/seeders/project-data/cd-system.json`

---

### 2. Configuración del Menú del Sidebar en `config/demo1/module-menu.php`

Agregar la entrada del menú para que aparezca en el sidebar del admin:

```php
// Menu Module
[
    'title' => 'Menu',  // IMPORTANTE: Debe coincidir con la clave del módulo en cd-system.php
    'role' => ['System Admin', 'Administrator', 'Contributor', 'Editor', 'Author'],
    'path' => 'menu-settings',
    'permission' => ['view_menus'],  // Permisos requeridos
    'icon' => [
        'svg' => theme()->getSvgIcon(
            'demo1/media/icons/duotune/general/gen025.svg',
            'svg-icon-2'
        ),
        'font' => '<i class="bi bi-menu-button-wide fs-2"></i>',
    ],
],
```

**Ubicación**: `config/demo1/module-menu.php`

**Nota**: El `title` debe coincidir exactamente con la clave del módulo en `cd-system.php` (sin acentos, en minúsculas). El sistema normaliza los nombres para hacer la comparación.

---

## 🗄️ Base de Datos

### Migraciones

#### 1. Tabla de Categorías (`menu_categories`)

```php
Schema::create('menu_categories', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('slug')->unique();
    $table->text('description')->nullable();
    $table->boolean('is_featured')->default(false);
    $table->integer('order')->default(0);
    $table->timestamps();
    $table->softDeletes();
});
```

**Archivo**: `database/migrations/YYYY_MM_DD_HHMMSS_create_menu_categories_table.php`

---

#### 2. Tabla Principal (`menus`)

```php
Schema::create('menus', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('slug')->unique();
    $table->text('description')->nullable();
    $table->unsignedBigInteger('menu_category_id');
    $table->integer('order')->default(0);
    $table->boolean('is_active')->default(true);
    $table->timestamps();
    $table->softDeletes();

    $table->foreign('menu_category_id')
          ->references('id')
          ->on('menu_categories')
          ->onDelete('cascade');
});
```

**Archivo**: `database/migrations/YYYY_MM_DD_HHMMSS_create_menus_table.php`

---

#### 3. Tabla de Productos (`menu_products`)

```php
Schema::create('menu_products', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('slug')->unique();
    $table->text('description')->nullable();
    $table->decimal('price', 10, 2)->default(0);
    $table->string('image')->nullable();
    $table->boolean('is_active')->default(true);
    $table->integer('order')->default(0);
    $table->unsignedBigInteger('menu_category_id')->nullable();
    $table->timestamps();
    $table->softDeletes();

    $table->foreign('menu_category_id')
          ->references('id')
          ->on('menu_categories')
          ->onDelete('set null');
    
    $table->index('slug');
    $table->index('is_active');
    $table->index('menu_category_id');
});
```

**Archivo**: `database/migrations/YYYY_MM_DD_HHMMSS_create_menu_products_table.php`

---

#### 4. Tabla Pivot (`menu_menu_product`)

```php
Schema::create('menu_menu_product', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('menu_id');
    $table->unsignedBigInteger('menu_product_id');
    $table->integer('order')->default(0);
    $table->timestamps();

    $table->foreign('menu_id')
          ->references('id')
          ->on('menus')
          ->onDelete('cascade');
    
    $table->foreign('menu_product_id')
          ->references('id')
          ->on('menu_products')
          ->onDelete('cascade');

    $table->unique(['menu_id', 'menu_product_id']);
});
```

**Archivo**: `database/migrations/YYYY_MM_DD_HHMMSS_create_menu_menu_product_table.php`

---

### Ejecutar Migraciones

```bash
php artisan migrate
```

---

## 🎯 Modelos

### 1. Modelo Principal: `Menu`

**Ubicación**: `app/Modules/Menu/Models/Menu.php`

**Características principales**:
- SoftDeletes
- Generación automática de slug único
- Relaciones: `category()`, `products()`
- Scopes: `active()`, `ordered()`, `byCategory()`, `featured()`, `search()`

**Ejemplo**:

```php
<?php

namespace App\Modules\Menu\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Menu extends Model
{
    use SoftDeletes;

    protected $table = 'menus';

    protected $fillable = [
        'name',
        'slug',
        'description',
        'menu_category_id',
        'is_active',
        'order',
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'order' => 'integer',
    ];

    // Relación: Un menú pertenece a una categoría
    public function category()
    {
        return $this->belongsTo(MenuCategory::class, 'menu_category_id');
    }

    // Relación: Un menú puede tener múltiples productos (many-to-many)
    public function products()
    {
        return $this->belongsToMany(MenuProduct::class, 'menu_menu_product', 'menu_id', 'menu_product_id')
                    ->withPivot('order')
                    ->withTimestamps()
                    ->orderBy('menu_menu_product.order', 'asc');
    }

    // Scopes
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    public function scopeOrdered($query)
    {
        return $query->orderBy('order', 'asc');
    }

    // Mutator para generar slug único automáticamente
    public function setNameAttribute($value)
    {
        $this->attributes['name'] = $value;
        
        $baseSlug = Str::slug($value);
        $slug = $baseSlug;
        $counter = 1;
        
        while (static::withTrashed()
            ->where('slug', $slug)
            ->where('id', '!=', $this->id ?? 0)
            ->exists()) {
            $slug = $baseSlug . '-' . $counter;
            $counter++;
        }

        $this->attributes['slug'] = $slug;
    }
}
```

---

### 2. Modelo de Categorías: `MenuCategory`

**Ubicación**: `app/Modules/Menu/Models/MenuCategory.php`

**Características**:
- Relación `hasMany` con `Menu`
- Scopes: `featured()`, `ordered()`, `active()`
- Generación automática de slug único

---

### 3. Modelo de Productos: `MenuProduct`

**Ubicación**: `app/Modules/Menu/Models/MenuProduct.php`

**Características**:
- Relación `belongsToMany` con `Menu`
- Relación `belongsTo` con `MenuCategory`
- Manejo de imágenes con Storage
- Scopes: `active()`, `ordered()`, `byCategory()`

---

## 🎮 Controladores

### Estructura de Controladores Admin

#### 1. Controlador Principal: `MenuController`

**Ubicación**: `app/Modules/Menu/Controllers/Admin/MenuController.php`

**Métodos principales**:
- `manager()` - Vista principal del manager unificado
- `getStats()` - Obtener estadísticas para AJAX
- `index()` - Lista de menús
- `getMenus()` - Datos para DataTables
- `create()` - Formulario de creación
- `store()` - Guardar nuevo menú
- `show($id)` - Mostrar menú específico (para AJAX)
- `update($id)` - Actualizar menú
- `destroy($id)` - Eliminar menú
- `destroyMultiple()` - Eliminar múltiples menús
- `toggleActive($id)` - Alternar estado activo/inactivo

**Características**:
- Middleware de permisos en el constructor
- Verificación de módulo activo
- Validación de datos
- Respuestas JSON para AJAX
- Manejo de relaciones many-to-many

**Ejemplo de constructor**:

```php
public function __construct()
{
    // Verificar que el módulo esté habilitado
    if (!config('cd-system.modules.menu.active', false)) {
        abort(404, 'Menu module is disabled');
    }

    // Middleware de permisos
    $this->middleware('permission:view_menus')->only(['index']);
    $this->middleware('permission:create_menus')->only(['create', 'store']);
    $this->middleware('permission:edit_menus')->only(['edit', 'update']);
    $this->middleware('permission:delete_menus')->only(['destroy', 'destroyMultiple']);
}
```

---

#### 2. Controlador de Categorías: `MenuCategoryController`

**Ubicación**: `app/Modules/Menu/Controllers/Admin/MenuCategoryController.php`

**Métodos**:
- `index()` - Vista de categorías
- `getCategories()` - Datos para DataTables
- `show($id)` - Mostrar categoría específica
- `store()` - Crear categoría
- `update($id)` - Actualizar categoría
- `destroy($id)` - Eliminar categoría
- `destroyMultiple()` - Eliminar múltiples categorías

---

#### 3. Controlador de Productos: `MenuProductController`

**Ubicación**: `app/Modules/Menu/Controllers/Admin/MenuProductController.php`

**Métodos**:
- `getProducts()` - Datos para DataTables
- `show($id)` - Mostrar producto específico
- `store()` - Crear producto
- `update($id)` - Actualizar producto
- `destroy($id)` - Eliminar producto
- `destroyMultiple()` - Eliminar múltiples productos

**Características especiales**:
- Manejo de subida de imágenes
- Validación de archivos
- Eliminación de imágenes al borrar productos

---

### Controlador Frontend: `MenuController`

**Ubicación**: `app/Modules/Menu/Controllers/Frontend/MenuController.php`

**Métodos**:
- `index()` - Lista de menús públicos
- `byCategory($slug)` - Menús por categoría
- `show($slug)` - Mostrar menú específico
- `search()` - Buscar menús

**Características**:
- Solo muestra menús y productos activos
- Optimización con eager loading
- Filtrado por estado activo en relaciones

---

## 🛣️ Rutas

### Archivo de Rutas: `routes/modules/menu.php`

**Estructura**:

```php
<?php

use Illuminate\Support\Facades\Route;

// ==========================================
// MENU ADMIN MODULE (Dashboard)
// ==========================================
Route::middleware(['auth'])->group(function () {
    // Vista unificada del manager
    Route::prefix('menu-settings')->name('menu-settings.')->group(function () {
        Route::get('/', [MenuController::class, 'manager'])->name('index');
        Route::get('/stats', [MenuController::class, 'getStats'])->name('stats');
    });

    Route::prefix('menus')->name('menus.')->group(function () {
        // IMPORTANTE: Rutas específicas ANTES de rutas con {id}
        
        // Categorías
        Route::get('/categories/get-categories', [MenuCategoryController::class, 'getCategories'])->name('categories_data');
        Route::get('/categories/show/{id}', [MenuCategoryController::class, 'show'])->name('show_category');
        Route::post('/categories', [MenuCategoryController::class, 'store'])->name('store_category');
        Route::put('/categories/{id}', [MenuCategoryController::class, 'update'])->name('update_category');
        Route::delete('/categories/{id}', [MenuCategoryController::class, 'destroy'])->name('delete_category');
        Route::delete('/categories/destroy-multiple', [MenuCategoryController::class, 'destroyMultiple'])->name('delete_multiple_categories');

        // Productos
        Route::get('/products/get-products', [MenuProductController::class, 'getProducts'])->name('products_data');
        Route::get('/products/show/{id}', [MenuProductController::class, 'show'])->name('show_product');
        Route::post('/products', [MenuProductController::class, 'store'])->name('store_product');
        Route::put('/products/{id}', [MenuProductController::class, 'update'])->name('update_product');
        Route::delete('/products/{id}', [MenuProductController::class, 'destroy'])->name('delete_product');
        Route::delete('/products/destroy-multiple', [MenuProductController::class, 'destroyMultiple'])->name('delete_multiple_products');

        // Menús (rutas con {id} al final)
        Route::get('/get-menus', [MenuController::class, 'getMenus'])->name('data');
        Route::post('/', [MenuController::class, 'store'])->name('store');
        Route::get('/{id}', [MenuController::class, 'show'])->name('show');
        Route::put('/{id}', [MenuController::class, 'update'])->name('update');
        Route::delete('/{id}', [MenuController::class, 'destroy'])->name('destroy');
    });
});

// ==========================================
// MENU FRONTEND MODULE (Public)
// ==========================================
Route::middleware(['maintenance:menu', 'module.enabled:menu'])
    ->prefix('menu')
    ->name('front.menu.')
    ->group(function () {
        Route::get('/', [MenuController::class, 'index'])->name('index');
        Route::get('/category/{slug}', [MenuController::class, 'byCategory'])->name('category');
        Route::get('/{slug}', [MenuController::class, 'show'])->name('show');
        Route::get('/search', [MenuController::class, 'search'])->name('search');
    });
```

**Reglas importantes**:
1. **Orden de rutas**: Las rutas específicas (como `/categories`, `/products`) deben ir ANTES de las rutas con parámetros dinámicos (`/{id}`, `/{slug}`)
2. **Middleware**: Admin usa `auth`, Frontend usa `maintenance:menu` y `module.enabled:menu`
3. **Nombres de rutas**: Usar prefijos consistentes (`menus.`, `front.menu.`)

**Registro en `routes/cd-system.php`**:

```php
require __DIR__ . '/modules/menu.php';
```

---

## 🎨 Vistas

### Estructura de Vistas Admin

#### 1. Vista Principal: `manager.blade.php`

**Ubicación**: `resources/views/modules/menu/admin/manager.blade.php`

**Características**:
- Extiende `x-base-layout`
- Incluye header del módulo con `x-admin-header`
- Estadísticas en la parte superior
- Tabs para diferentes secciones (Menús, Categorías, Productos)
- Incluye modales y partials

**Estructura**:

```blade
<x-base-layout>
    <x-admin-header module="menu" />
    
    <!-- Stats Bar -->
    <div class="card mb-4">
        <!-- Estadísticas -->
    </div>
    
    <!-- Tabs Card -->
    <div class="card">
        <div class="card-header">
            <!-- Nav Tabs -->
        </div>
        <div class="card-body">
            <!-- Tab Content -->
            @include('modules.menu.admin.partials.menus-tab')
            @include('modules.menu.admin.partials.categories-tab')
            @include('modules.menu.admin.partials.products-tab')
        </div>
    </div>
    
    <!-- Modals -->
    @include('modules.menu.admin.modals.add-menu')
    @include('modules.menu.admin.modals.edit-menu')
    <!-- ... más modales ... -->
    
    @push('scripts')
        <!-- JavaScript files -->
    @endpush
</x-base-layout>
```

---

#### 2. Partials (Tabs)

**Ubicación**: `resources/views/modules/menu/admin/partials/`

**Archivos**:
- `menus-tab.blade.php` - Tabla de menús con DataTables
- `categories-tab.blade.php` - Tabla de categorías
- `products-tab.blade.php` - Tabla de productos

**Estructura de un tab**:

```blade
<!--begin::Table Header-->
<div class="d-flex flex-wrap align-items-center justify-content-between gap-3 mb-4">
    <!--begin::Filters-->
    <div class="d-flex align-items-center gap-2">
        <!-- Search input -->
    </div>
    <!--end::Filters-->
    
    <!--begin::Actions-->
    <div class="d-flex align-items-center gap-2">
        <!-- Add button -->
        <!-- Selected toolbar -->
    </div>
    <!--end::Actions-->
</div>

<!--begin::Table-->
<div class="table-responsive">
    <table class="table align-middle table-row-dashed fs-6 gy-5" id="kt_[nombre]_table">
        <!-- DataTables columns -->
    </table>
</div>
```

---

#### 3. Modales

**Ubicación**: `resources/views/modules/menu/admin/modals/`

**Archivos**:
- `add-menu.blade.php` - Modal para agregar menú
- `edit-menu.blade.php` - Modal para editar menú
- `add-category.blade.php` - Modal para agregar categoría
- `edit-category.blade.php` - Modal para editar categoría
- `add-product.blade.php` - Modal para agregar producto
- `edit-product.blade.php` - Modal para editar producto

**Estructura de un modal**:

```blade
<div class="modal fade" id="kt_modal_add_[nombre]" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered modal-lg">
        <div class="modal-content">
            <form class="form" action="{{ route('[ruta].store') }}" id="new_form_[nombre]">
                @csrf
                <div class="modal-header">
                    <h2 class="fw-bold">Nuevo [Nombre]</h2>
                    <!-- Close button -->
                </div>
                <div class="modal-body px-5 my-7">
                    <!-- Form fields -->
                </div>
                <div class="modal-footer">
                    <!-- Buttons -->
                </div>
            </form>
        </div>
    </div>
</div>
```

---

### Vista Frontend: `index.blade.php`

**Ubicación**: `resources/views/modules/menu/frontend/index.blade.php`

**Características**:
- Extiende `layout.front.master`
- Reutiliza estilos del tema (sin modificarlos)
- Muestra datos dinámicos desde la base de datos
- Estructura responsive

**Estructura**:

```blade
@extends('layout.front.master')

@section('content')
    <!-- Page Header -->
    
    <!-- Menu Section -->
    <div id="menu" class="container py-4 my-5">
        @foreach($categories as $category)
            @foreach($category->menus as $menu)
                @foreach($menu->products as $product)
                    <!-- Product item -->
                @endforeach
            @endforeach
        @endforeach
    </div>
@endsection
```

---

## 📜 JavaScript

### Estructura de Archivos JavaScript

**Ubicación**: `resources/assets/extended/js/custom/menu/`

**Archivos principales**:

1. **`manager.js`** - JavaScript principal del manager
   - Inicializa DataTables
   - Maneja tabs
   - Gestiona estadísticas
   - Event listeners para acciones

2. **`add.js`** - Formulario de agregar menú
   - Validación con FormValidation
   - Envío AJAX con Axios
   - Manejo de checkboxes (is_active)

3. **`categories/add.js`** - Formulario de agregar categoría
4. **`products/add.js`** - Formulario de agregar producto
5. **`products/edit.js`** - Formulario de editar producto

### Estructura de `manager.js`

```javascript
"use strict";

var KTMenuManager = function () {
    // Private variables
    var menusTable, categoriesTable, productsTable;
    var currentTab = 'menus';

    // Initialize all components
    var init = function () {
        // Setup AJAX defaults
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
                'X-Requested-With': 'XMLHttpRequest'
            },
            withCredentials: true
        });

        initStats();
        initTabs();
        initMenusTable();
        initCategoriesTable();
        initProductsTable();
        initModals();
        updateStats();
    };

    // DataTables initialization
    var initMenusTable = function () {
        menusTable = $('#kt_menus_table').DataTable({
            // Configuración DataTables
        });
    };

    // Public API
    return {
        init: init
    };
}();

// Initialize on DOM ready
KTUtil.onDOMContentLoaded(function () {
    KTMenuManager.init();
});
```

### Características Importantes

1. **CSRF Token**: Siempre incluir en headers AJAX
2. **withCredentials**: Necesario para mantener sesión
3. **DataTables**: Configurar con `serverSide: true` para grandes volúmenes
4. **FormValidation**: Usar para validación de formularios
5. **Axios**: Para peticiones AJAX
6. **SweetAlert2**: Para notificaciones

### Compilación de Assets

Los archivos JavaScript deben compilarse con `npm run dev` y se copian a:
- `public/demo1/extended/js/custom/menu/`

**Configuración en `webpack.mix.js`**:

```javascript
// Extend custom js files for laravel
(glob.sync('resources/assets/extended/js/**/*.js') || []).forEach(file => {
    var output = `public/${demo}/${file.replace('resources/assets/extended/', '')}`;
    mix.scripts(file, output);
});
```

---

## 🔐 Permisos y Roles

### 1. Crear Permisos: `MenuPermissionsSeeder`

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

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;

class MenuPermissionsSeeder extends Seeder
{
    public function run()
    {
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        $permissions = [
            'view_menus',
            'create_menus', 
            'edit_menus',
            'delete_menus',
        ];

        foreach ($permissions as $permission) {
            Permission::firstOrCreate(['name' => $permission]);
        }
    }
}
```

**Ejecutar**:
```bash
php artisan db:seed --class=MenuPermissionsSeeder
```

---

### 2. Asignar Permisos a Roles: `AssignMenuPermissionsSeeder`

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

```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;

class AssignMenuPermissionsSeeder extends Seeder
{
    public function run()
    {
        $permissions = [
            'view_menus',
            'create_menus', 
            'edit_menus',
            'delete_menus',
        ];

        $adminRoles = ['System Admin', 'Administrator', 'Contributor', 'Editor', 'Author'];
        
        foreach ($adminRoles as $roleName) {
            $role = Role::where('name', $roleName)->first();
            if ($role) {
                $role->givePermissionTo($permissions);
            }
        }
    }
}
```

**Ejecutar**:
```bash
php artisan db:seed --class=AssignMenuPermissionsSeeder
```

---

### 3. Uso de Permisos en Controladores

```php
public function __construct()
{
    $this->middleware('permission:view_menus')->only(['index']);
    $this->middleware('permission:create_menus')->only(['create', 'store']);
    $this->middleware('permission:edit_menus')->only(['edit', 'update']);
    $this->middleware('permission:delete_menus')->only(['destroy']);
}
```

---

## 🌱 Seeders

### 1. Datos Iniciales: `menu.json`

**Ubicación**: `database/seeders/project-data/menu.json`

```json
{
  "categories": [
    {
      "name": "Menú del Día",
      "slug": "menu-del-dia",
      "description": "Platos especiales del día",
      "is_featured": true,
      "order": 1
    }
  ],
  "menus": [
    {
      "name": "Menú del Día Especial",
      "slug": "menu-del-dia-especial",
      "description": "Nuestra selección especial del día",
      "category": "Menú del Día",
      "is_active": true,
      "order": 1
    }
  ]
}
```

**Nota**: Este archivo se procesa en el `Project_Seeder` principal.

---

### 2. Seeder de Permisos

Ya documentado en la sección [Permisos y Roles](#permisos-y-roles).

---

## 🔗 Integración con el Sistema

### 1. Service Provider para Menú del Sidebar

El sistema usa `ModuleMenuServiceProvider` para cargar dinámicamente los menús de los módulos activos en el sidebar.

**Ubicación**: `app/Providers/ModuleMenuServiceProvider.php`

**Funcionamiento**:
1. Lee `config/demo1/module-menu.php`
2. Verifica si el módulo está activo en `config/cd-system.modules.[nombre].active`
3. Inserta el menú en la posición correcta
4. Filtra por permisos del usuario

**No requiere modificación** para nuevos módulos, solo agregar la entrada en `config/demo1/module-menu.php`.

---

### 2. Deshabilitar Rutas Estáticas

Si existe una ruta estática para el mismo path, debe comentarse o eliminarse.

**Ejemplo** en `routes/modules/cd-base.php`:

```php
// Route deshabilitada - Ahora se usa el módulo Menu dinámico
// Route::middleware(['maintenance:menu', 'module.enabled:menu'])->group(function () {
//     Route::get('/menu', [HomepageController::class, 'menu'])->name('menu');
// });
```

---

### 3. Limpiar Caché

Después de crear/modificar un módulo:

```bash
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear
```

---

## ✅ Checklist para Nuevos Módulos

Usa esta checklist como guía para crear cualquier nuevo módulo:

### 📋 Configuración

- [ ] Agregar módulo en `config/cd-system.php` (sección `modules`)
- [ ] Agregar entrada en `config/demo1/module-menu.php` (menú del sidebar)
- [ ] Verificar que `active` esté configurado correctamente
- [ ] Comentar/eliminar rutas estáticas conflictivas

### 🗄️ Base de Datos

- [ ] Crear migraciones para todas las tablas necesarias
- [ ] Incluir `timestamps()` y `softDeletes()` cuando corresponda
- [ ] Definir relaciones con foreign keys
- [ ] Agregar índices para campos de búsqueda frecuente
- [ ] Ejecutar migraciones: `php artisan migrate`

### 🎯 Modelos

- [ ] Crear modelos en `app/Modules/[Nombre]/Models/`
- [ ] Definir `$fillable` y `$casts`
- [ ] Implementar relaciones Eloquent
- [ ] Crear scopes útiles (`active()`, `ordered()`, etc.)
- [ ] Implementar mutators para slugs únicos
- [ ] Agregar accessors si es necesario

### 🎮 Controladores

- [ ] Crear controladores Admin en `app/Modules/[Nombre]/Controllers/Admin/`
- [ ] Crear controlador Frontend en `app/Modules/[Nombre]/Controllers/Frontend/`
- [ ] Implementar middleware de permisos en constructores
- [ ] Verificar módulo activo en constructores
- [ ] Implementar métodos CRUD completos
- [ ] Agregar métodos para DataTables (`get[Nombre]s()`)
- [ ] Implementar validación de datos
- [ ] Manejar respuestas JSON para AJAX

### 🛣️ Rutas

- [ ] Crear archivo `routes/modules/[nombre].php`
- [ ] Definir rutas Admin con middleware `auth`
- [ ] Definir rutas Frontend con middleware `maintenance` y `module.enabled`
- [ ] **ORDEN IMPORTANTE**: Rutas específicas antes de rutas con `{id}` o `{slug}`
- [ ] Registrar rutas en `routes/cd-system.php`
- [ ] Limpiar caché de rutas: `php artisan route:clear`

### 🎨 Vistas

- [ ] Crear estructura de directorios en `resources/views/modules/[nombre]/`
- [ ] Crear vista principal `admin/manager.blade.php`
- [ ] Crear partials para tabs si es necesario
- [ ] Crear modales para agregar/editar
- [ ] Crear vista frontend `frontend/index.blade.php`
- [ ] Reutilizar estilos existentes (no modificar CSS)
- [ ] Incluir componentes Metronic correctamente

### 📜 JavaScript

- [ ] Crear estructura en `resources/assets/extended/js/custom/[nombre]/`
- [ ] Crear `manager.js` principal
- [ ] Crear archivos JS para formularios (`add.js`, `edit.js`)
- [ ] Incluir CSRF token en todas las peticiones AJAX
- [ ] Configurar DataTables correctamente
- [ ] Usar FormValidation para formularios
- [ ] Compilar assets: `npm run dev`
- [ ] Verificar que los archivos se copien a `public/demo1/extended/js/custom/[nombre]/`

### 🔐 Permisos

- [ ] Crear `[Nombre]PermissionsSeeder.php`
- [ ] Definir permisos: `view_[nombre]s`, `create_[nombre]s`, `edit_[nombre]s`, `delete_[nombre]s`
- [ ] Crear `Assign[Nombre]PermissionsSeeder.php`
- [ ] Asignar permisos a roles de administrador
- [ ] Ejecutar seeders: `php artisan db:seed --class=[Nombre]PermissionsSeeder`
- [ ] Ejecutar asignación: `php artisan db:seed --class=Assign[Nombre]PermissionsSeeder`

### 🌱 Seeders

- [ ] Crear archivo JSON en `database/seeders/project-data/[nombre].json`
- [ ] Definir estructura de datos iniciales
- [ ] Integrar en `Project_Seeder` principal si es necesario

### 🧪 Pruebas

- [ ] Verificar que el módulo aparece en el sidebar cuando está activo
- [ ] Probar creación de registros desde el admin
- [ ] Probar edición de registros
- [ ] Probar eliminación (simple y múltiple)
- [ ] Verificar que DataTables carga correctamente
- [ ] Probar filtros y búsqueda
- [ ] Verificar permisos funcionan correctamente
- [ ] Probar vista frontend muestra datos dinámicos
- [ ] Verificar que rutas funcionan correctamente
- [ ] Limpiar todas las cachés después de cambios

---

## 📝 Convenciones de Nomenclatura

### Archivos y Clases

- **Modelos**: PascalCase singular (`Menu`, `MenuCategory`, `MenuProduct`)
- **Controladores**: PascalCase con sufijo `Controller` (`MenuController`, `MenuCategoryController`)
- **Vistas**: kebab-case (`manager.blade.php`, `add-menu.blade.php`)
- **JavaScript**: camelCase (`manager.js`, `addMenu.js`)
- **Migraciones**: snake_case con prefijo de fecha (`2026_01_30_114735_create_menu_categories_table.php`)

### Base de Datos

- **Tablas**: snake_case plural (`menu_categories`, `menus`, `menu_products`)
- **Tablas pivot**: snake_case con nombres de ambas tablas (`menu_menu_product`)
- **Columnas**: snake_case (`menu_category_id`, `is_active`, `created_at`)

### Rutas

- **Prefijos**: kebab-case (`menu-settings`, `menus`)
- **Nombres**: dot notation (`menus.store`, `front.menu.index`)

---

## 🔍 Ejemplos de Relaciones

### One-to-Many

```php
// MenuCategory tiene muchos Menu
public function menus()
{
    return $this->hasMany(Menu::class, 'menu_category_id');
}

// Menu pertenece a MenuCategory
public function category()
{
    return $this->belongsTo(MenuCategory::class, 'menu_category_id');
}
```

### Many-to-Many

```php
// Menu tiene muchos MenuProduct
public function products()
{
    return $this->belongsToMany(MenuProduct::class, 'menu_menu_product', 'menu_id', 'menu_product_id')
                ->withPivot('order')
                ->withTimestamps()
                ->orderBy('menu_menu_product.order', 'asc');
}

// MenuProduct pertenece a muchos Menu
public function menus()
{
    return $this->belongsToMany(Menu::class, 'menu_menu_product', 'menu_product_id', 'menu_id')
                ->withPivot('order')
                ->withTimestamps();
}
```

---

## 🎨 Patrones de Diseño Utilizados

### 1. Manager Unificado

Un solo controlador (`MenuController`) gestiona múltiples entidades relacionadas mediante tabs.

**Ventajas**:
- Interfaz unificada
- Compartir estadísticas
- Mejor UX

### 2. Separación de Productos

El módulo Menu tiene sus propios productos (`MenuProduct`) independientes del módulo Products global.

**Ventajas**:
- Desacoplamiento de módulos
- Flexibilidad
- Escalabilidad

### 3. SoftDeletes

Todos los modelos principales usan `SoftDeletes` para mantener integridad referencial.

**Ventajas**:
- Recuperación de datos
- Auditoría
- Integridad referencial

---

## 🚀 Comandos Útiles

### Crear Componentes

```bash
# Crear migración
php artisan make:migration create_[nombre]_table

# Crear modelo
php artisan make:model Modules/[Nombre]/Models/[Nombre]

# Crear controlador
php artisan make:controller Modules/[Nombre]/Controllers/Admin/[Nombre]Controller
php artisan make:controller Modules/[Nombre]/Controllers/Frontend/[Nombre]Controller

# Crear seeder
php artisan make:seeder [Nombre]PermissionsSeeder
php artisan make:seeder Assign[Nombre]PermissionsSeeder
```

### Ejecutar Operaciones

```bash
# Migraciones
php artisan migrate
php artisan migrate:rollback

# Seeders
php artisan db:seed --class=[Nombre]PermissionsSeeder
php artisan db:seed --class=Assign[Nombre]PermissionsSeeder

# Limpiar caché
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear

# Compilar assets
npm run dev
npm run watch  # Para desarrollo
```

---

## 📚 Recursos Adicionales

### Documentación de Laravel

- [Eloquent Relationships](https://laravel.com/docs/eloquent-relationships)
- [Migrations](https://laravel.com/docs/migrations)
- [Routing](https://laravel.com/docs/routing)
- [Blade Templates](https://laravel.com/docs/blade)

### Documentación de Spatie Permission

- [Laravel Permission](https://spatie.be/docs/laravel-permission)

### Documentación de DataTables

- [Yajra DataTables](https://yajrabox.com/docs/laravel-datatables)

---

## 🎯 Resumen del Flujo Completo

1. **Configuración**: Agregar módulo en `cd-system.php` y `module-menu.php`
2. **Base de Datos**: Crear migraciones y ejecutarlas
3. **Modelos**: Crear modelos con relaciones y scopes
4. **Controladores**: Crear controladores Admin y Frontend
5. **Rutas**: Definir rutas en `routes/modules/[nombre].php`
6. **Vistas**: Crear vistas admin y frontend
7. **JavaScript**: Crear archivos JS y compilar
8. **Permisos**: Crear y asignar permisos
9. **Seeders**: Crear datos iniciales
10. **Pruebas**: Verificar funcionamiento completo

---

## 📌 Notas Importantes

1. **Orden de Rutas**: Siempre poner rutas específicas antes de rutas con parámetros dinámicos
2. **CSRF Token**: Incluir en todas las peticiones AJAX
3. **Permisos**: Verificar en constructores de controladores
4. **Caché**: Limpiar después de cambios importantes
5. **Assets**: Compilar con `npm run dev` después de crear/modificar JS
6. **Nombres**: Mantener consistencia en nomenclatura
7. **Estilos**: Reutilizar, no modificar estilos existentes
8. **Relaciones**: Optimizar con eager loading en consultas

---

**Última actualización**: Febrero 2026
**Versión del documento**: 1.0.0
**Módulo de referencia**: Menu

