# Fase 1 — Reestructuración del núcleo

> Completada: 2026-04-23

## Objetivo

Dejar el núcleo del sistema robusto, sin código deprecado, con los módulos completamente autocontenidos y con aislamiento de datos garantizado a nivel de modelo.

---

## 1.1 ModulesServiceProvider — reescritura completa

**Archivo:** `app/Providers/ModulesServiceProvider.php`

### Cambios
- **Eliminado `->namespace()` deprecado** (Laravel 10+). Las rutas de cada módulo ya usaban FQCN con `use` propio — no se rompió nada.
- **Nuevo método `discoverModules()`**: lee todos los `module.json`, filtra por `enabled: true` (o `core: true`), valida dependencias del campo `requires`, y ordena por prioridad.
- **Validación de dependencias**: si un módulo declara `requires: ["OtroModulo"]` y ese módulo no está habilitado, el módulo se omite con `Log::warning()` sin romper la app.
- **`try/catch` por módulo**: un módulo corrupto loguea el error y la app sigue funcionando.
- **Namespace de vistas por módulo**: cada módulo usa su `alias` del `module.json` (ej. `sfm::`, `core::`) en lugar del `module::` compartido. Elimina colisiones de nombres entre módulos.
- **`Livewire::componentNamespace()`**: registro automático de componentes desde `Modules/{id}/Http/Livewire/` con prefijo `alias.`. Ej: `sfm.bucket-index` → `Modules\SFM\Http\Livewire\BucketIndex`.

---

## 1.2 Actualización de module.json

**Archivos:** `Modules/*/module.json` (los 3 módulos)

Campos agregados a todos:

| Campo | Descripción |
|---|---|
| `alias` | Prefijo corto para namespace de vistas y componentes Livewire |
| `enabled` | `true/false` — controlado por Wizard 3 (Fase 3) |
| `core` | `true` en Core — nunca se puede deshabilitar |
| `requires` | Array de IDs de módulos dependientes |
| `permissions` | Array de recursos que el módulo registra como permisos |

TaskManager se creó con `enabled: false` y `version: 0.1.0` (no implementado aún).

---

## 1.3 Livewire components movidos dentro de cada módulo

### Archivos eliminados (ubicación antigua)
- `app/Livewire/Modules/SimpleFinancialManagement/BucketIndex.php`
- `app/Livewire/Modules/SimpleFinancialManagement/MovementCrud.php`
- `app/Livewire/Modules/SimpleFinancialManagement/Test.php`
- `resources/views/livewire/modules/simple-financial-management/bucket-index.blade.php`
- `resources/views/livewire/modules/simple-financial-management/movement-crud.blade.php`
- `resources/views/livewire/modules/simple-financial-management/test.blade.php`

### Archivos creados (nueva ubicación dentro del módulo)
- `Modules/SimpleFinancialManagement/Http/Livewire/BucketIndex.php`
- `Modules/SimpleFinancialManagement/Http/Livewire/MovementCrud.php`
- `Modules/SimpleFinancialManagement/Http/Livewire/Test.php`
- `Modules/SimpleFinancialManagement/Resources/views/livewire/bucket-index.blade.php`
- `Modules/SimpleFinancialManagement/Resources/views/livewire/movement-crud.blade.php`
- `Modules/SimpleFinancialManagement/Resources/views/livewire/test.blade.php`

### Cambios en los componentes reescritos
- Namespace: `App\Livewire\Modules\SFM\*` → `Modules\SimpleFinancialManagement\Http\Livewire\*`
- Vistas: `view('livewire.modules.sfm.*')` → `view('sfm::livewire.*')`
- Todas las propiedades renombradas a `camelCase` (ver sección 1.6)
- Lógica de seguridad ya incorporada desde Fase 0

### Llamadas `@livewire` actualizadas
```blade
{{-- Antes --}}
@livewire('modules.simple-financial-management.bucket-index')

{{-- Después --}}
@livewire('sfm.bucket-index')
```

---

## 1.4 Global Scope `owner` en modelos SFM

**Archivos:** 5 modelos de `Modules/SimpleFinancialManagement/Models/`

Todos los modelos con `user_id` en la tabla recibieron:

```php
protected static function booted(): void
{
    static::addGlobalScope('owner', function ($query) {
        if (Auth::check()) {
            $query->where('tabla.user_id', Auth::id());
        }
    });
}
```

Modelos afectados: `Wallet`, `Bucket`, `Transaction`, `CreditCard`, `Tag`.

**Efecto**: cualquier query sobre estos modelos filtrará automáticamente por el usuario autenticado. No es necesario agregar `->where('user_id', ...)` manualmente en ningún lugar.

