# AGENTS.md — Users (Laravel 13 + Jetstream + Livewire 4)

## Quick start

```bash
cp .env.example .env && composer install --ignore-platform-req=ext-bcmath && npm install
php artisan key:generate
php artisan migrate --seed
npm run build
```

Default superadmin: `super@admin` / `**admin`

## Key commands

| Command | What |
|---|---|
| `php artisan serve` | Start dev server (PHP 8.5+ del sistema, no XAMPP) |
| `composer dev` | Server + queue + logs + Vite concurrently |
| `npm run dev` | Vite dev server only |
| `php artisan migrate --seed` | Migrate + seed (roles, superadmin, default system data) |
| `php artisan db:seed --class=RoleSeeder` | Seed roles/permissions only |
| `php artisan permissions:sync` | Sync modules & permissions from `config/permissions.php` to DB |
| `php artisan permissions:sync --clean` | Same + removes stale permissions not in config |
| `php artisan test` | All tests |
| `php artisan test --filter=ExampleTest` | Single test |
| `composer pint` | Lint (Laravel Pint) |

## Architecture

- **UI**: Livewire 4 components in `App\Livewire\` — use `WithPagination` trait + `$listeners` for SweetAlert2 events
- **Auth**: Jetstream (Livewire stack) + Fortify + Sanctum. Routes authenticated via `auth:sanctum`, `verified`, and `jetstream.auth_session`
- **RBAC**: Spatie Laravel Permission v6.25+. Permisos dinámicos agrupados por módulo (tabla `modules` + `module_id` en `permissions`). Sincronización vía `config/permissions.php` + `php artisan permissions:sync`. Rutas guardadas con `role:Superadministrador|Administrador` middleware. Vistas usan `@can('modulo.accion')`.
- **Localization**: `mcamara/laravel-localization`. Each module has its own lang file in `lang/{locale}/` (e.g. `lang/es/createuser.php`). App locale defaults to `es`
- **DB**: MySQL in current `.env`. Session, cache, and queue all use `database` driver
- **System config**: Single-row `sistema` table (id=1) for company name, logo, RIF, address, phone

## Routes (web.php, authenticated)

| Path | View | Purpose |
|---|---|---|
| `/dashboard` | `dashboard` | Dashboard with real-time stats, user activity, role distribution |
| `/users` | `users` | User list with search/pagination/perm modal |
| `/infouser/{id?}` | `infouser` | User detail view |
| `/createuser` | `createuser` | Create user (email + role, sends welcome mail) |
| `/edituser/{id?}` | `edituser` | Edit user, reset password, change role/status |
| `/config` | `config` | System configuration |
| `/editsistema` | `editsistema` | Edit company data/logo |
| `/roles` | `roles` | Role CRUD + permission assignment |
| `/permisos` | `permisos` | Permission list with CRUD, module grouping |

## Livewire components (14)

- **Dashboard** — real-time system stats: user count, active/inactive, roles, event activity (permission-gated), users-by-role bar chart, recent activity feed
- **SearchBar** — smart search in navbar: real-time results, filtered by permissions, keyboard navigation
- **ShowUsers** — paginated user list, search, delete confirmation modal, inline permission toggle per user
- **CreateUser** — create user by email, assign role, send `WelcomeNewUser` mail with temp password
- **EditUser** — edit profile fields, reset password (sends `PasswordResetMail`), toggle status (1=active/2=inactive), change role
- **InfoUser** — read-only user detail with identification, contract, profile photo initials fallback
- **Roles** — CRUD roles, assign/revoke permissions per role (agrupados por módulo), remove role from users on delete
- **Permisos** — CRUD permissions, module assignment, paginated list with user count per permission
- **EditSistema** — single-row company config with logo upload via `WithFileUploads`
- **Alerts, AlertsModule** — alert/notification placeholders
- **Favicon, Logo** — display system logo from `sistema` table
- **LanguageSwitcher** — toggle locale (stored in session)

## Lang file conventions

- Module-specific files: `lang/{es,en}/createuser.php`, `showusers.php`, `roles.php`, etc.
- Shared messages: `lang/{es,en}/messages.php` (status updates, delete confirmations)
- Jetstream UI strings: `lang/{es,en}.json`
- If adding a new lang file, mirror it for both `es/` and `en/` directories

## Seeder (database/seeders/)

- `RoleSeeder`: 4 roles (Superadministrador, Administrador, User, Cliente) + permissions dinámicos desde `config/permissions.php` vía `Artisan::call('permissions:sync')`
- `DatabaseSeeder`: calls RoleSeeder, creates superadmin user, creates default company record in `sistema` table
- Run order: `RoleSeeder` → `UserSeeder` optional (uses factory in DatabaseSeeder)

## When modifying code

1. Update `docs/changelog.md` per `docs/rules/changelog_policy.md`
2. Follow `docs/rules/coding-style.md`: isolated modules, Livewire `WithPagination` + SweetAlert2 listeners, per-module lang files, delegate complex logic to Services
3. If creating a new Livewire component, add its lang file to both `es/` and `en/`
4. If adding DB columns, create a migration (no `--foreign` constraints in SQLite by default)
5. If creating a new module, integrate it into the Dashboard (see Dashboard Integration section)
6. **Si agregas una nueva ruta que pertenezca a una sección existente del sidebar**, agrega su patrón de URL al helper `app/Helpers/sidebar.php` en el array `$patterns` de la sección correspondiente. Nunca agregues `request()->is()` directo en el Blade.

## Estructura de Módulos (OBLIGATORIO)

Todo **módulo o sección nueva** DEBE seguir esta estructura de 4 capas exactamente en este orden:

### 1. Ruta (`routes/web.php`)

```php
Route::get('/{nombre-seccion}', function () {
    return view('{nombre-seccion}');
})->name('{nombre-seccion}')->middleware('role:Superadministrador|Administrador');
```

### 2. Vista página (`resources/views/{nombre-seccion}.blade.php`)

```blade
<x-app-layout>
    <x-{nombre-seccion}/>
