# Reporte: Refactor Inventario — Rutas modulares + Feature Slice (2026-05-30)

Consolidación del backend de Ficha de Inventario en dos fases: (1) contrato HTTP unificado con ficha padre como recurso principal y secciones genéricas; (2) reorganización del dominio bajo `App\Features\Inventario` con limpieza de código legacy. Se realizaron 6 commits atómicos en `main`.

---

## 1. Resumen de Cambios

| Aspecto | Antes | Después |
| ------- | ----- | ------- |
| **Cabecera (sección 0)** | `PUT .../seccion-0` como sección más | `GET/PUT fichas-inventario/{inventario}` — ficha padre |
| **Secciones** | Rutas dispersas, Actions por sección | `GET/PUT .../seccion-{section}` vía `SectionController` + factory |
| **Creación** | `POST fichas-inventario` | `POST fichas-registro/{registro}/inventario` (requiere registro aprobado) |
| **Estados** | `App\Enums\InventarioEstado` | `App\Features\Inventario\States\*` (Spatie Model States) |
| **Servicios** | `app/Services/Inventario/` | `app/Features/Inventario/Services/` |
| **Modelos** | `app/Models/` (raíz) | `app/Models/Inventario/` (~33 modelos) |
| **Actions legacy** | `app/Actions/FichaInventario/*` (22+ archivos) | Eliminadas; lógica en servicios |
| **Controlador monolítico** | `FichaInventarioController` | `FichaController` + `SectionController` (sin mover de `Http/Controllers`) |
| **Tests** | `tests/Feature/FichaInventario/`, `FichasInventario/` | `tests/Feature/Inventario/` (33 archivos) |
| **Autorización** | Trait `FichaEditable` + enum | Estados Spatie (`canEditFicha()`, `canEditSection()`) + Form Requests + Spatie Permission |

---

## 2. Fase 1 — Contrato de Rutas

Archivo dedicado: `routes/inventario.php` (incluido desde `routes/web.php`).

### Rutas de ficha padre

| Método | URI | Handler | Nombre |
| ------ | --- | ------- | ------ |
| GET | `fichas-inventario` | `FichaController@index` | `fichas-inventario.index` |
| GET | `fichas-inventario/crear` | `FichaController@create` | `fichas-inventario.create` |
| GET | `fichas-inventario/{inventario}` | `FichaController@show` | `fichas-inventario.show` |
| PUT | `fichas-inventario/{inventario}` | `FichaController@update` | `fichas-inventario.update` |
| DELETE | `fichas-inventario/{inventario}` | `FichaController@destroy` | `fichas-inventario.destroy` |
| PUT | `fichas-inventario/{inventario}/estado` | `FichaController@changeState` | `fichas-inventario.change-state` |
| GET | `fichas-inventario/{inventario}/completitud` | `FichaController@completitud` | `fichas-inventario.completitud` |
| GET | `fichas-inventario/{inventario}/step-states` | `FichaController@stepStates` | `fichas-inventario.step-states` |

### Creación anidada bajo registro

| Método | URI | Handler | Nombre |
| ------ | --- | ------- | ------ |
| GET | `fichas-registro/{registro}/inventario/crear` | `FichaController@createForRegistro` | `fichas-registro.inventario.create` |
| POST | `fichas-registro/{registro}/inventario` | `FichaController@store` | `fichas-registro.inventario.store` |

### Secciones unificadas

| Método | URI | Handler | Nombre |
| ------ | --- | ------- | ------ |
| GET | `fichas-inventario/{inventario}/seccion-{section}` | `SectionController@show` | `fichas-inventario.seccion.show` |
| PUT | `fichas-inventario/{inventario}/seccion-{section}` | `SectionController@update` | `fichas-inventario.seccion.update` |

Patrón `{section}`: `[0-9]+(-[0-9]+)?|anexos` — cubre `1`, `16-1`, `17-3`, `anexos`, etc.

`SectionServiceFactory` resuelve el servicio por convención:

```
App\Features\Inventario\Services\Seccion{Studly}Service
```

Ejemplo: relación `seccion161` → `Seccion161Service`.

---

## 3. Fase 2 — Estructura Feature Slice

```
app/Features/Inventario/
├── Actions/CreateBrigadistaAction.php
├── Enums/InventarioSectionCode.php
├── Exceptions/StateTransitionException.php
├── Services/
│   ├── FichaService.php
│   ├── Seccion{1..19}Service.php (+ sub-secciones 161–164, 171–173, 181–182, Anexos)
│   └── Core/
│       ├── BaseSectionService.php
│       ├── SectionServiceFactory.php
│       ├── SectionCatalogProvider.php
│       └── HasSectionMedia.php
└── States/
    ├── InventarioEstado.php (abstract)
    ├── Borrador.php, EnRevision.php, Validada.php, Aprobada.php, Observado.php

app/Models/Inventario/          ← 33 modelos Eloquent
app/Http/Requests/Inventario/   ← 4 Form Requests
database/factories/Inventario/  ← 5 factories con newFactory()
tests/Feature/Inventario/       ← 33 archivos de test
tests/Unit/Features/Inventario/ ← 2 archivos unitarios
```

**Sin mover (convención Laravel + Wayfinder):**

