# Panel Admin (`/admin/*`)

> Panel del staff de BewPro. Cubre System Admin, Administrator, Super Admin, Admin Comercial.
> Estado: ✅ 13/15 ejes — Production-polished (post-fixes 2026-05-12).
>
> Última actualización: 2026-05-12 (post Admin polish sprint)

---

## Quién es el usuario

Staff interno de BewPro que opera la empresa:
- **System Admin / Administrator**: full access — ven todo, hacen todo. Es el rol que uso yo (founder) y operadores senior.
- **Super Admin**: capacidades extra (audit log, import masivo, system-wide ops). Usado para incidentes / migrations.
- **Admin Comercial**: subset del Admin — ve customers + resellers, no ve tenants técnicos ni audit log. Pensado para sales/CS.

**Lo que el usuario espera:**
- Vista accionable del día ("¿qué requiere mi atención HOY?")
- CRUD de customers, resellers, tenants
- Audit log de cambios sensibles
- Operaciones bulk sin tocar tinker/SQL

**Lo que NO espera:**
- Onboarding (es power user)
- Help in-panel (tiene docs en /docs/)
- Empty states con CTA "comprá tu primer X" (es interno)

---

## Rutas implementadas

| Ruta | Método | Vista | Propósito |
|------|--------|-------|-----------|
| `/admin/dashboard` | GET | `dashboard.blade.php` | KPIs accionables + signups recientes |
| `/admin/tenants` | GET | `tenants.blade.php` | Cross-tenant inventory |
| `/admin/audit-log` | GET | `audit-log.blade.php` | Activity log de staff (Spatie/Activitylog) |
| `/admin/customers` | GET | `customers/index.blade.php` | Tabla customers con bulk actions |
| `/admin/customers/{user}/edit` | GET | `customers/edit.blade.php` | Detalle + roles + proyectos |
| `/admin/customers/{user}/roles` | PATCH | — | Update roles Spatie |
| `/admin/customers/{user}/notes` | PATCH | — | Update admin_notes (⚠️ form no renderizado) |
| `/admin/customers/{user}/reset-password` | POST | — | Reset password con temppass |
| `/admin/customers/{user}/verify-email` | POST | — | Force verify email |
| `/admin/customers/export` | GET | (CSV streamed) | Export CSV |
| `/admin/customers/bulk` | POST | — | Bulk actions (assign_role, remove_role, verify_email, delete) |
| `/admin/resellers` | GET | `resellers/index.blade.php` | Applications al programa |
| `/admin/resellers/{id}` | GET | `resellers/show.blade.php` | Detalle application |
| `/admin/resellers/{id}/start-review` | POST | — | Marca en revisión |
| `/admin/resellers/{id}/approve` | POST | — | Aprueba + asigna rol Reseller + Slack notif |
| `/admin/resellers/{id}/reject` | POST | — | Rechaza con notas |

Middleware: `ensure.main.site` + `auth` + `verified` + permisos granulares por método (customers.view, customers.edit, etc.).

---

## Standard de Madurez — audit por eje

| Eje | Status | Hallazgo |
|-----|--------|----------|
| 1. Estructura base | ✅ | x-base-layout + x-admin-header consistente |
| 2. Onboarding | N/A | Power user interno — no aplica welcome card. |
| 3. Stats top | ✅ | Dashboard tiene 4 KPIs accionables + 4 métricas overview |
| 4. Filtros + search | ✅ | Customers tiene 5+ filtros combinables, Tenants/Resellers similar |
| 5. Empty states | ✅ | "Limpiar filtros" CTA cuando hay filters activos (fix 2026-05-12) |
| 6. Lifecycle banners | ⚠️ | Dashboard usa border-warning si pending > 0, pero no badge "ACTION REQUIRED" tipo Stripe. Funcional pero perceptiblemente menos urgente. |
| 7. Progress + ETA | ✅ | Tenants table muestra last_synced_at con diffForHumans |
| 8. Primary + secondary | ⚠️ | Bulk actions OK, pero primary action por row no siempre destacada (edit/eliminar mismo peso visual) |
| 9. Help in-panel | ⚠️ | Sin help/tooltips. Aceptable para power users — pero tooltips explicando términos técnicos ayudarían a operadores nuevos. |
| 10. Integraciones | ✅ | Slack + email notif (reject/approve, fix 2026-05-12) + Airtable links |
| 11. Auth + permisos | ✅ | Permisos granulares por método, guards anti-self-affect en bulk |
| 12. Responsive | ✅ | Filtros customers ajustados a col-12 col-sm-6 col-md-* (fix 2026-05-12) |
| 13. Flash + alerts | ✅ | Session-based, redirect-safe; flash de reject ahora honesto |
| 14. Footer útil | ⚠️ | Footer es genérico, no tiene shortcuts a docs operativos |
| 15. Idioma + tono | ✅ | Audit log labels ES (Creado/Actualizado/Eliminado) — fix 2026-05-12 |