</x-app-layout>
```

### 3. Componente wrapper (`resources/views/components/{nombre-seccion}.blade.php`)

```blade
{{-- Sidebar --}}
<x-sidebar />
    <main class="w-full md:w-[calc(100%-256px)] md:ml-64 bg-slate-50 min-h-screen transition-all main">
        <!-- navbar -->
        <x-navbar />
        <!-- end navbar -->

      <!-- Content -->
        @livewire('{nombre-livewire}')
      <!-- End Content -->
   </main>
```

### 4. Componente Livewire

- **Clase:** `app/Livewire/{NombreComponente}.php`
- **Vista:** `resources/views/livewire/{nombre-componente}.blade.php`

### Reglas adicionales de estructura

- El `{nombre-seccion}` en la ruta, la vista página y el componente wrapper debe ser **idéntico** (e.g. `recaptcha-config` en los 3 archivos).
- El componente Livewire se referencia con guiones en `@livewire()` y en el nombre de archivo de la vista.
- La clase Livewire usa **PascalCase** (e.g. `RecaptchaConfig`).
- El lang file del módulo sigue el mismo patrón: `lang/{es,en}/{nombre-seccion en camelCase sin guiones}.php` (e.g. `recaptchaconfig.php`).

## Dashboard Integration (OBLIGATORIO)

Todo **módulo nuevo** DEBE integrarse en el Dashboard (`app/Livewire/Dashboard.php` y `resources/views/livewire/dashboard.blade.php`):

1. Agregar una tarjeta de estadística en la grilla superior (total, activos, tendencia)
2. Si el módulo genera eventos de auditoría, asegurar que aparezcan en el feed de "Actividad Reciente"
3. Si el módulo tiene datos agrupables (ej: por categoría/estado), agregar un bloque en la sección inferior
4. Usar `@can('modulo.index')` para ocultar bloques según permisos del usuario
5. Agregar claves al archivo `lang/{es,en}/dashboard.php`

Ejemplo de integración mínima:
```php
// En Dashboard.php mount()
if (auth()->user()->can('modulo.index')) {
    $this->moduloTotal = ModuloModel::count();
    $this->moduloActive = ModuloModel::where('activo', true)->count();
}
```

## Event Logging (OBLIGATORIO)

Toda acción de negocio (crear, editar, eliminar) en **cualquier módulo actual o futuro** DEBE registrar un evento usando `App\Services\EventLogger`:

```php
EventLogger::log('modulo.accion', __('events_log.clave_traduccion', ['param' => $valor]), [
    'metadata_opcional' => $dato,
]);
```

- El primer parámetro (`event_type`) sigue el patrón `{modulo}.{accion}` (ej: `user.created`, `blog.published`).
- El segundo parámetro es una descripción humanamente legible, siempre con traducción vía lang file `events_log.php`.
- El tercer parámetro (opcional) es un array para datos extra (ids, valores anteriores/nuevos, etc.).
- Si la acción implica múltiples cambios (ej: actualizar perfil), agrupar en un solo evento descriptivo.
- Las lang files `lang/{es,en}/events_log.php` deben mantenerse sincronizadas con cada nuevo tipo de evento.

### Módulos actuales con logging integrado (referencia):
- `user.created`, `user.deleted`, `user.password_reset`, `user.status_changed`, `user.role_changed`
- `role.created`, `role.updated`, `role.deleted`
- `permission.created`, `permission.updated`, `permission.deleted`
- `system.updated`

## Breadcrumb Translations (OBLIGATORIO)

Toda **ruta nueva** que se agregue al sistema DEBE tener su correspondiente traducción en el breadcrumb:

1. Agregar la clave `breadcrumb_{segmento}` en `lang/es/navbar.php` y `lang/en/navbar.php`, donde `{segmento}` es el primer segmento de la URL (ej: para `/reportes` → `breadcrumb_reportes`).
2. Si el segmento contiene guiones (`google-config`), usar exactamente el mismo nombre con guiones como clave.
3. El fallback automático muestra el segmento con formato título (ej: `edit-user` → `Edit User`), pero la traducción explícita es obligatoria para mantener consistencia.
4. El breadcrumb se renderiza en `resources/views/components/navbar.blade.php` usando `trans()->has()` con fallback a `Str::title()`.

## Estructura Modular (para módulos complejos)

Cuando se indique "estructura modular", usar este layout de directorios personalizado:

```
app/
├── Livewire/{Modulo}/
│   ├── Componente1.php
│   └── Componente2.php
├── Models/{Modulo}/
│   ├── Modelo1.php
│   └── Modelo2.php
├── Services/
│   └── {Modulo}Service.php
database/migrations/
├── xxxx_create_tabla1_table.php
└── xxxx_create_tabla2_table.php
lang/{modulo}/
├── es.php
└── en.php
resources/views/
├── {modulo}/
│   ├── pagina1.blade.php
│   └── pagina2.blade.php
├── components/{modulo}/
│   ├── componente1.blade.php
│   └── componente2.blade.php
└── livewire/{modulo}/
    ├── componente1.blade.php
    └── componente2.blade.php
