# Gestión administrativa de usuarios

## Objetivo y permisos

El módulo usa sesión Sanctum y los permisos `users.view_any`, `users.view`, `users.create`, `users.update`, `users.change_status` y `users.assign_role`. El sidebar muestra **Usuarios** solo con `users.view_any`; el backend valida cada permiso independientemente.

| Método | Endpoint | Permiso |
|---|---|---|
| GET | `/api/v1/admin/users` | `users.view_any` |
| POST | `/api/v1/admin/users` | `users.create` |
| GET | `/api/v1/admin/users/{uuid}` | `users.view` |
| PATCH | `/api/v1/admin/users/{uuid}` | `users.update` |
| PATCH | `/api/v1/admin/users/{uuid}/status` | `users.change_status` |
| PUT | `/api/v1/admin/users/{uuid}/role` | `users.assign_role` |
| GET | `/api/v1/admin/pharmacies/options` | `users.view_any` |

El listado admite `page`, `per_page` (1–100), `search`, `status`, `role`, `pharmacy_id`, `created_from`, `created_to`, `sort` (`created_at`, `first_name`, `last_name`, `username`, `email`, `status`) y `direction`.

## Payloads

Crear requiere los datos personales, `password`, `password_confirmation`, `status`, `role` y `pharmacy_id` cuando `role` es `dependent`. Para actualizar se permiten solo los datos personales y `pharmacy_id`; contraseña, estado y rol usan endpoints separados.

```js
await api.post('/api/v1/admin/users', {
  first_name: 'Juan', last_name: 'Pérez', identification_number: '00112345678',
  whatsapp: '8095555555', username: 'juanperez', email: 'juan@example.com',
  city: 'Santiago', password: 'Password123!', password_confirmation: 'Password123!',
  status: 'active', role: 'dependent', pharmacy_id: 'uuid-de-farmacia',
})
await api.patch(`/api/v1/admin/users/${id}/status`, { status: 'blocked' })
await api.put(`/api/v1/admin/users/${id}/role`, { role: 'administrator', pharmacy_id: null })
```

Las farmacias se seleccionan desde `GET /api/v1/admin/pharmacies/options`; solo devuelve activas e IDs UUID. `dependent` exige farmacia activa; `administrator` puede no tenerla. Nunca enviar IDs numéricos, permisos ni roles múltiples.

## Errores y pruebas manuales

Los errores siguen el contrato API. Usar `USER_DATA_ALREADY_EXISTS` para conflictos de datos y `LAST_ACTIVE_ADMINISTRATOR_REQUIRED`, `CANNOT_DISABLE_CURRENT_USER` y `CANNOT_CHANGE_CURRENT_USER_ROLE` (409) para protecciones administrativas. Manejar 401 limpiando sesión, 403 como acceso denegado, 422 por campo y 429 sin reintento inmediato.

Prueba manualmente: visibilidad del menú según permiso, creación dependent con/sin farmacia, normalización de usuario/correo/teléfonos, filtros, bloqueo propio, degradación del último administrador y actualización de sesión después de cambiar el rol propio permitido.