**Score: 13/15 ✅, 3/15 ⚠️ (todas aceptables — gaps no UX-blocking).**

**Veredicto: Production-polished (post fixes 2026-05-12).**

---

## Cambios 2026-05-12 (Admin polish sprint)

5 fixes ejecutados que llevaron el panel de 9/15 a 13/15:

| Fix | Archivos tocados | Resultado |
|-----|------------------|-----------|
| P0-1 admin notes form | `customers/edit.blade.php` (+ form textarea con @can guard) | Route PATCH `/admin/customers/{user}/notes` ya tiene UI. Visible solo con permission `customers.edit`. |
| P0-2 reseller reject email | `app/Mail/ResellerApplicationDecisionMail.php` (NUEVO), `emails/reseller-application-decision.blade.php` (NUEVO), `Admin/ResellersController.php` (Mail::send en approve + reject, flash honesto) | Approval/rejection ahora envía email real al solicitante. Flash refleja si se envió o falló. |
| P0-3 empty states con "Limpiar filtros" | `customers/index.blade.php`, `tenants.blade.php`, `audit-log.blade.php`, `resellers/index.blade.php` | Cada empty state con CTA reset cuando hay filtros activos. |
| P1-7 audit log ES | `audit-log.blade.php` (label map + select options) | "Creado / Actualizado / Eliminado" en lugar de inglés. |
| P1-6 filtros responsive | `customers/index.blade.php` (col-md-* → col-12 col-sm-6 col-md-*) | Tablet 600-768px ya no apila mal. |

---

## Gaps remanentes (no bloqueantes — backlog)

### P1 — Polish secundario

1. **Lifecycle banners ACTION REQUIRED**
   - Dashboard hoy: card con border-warning si pending > 0.
   - Mejora: badge fixed-top "{N} acciones pendientes" hasta que el operador las atienda.
   - Estimado: 1h.

2. **Tooltips en términos técnicos**
   - "¿qué es reseller_pending?", "¿qué es bulk-delete safely?", "¿qué pasa al verify-email?".
   - Fix: agregar `<i class="fas fa-info-circle" data-bs-toggle="tooltip" title="...">` al lado de cada término.
   - Estimado: 1h.

3. **Primary action por row destacada**
   - Hoy edit y delete tienen el mismo peso visual.
   - Fix: edit → btn-primary, delete → btn-icon btn-light con tooltip.
   - Estimado: 30 min.

### P2 — Diferidos (no bloquean cierre del trabajo de paneles)

4. **Soft deletes en bulk delete**: hoy es hard delete. Diferido — operador debe saber lo que hace.
5. **Tests admin**: 0% coverage. Diferido — no es UX gap, es backend gap.
6. **Performance dashboard**: 11 queries sin eager loading. Diferido — bajo tráfico, no problema hoy.
7. **CSV export customizable**: columnas hardcoded. Diferido — operadores aceptan el formato fijo.
8. **Spatie/Activitylog migration check**: hay deps no verificada. Validar que la migration corrió.

---

## Decisiones de diseño

### Por qué no hay onboarding

Admin es power user interno. Si entra sin saber qué hace, hay un problema de hiring, no de UX. Aceptable marcar el eje como N/A.

### Por qué bulk actions son hard delete

Operador staff sabe SQL si quiere recovery. Soft delete agrega complejidad (deleted_at en 5 tablas, scope global, cleanup cron). El cost/benefit no cierra para volumen actual.

### Por qué permisos granulares por método

`customers.view`, `customers.edit`, `customers.assign-roles` son distintos. Admin Comercial puede ver pero no asignar roles. Permite gradar acceso staff sin múltiples roles.

---

## Referencias

- Roles & permisos: `docs/bewpro2.0/operaciones/roles-y-permisos.md`
- Standard de madurez: `docs/bewpro2.0/paneles/standard-de-madurez.md`
- Sprint 1 roles: `docs/bewpro2.0/operaciones/sprint1-roles-checklist.md`