routes/web.php
config/permissions.php
```

Reglas:
1. **Livewire components** se registran manualmente en `AppServiceProvider::boot()` con `Livewire::component('{modulo}.{nombre}', Class::class)`.
2. **Models** usan namespace `App\Models\{Modulo}\`.
3. **Views página** van en `resources/views/{modulo}/`.
4. **Component wrappers** van en `resources/views/components/{modulo}/` y se referencian como `x-{modulo}.{nombre}`.
5. **Lang files** van en `lang/{es,en}/{modulo}.php` (sin subdirectorio propio). Se acceden con `__('{modulo}.clave')`.
6. Todo módulo complejo DEBE usar `NotificacionService` para notificar eventos importantes.

## Mobile-First & Responsiveness

- All modals use `w-full sm:w-2/3 lg:w-1/2` instead of fixed widths; never use bare `w-1/2`
- All filter/search bars use `flex flex-col sm:flex-row` to stack on mobile
- Tables with many columns use `overflow-x-auto` wrapper + `min-width` on `<table>`
- Sidebar is hidden on mobile (`-translate-x-full`) and toggled via `sidebar-toggle` button
- Sidebar overlay (`sidebar-overlay`) closes sidebar when tapped
- All interactive elements (buttons, links) have minimum 44px touch target where possible
- The `.main` content area uses `w-full md:w-[calc(100%-256px)] md:ml-64` for responsive layout

## PWA (Progressive Web App)

- `public/manifest.json`: name, short_name, icons (192/512 SVG), theme_color `#1f2937`, display standalone
- `public/sw.js`: cache-first strategy for same-origin GETs + offline fallback
- `public/favicon.svg`: SVG favicon in app layout
- `public/icons/icon-192.svg`, `icon-512.svg`: PWA icons (SVG format)
- Both layouts include: `<meta name="theme-color">`, `<meta apple-mobile-web-app-capable>`, `<link rel="manifest">`, `<link rel="icon">`, SW registration script
- SW registration only activates on `localhost` or `https` to avoid development conflicts