**Nota sobre relaciones**: las relaciones `belongsTo` / `hasMany` entre modelos SFM usan `->withoutGlobalScope('owner')` para evitar que el scope interfiera con los JOINs internos.

Adicionalmente, `Transaction` recibió:
- `$fillable` explícito (reemplaza `$guarded = []`)
- `$casts` para `metadata` (array), `reconciled` (boolean), `date`, `amount`
- Relaciones: `wallet()`, `bucket()`, `creditCard()`

`CreditCard` recibió:
- `user_id` en `$fillable`
- `$casts` para campos booleanos y decimales
- Relación `transactions()`

`Tag` recibió:
- `user_id` en `$fillable`
- Relación `transactions()` via `sfm_transaction_tags`

---

## 1.5 Migración de índices de rendimiento

**Archivo:** `Modules/SFM/database/migrations/2026_04_23_000001_add_performance_indexes_to_sfm_tables.php`

Índices compuestos agregados:

| Tabla | Índice | Propósito |
|---|---|---|
| `sfm_transactions` | `(user_id, date)` | Queries de dashboard por período |
| `sfm_transactions` | `(user_id, type)` | Filtrar ingresos/gastos |
| `sfm_transactions` | `(wallet_id, date)` | Saldo de wallet en rango de fechas |
| `sfm_transactions` | `(bucket_id, date)` | Gasto por categoría en período |
| `sfm_wallets` | `user_id` | Listado de wallets del usuario |
| `sfm_buckets` | `user_id` | Listado de buckets del usuario |
| `sfm_credit_cards` | `user_id` | Listado de TCs del usuario |
| `sfm_tags` | `user_id` | Listado de tags del usuario |

---

## 1.6 Estandarización de nomenclatura camelCase en Livewire

Aplicado en los componentes reescritos (`BucketIndex`, `MovementCrud`):

| Antes (snake_case) | Después (camelCase) |
|---|---|
| `$per_page` | `$perPage` |
| `$sort_by` | `$sortBy` |
| `$sort_asc` | `$sortAsc` |
| `$new_name` | `$newName` |
| `$new_kind` | `$newKind` |
| `$new_description` | `$newDescription` |
| `$movements_types` | `$movementTypes` |
| `$add_wallet_modal` | `$addWalletModal` |
| `$new_wallet_name` | `$newWalletName` |
| `$new_wallet_reason` | `$newWalletType` (campo renombrado también) |

---

## 1.7 Protección de mass assignment en Transaction

`$guarded = []` reemplazado por `$fillable = [...]` explícito con todos los campos de la migración.

---

## 1.8 Flush de caché de permisos en WizardController

**Archivo:** `Modules/Core/Http/Controllers/Wizard/WizardController.php`

Agregado al final de `resetPermissions()`:
```php
app(PermissionRegistrar::class)->forgetCachedPermissions();
```

Los cambios de permisos son efectivos inmediatamente sin necesidad de que el usuario cierre y vuelva a iniciar sesión.

---

## 1.x Migración de alias de vistas: `module::` → alias por módulo

Todos los controllers que usaban el namespace compartido `module::` fueron actualizados:

**Core** (6 controllers): `module::` → `core::`
**SFM** (5 controllers): `module::` → `sfm::`

Esto elimina el riesgo de colisión de nombres de vistas entre módulos.

---

## Archivos modificados / creados / eliminados

### Creados
- `Modules/Core/module.json` (actualizado)
- `Modules/SimpleFinancialManagement/module.json` (actualizado)
- `Modules/TaskManager/module.json` (creado)
- `Modules/SFM/Http/Livewire/BucketIndex.php`
- `Modules/SFM/Http/Livewire/MovementCrud.php`
- `Modules/SFM/Http/Livewire/Test.php`
- `Modules/SFM/Resources/views/livewire/bucket-index.blade.php`
- `Modules/SFM/Resources/views/livewire/movement-crud.blade.php`
- `Modules/SFM/Resources/views/livewire/test.blade.php`
- `Modules/SFM/database/migrations/2026_04_23_000001_add_performance_indexes_to_sfm_tables.php`

### Modificados
- `app/Providers/ModulesServiceProvider.php` (reescritura completa)
- `Modules/SFM/Models/Wallet.php`, `Bucket.php`, `Transaction.php`, `CreditCard.php`, `Tag.php`
- `Modules/Core/Http/Controllers/Wizard/WizardController.php`
- 11 controllers (Core y SFM) — alias de vistas

### Eliminados
- `app/Livewire/Modules/SimpleFinancialManagement/` (3 archivos)
- `resources/views/livewire/modules/simple-financial-management/` (3 archivos)
