# API de usuarios y hogares

Todas las respuestas son JSON; errores `{ "error": { "code": "…", "message": "…" } }`.
Enviar cuerpo JSON y conservar cookie de sesión. Antes de mutar datos,
obtener `GET /api/v1/auth/csrf` y enviar `csrf_token` en `X-CSRF-Token`.
Registro y login rotan sesión y token; usar el nuevo token de su respuesta.

| Ruta | Métodos | Acceso |
|---|---|---|
| `/api/v1/health` | GET, HEAD | Público, proceso |
| `/api/v1/auth/csrf` | GET | Público, crea sesión |
| `/api/v1/auth/register` | POST | name, email, password |
| `/api/v1/auth/login` | POST | email, password |
| `/api/v1/auth/me` | GET | Sesión |
| `/api/v1/auth/logout` | POST | Sesión + CSRF |
| `/api/v1/homes` | GET, POST | Sesión; crear con name, timezone IANA |
| `/api/v1/homes/{id}` | GET, PATCH | Miembro; PATCH propietario |
| `/api/v1/homes/{id}/rooms` | GET, POST | Miembro; POST propietario, name |
| `/api/v1/rooms/{id}` | PATCH | Propietario, name |
| `/api/v1/homes/{id}/members` | GET, POST | Propietario; agregar con email, role |
| `/api/v1/homes/{id}/members/{userId}` | PATCH, DELETE | Propietario; PATCH con role |

Roles asignables: resident, guest. El propietario no puede eliminarse ni
cambiarse de rol. Agregar miembros no envía mensajes: la cuenta debe existir.
Una cuenta ajena recibe 404 para evitar revelar la existencia del hogar.
Un miembro sin permiso de configuración recibe 403. La revocación se evalúa
en la siguiente solicitud, aunque mantenga sesión abierta.

Contraseñas: 12–72 bytes, hash PHP; correo normalizado a minúsculas.
Límite combinado de registro/login: 30 intentos por IP cada 15 minutos.
Se usa REMOTE_ADDR, nunca un encabezado reenviado sin validar.
Cookies HttpOnly, SameSite=Lax, Secure fuera de desarrollo. Expiración por
30 minutos de inactividad. No se devuelven hashes ni credenciales.

## Usuarios y acceso infantil

- Registro: `name`, `username`, `password` y `email` opcional. El cliente
  anterior puede seguir registrándose solo con correo.
- Login: `identifier` (usuario o correo) y `password`; `email` sigue aceptado.
- `PATCH /api/v1/auth/me`: elegir/cambiar `username` de cuenta estándar.
- `POST /homes/{id}/members`: acepta `identifier` además de `email`.
- `GET /homes/{id}/children`: perfiles y habitaciones asignadas; propietario.
- `POST /homes/{id}/children`: crear perfil sin correo; propietario.
- `PATCH /homes/{id}/children/{userId}`: administrar perfil; propietario.

Las tres últimas rutas llevan el prefijo `/api/v1`. Para crear o editar,
enviar `name`, `username`, `enabled` booleano y `room_ids` como lista de
enteros. En creación, `password` es obligatoria; al editar, omitirla o enviar
cadena vacía conserva la contraseña. La respuesta no contiene contraseñas.
Editar invalida las sesiones infantiles existentes. Pausar también impide
login. El listado de habitaciones filtra los permisos en el servidor.

## Dispositivos y monitoreo

En el piloto, las rutas anteriores llevan prefijo `/homecore/api/v1`.
`HOMECORE_BASE_PATH` configura el prefijo y la ruta de cookie; en desarrollo
vacío se mantiene `/api/v1`.

| Ruta relativa a `/api/v1` | Métodos | Acceso |
|---|---|---|
| `/homes/{id}/devices` | GET, POST | Miembro; POST propietario |
| `/devices/{id}` | GET, PATCH | Lectura autorizada; PATCH propietario |
| `/devices/{id}/rotate-secret` | POST | Propietario |
| `/devices/{id}/telemetry/latest` | GET | Lectura autorizada |
| `/devices/{id}/telemetry/history` | GET | Lectura autorizada, últimas 100 |

Registro: `name`, `room_id` entero de una habitación del hogar. Devuelve
`device` y `device_token` solo esa vez. Rotación devuelve `device_uid` y
`device_token`; invalida la conexión anterior. PATCH acepta `enabled` booleano
para pausar/reactivar. No hay reasignación entre hogares ni comandos aún.
Los listados/lecturas nunca devuelven secretos ni hashes. Un niño necesita
permiso de habitación tanto para listar como para acceder por ID e historial.

Las fechas son UTC ISO 8601 y los valores son números. Sin datos, las
lecturas son null. `online` se calcula a partir de conexión activa,
`enabled` y `last_seen_at` reciente. `source` identifica simulación/sensor.