## Equipo de Agentes

### SecurityAgent
- **Responsabilidad:** Auditoría de seguridad
- **Scope:** Middleware, autorizaciones `@can`, inyección SQL, validación de inputs
- **Skill:** `audit_vulnerabilities` — ejecutar siempre antes de validar un cambio

### QualityTesterAgent
- **Responsabilidad:** Testing y optimización
- **Scope:** Tiempos de carga, consultas N+1, tests unitarios/funcionales
- **Skill:** `performance_check` — analizar consultas redundantes en el componente

### DocumentationAgent
- **Responsabilidad:** Documentación (devs + usuario final)
- **Scope:** Mantener AGENTS.md, docs de uso del módulo, registrar en `docs/changelog.md`
- **Skill:** `sync_documentation` — generar instrucciones de manejo para usuarios finales

### ArchitectAgent
- **Responsabilidad:** Estructura, buenas prácticas y patrones
- **Scope:** Asegurar cumplimiento del patrón de módulos aislados de Laravel 12
- **Skill:** `validate_architecture_rules`

## Seguridad (Fase 1.3 — implementación obligatoria)

### Middleware de seguridad activos (registrados en `bootstrap/app.php`)
1. **`SecurityHeaders`** (web) — CSP + X-Frame-Options + X-Content-Type-Options + Referrer-Policy + Permissions-Policy + HSTS. Configurado en `config/security.php`. **Política dual**: admin (`frame-ancestors 'self'`) vs pública (`frame-ancestors 'none'`).
2. **`ForceHttps`** (global, prepended) — Redirección 301 a HTTPS. Deshabilitado por defecto; activar con `SECURITY_FORCE_HTTPS=true` en `.env` de producción.
3. **`SetLocale`** (web) — Resolución de locale DB → sesión → navegador → config.
4. **`ThrottleSensitiveAuthActions`** (alias `throttle.sensitive`) — Aplicado a Fortify vía `config/fortify.php`. Rate limit dinámico en register (3/h) y forgot-password (5/min) por nombre de ruta.

### Rate limiters disponibles
Definidos en `app/Providers/FortifyServiceProvider.php::configureRateLimiting()`:
- `login` — 5/min por email+IP
- `two-factor` — 5/min por sesión
- `register` — 3/h por IP
- `forgot-password` — 5/min por email+IP
- `oauth` — 10/min por IP (aplicado a `/auth/google/*`)