- `app/Http/Controllers/Inventario/FichaController.php`
- `app/Http/Controllers/Inventario/SectionController.php`
- `app/Http/Controllers/Inventario/MediaUploadController.php`

---

## 4. Máquina de Estados (Spatie Model States)

```
Borrador ──────► EnRevision ──────► Validada ──────► Aprobada
   │                  │                  │
   │                  ▼                  ▼
   │              Observado ◄──────── Observado
   │                  │
   └──────────────────┘ (re-submit)
```

| Estado | Editar cabecera | Editar otras secciones |
| ------ | --------------- | ---------------------- |
| Borrador | ✅ | ✅ si cabecera completada |
| Observado | ✅ | ✅ si cabecera completada |
| EnRevision / Validada / Aprobada | ❌ | ❌ |

---

## 5. Limpieza Legacy Eliminada

| Ruta eliminada | Motivo |
| -------------- | ------ |
| `app/Services/Inventario/` | Duplicado tras mover a `Features/Inventario` |
| `app/States/Inventario/` | Duplicado; estados viven en Features |
| `app/Actions/FichaInventario/` (22+ Actions) | Reemplazadas por servicios + controladores |
| `app/Http/Controllers/FichaInventarioController.php` | Reemplazado por `FichaController` |
| `app/Enums/InventarioEstado.php` | Reemplazado por Spatie States |
| `tests/Feature/FichaInventario/`, `FichasInventario/` | Consolidados en `Feature/Inventario` |
| Modelos huérfanos `Inventario171Hallazgo`, `Inventario172Fila`, `Inventario173Fila`, etc. | Esquema simplificado (JSON en tablas principales) |

**Fix adicional:** eliminada relación `Inventario172Catalogo::filas()` que apuntaba a `Inventario172Fila` (modelo inexistente; sección 17.2 usa JSON en `InvSeccion17`).

---

## 6. Form Requests (cabecera y flujo)

| Clase | Uso |
| ----- | --- |
| `StoreFichaInventarioRequest` | Creación desde registro aprobado |
| `UpdateInventarioRequest` | Actualización cabecera |
| `ChangeInventarioStateRequest` | Transiciones de estado |
| `DeleteInventarioRequest` | Eliminación (solo Borrador) |

---

## 7. Commits Realizados (6)

| SHA | Mensaje |
| --- | ------- |
| `834f9de` | `refactor(inventario): simplificar esquema sección 17 e instalar model-states` |
| `eed9495` | `refactor(inventario): consolidar dominio en App\Features\Inventario` |
| `e2e4f85` | `refactor(inventario): mover modelos Eloquent y factories a namespace Inventario` |
| `f7e9556` | `refactor(inventario): rutas modulares, FichaController delgado y Form Requests` |
| `5ff8655` | `test(inventario): unificar suite en Feature/Inventario y actualizar seeders` |
| `d263627` | `chore: agregar traducciones en inglés y actualizar configuración del proyecto` |

---

## 8. Verificación

### Suite de inventario

```
php artisan test --compact tests/Feature/Inventario tests/Unit/Features/Inventario
→ 309 passed
```

### Suite completa (~414 tests)

~27 fallos por `ViteManifestNotFoundException` (`public/build/manifest.json` ausente) al renderizar páginas Inertia — **no es lógica backend rota**.

### Build frontend

`bun run build` **falla** por imports Wayfinder obsoletos en React:

| Import obsoleto | Reemplazo |
| --------------- | --------- |
| `store` en `@/routes/fichas-inventario` | `fichas-registro.inventario.store` |
| `edit` eliminado | `show` (cabecera) y `seccion.show` (secciones) |

Archivos afectados (entre otros): `resources/js/pages/fichas-inventario/index.tsx`, `components/inventory-source-selection.tsx`, `navigation-buttons.tsx`, `layouts/inventory-form-layout.tsx`.

---

## 9. Relación con Reporte 2026-05-24

El reporte [`2026-05-24-refactor-seccion-16-base-section-service.md`](./2026-05-24-refactor-seccion-16-base-section-service.md) documenta el refactor previo de secciones 0, 13, 16–19 hacia `BaseSectionService` + DTOs. **Este reporte (2026-05-30)** cubre la capa superior: rutas HTTP, feature slice, namespaces y limpieza legacy que consume ese trabajo.

---

## 10. Pendiente

| Prioridad | Item | Detalle |
| --------- | ---- | ------- |
| **ALTA** | Frontend Wayfinder | Actualizar imports tras cambio de rutas; ejecutar `bun run build` |
| **MEDIA** | Tests Inertia | ~27 tests fallan hasta existir manifest Vite |
| **BAJA** | `StateTransitionException` | Definida pero sin usos activos aún |
| **BAJA** | `Seccion171Service::persist()` return type | Retorna `Inventario` vs contrato genérico del modelo de sección |

---

## 11. Diagrama de Capas (post-refactor)

```
HTTP (routes/inventario.php)
    │
    ├── FichaController ──► FichaService
    │                         └── Inventario (Models/Inventario)
    │
    └── SectionController ──► SectionServiceFactory
                                  └── App\Features\Inventario\Services\Seccion*Service
                                        └── BaseSectionService + HasSectionMedia
                                              └── Models/Inventario/InvSeccion*
```

Autorización: middleware `permission:fichas.inventario.manage` + `$inventario->estado->canEditSection($code)` en servicios/controladores.