Para agregar un nuevo limiter: editar `configureRateLimiting()` + agregar entrada en `config/security.php` (`rate_limits.*`).

### Al crear rutas nuevas con throttling
```php
Route::middleware('throttle:oauth')->group(function () {
    // rutas públicas con rate limit
});
```

### Cabeceras personalizadas en respuestas
Si necesitas añadir headers especiales en una vista, usa `{{-- @stack('headers') --}}` en el layout y `@push('headers', '<meta ...>')` en la vista. NO insertes `<meta>` directamente entre Blade.

## Performance (Fase 1.5 — convenciones)

### Self-host obligatorio
**NO usar CDNs externos** (`fonts.googleapis.com`, `unpkg.com`, `cdn.jsdelivr.net`, `cdnjs.cloudflare.com`). Todas las dependencias JS/CSS deben instalarse vía npm e importarse en `resources/js/app.js` o `resources/css/app.css`.

Paquetes auto-hospedados disponibles:
- `@fontsource/inter` (300-800 + italic) — sans principal
- `@fontsource/cormorant-garamond` (400-700 + italic) — serif editorial (landing)
- `@fontsource/playfair-display` (400-700 + italic) — display (landing)
- `boxicons` (CSS + fonts)
- `@popperjs/core` (JS)

Para agregar otro asset auto-hospedado: `npm install <paquete>` + `@import` en CSS o `import` en JS.

### Vite
- Inputs: `resources/css/app.css`, `resources/js/app.js`
- Sourcemaps: ON en producción
- Aliases: `@/` → `./resources`
- Code splitting via `manualChunks` (boxicons, popper)

## Base de datos (Fase 1.2 — convenciones)

Ver `docs/db_conventions.md` para detalle completo. Resumen crítico:
- Toda migración nueva DEBE declarar `$table->charset = 'utf8mb4'` y `$table->collation = 'utf8mb4_unicode_ci'`.
- FKs: `foreignId('xxx_id')->constrained()->cascadeOnDelete()` o `nullOnDelete()`.
- Índices: nombre explícito `idx_<tabla>_<columna>` o `uq_<tabla>_<columna>`.
- Seeders: `firstOrCreate` + `syncRoles` (idempotencia obligatoria).
- Cambios de tipo de columna: SQL crudo con `DB::statement()` (evita `doctrine/dbal`).

## Protocolo Maestro de Desarrollo (No negociable)

1. **Atomicidad:** Ningún cambio se considera terminado hasta que se genere su paquete de despliegue (`docs/package/`) y su `UPGRADE.md` correspondiente.
2. **Paquetes existentes:** Si el módulo o sección ya tiene un paquete de despliegue en `docs/package/`, las nuevas correcciones o funcionalidades se integran DENTRO de ese paquete existente. No se crea un paquete nuevo. La actualización es automática.
3. **Documentación de Entorno:** `docs/setup_environment.md` contiene la receta exacta para configurar un servidor nuevo desde cero (Ubuntu, Nginx, PHP 8.5, dominio .test, permisos).
4. **Consistencia:** Al finalizar cada tarea, preguntar al usuario: *"¿Deseas que genere el paquete de despliegue y actualice el UPGRADE.md para esta tarea?"* (Si el paquete ya existe, se actualizará automáticamente el existente).
5. **Bitácora:** `docs/master_roadmap.md` lista todos los módulos y su estado de sincronización. Se actualiza automáticamente al completar cada módulo.
6. **Post-tarea:** Actualizar `docs/changelog.md`, `docs/master_roadmap.md`, generar/actualizar paquete de despliegue si aplica, y commit.

## Skills activas

- `sync_changelog` — obligatoria al modificar lógica de negocio
- `audit_permissions` — obligatoria al crear/modificar rutas
- `i18n_sync` — obligatoria al añadir nuevas vistas (asegurar paridad en `lang/es` y `lang/en`)