Skip to content

Flujo Parámetros de agua

Base URL: /api/v1. Backend: camaroneras_backend (módulo parametros) ✅. Admin: camaroneras_admin (feature parametros) ✅. Mobile: camaroneras_mobile (feature parametros, offline-first) ✅. Quinto módulo de negocio; depende de piscinas. Captura físico-química por piscina (no por ciclo).

Requests y responses 2xx: bodies (tipos, opcionales, enums) y el shape de las respuestas exitosas están en la API Reference, generada desde el spec OpenAPI. Acá quedan solo las respuestas de error (4xx/5xx) y las reglas de negocio/flujo.

Modelo

Pool ──< WaterParam   (lectura de O2/temperatura/salinidad, en campo)
  • WaterParam: date, dissolvedOxygen (mg/L), temperature (°C), salinity (ppt), notes. Los tres valores son opcionales pero al menos uno debe venir.
  • Sin derivados: pura captura.

RBAC

  • Módulo parametros (label "Parámetros de agua") en el catálogo, clients ["web","mobile"].
  • Defaults: Administrador todo; Técnico ver/crear/editar; Bodeguero ver. Backfill automático.

Endpoints (protegidos: AccessJwtGuard + PermissionGuard; tenant del JWT)

GET /pools/:poolId/water-params — (parametros:ver)

Lista las lecturas de una piscina (más reciente primero).

POST /pools/:poolId/water-params — (parametros:crear)

Registra una lectura. Al menos uno de dissolvedOxygen/temperature/salinity.

json
// response 400 (ningún valor)
{ "error": "...", "message": "dissolvedOxygen must be a number ...", "statusCode": 400 }
json
// response 404 (piscina no existe / de otra org)
{ "error": "...", "message": "Piscina no encontrada", "statusCode": 404 }

PATCH /water-params/:id — (parametros:editar)

Edita una lectura (campos parciales).

DELETE /water-params/:id — (parametros:eliminar)

json
// response 404 (no existe o de otra organización)
{ "error": "...", "message": "Lectura no encontrada", "statusCode": 404 }

Flujo admin (camaroneras_admin, feature parametros)

  • Ruta: /parametros — protegida (ProtectedRoute module="parametros" action="ver"). Sin sesión → /login; sin permiso parametros:ver → bloqueada y sin item de nav.
  • Selector de piscina (FormCombobox) que carga de GET /pools. Sin selección se muestra un aviso; al elegir una piscina aparece la tabla de lecturas + acciones.
  • Tabla: Fecha · O₂ (mg/L) · Temp (°C) · Salinidad (ppt) · Notas · Acciones. Estados loading/empty. Diálogo crear/editar con validación "al menos un valor" en cliente (espeja el @ValidateIf del backend): botón deshabilitado hasta fecha + ≥1 valor.
  • Gating RBAC: "Nueva lectura" con parametros:crear; "Editar" con parametros:editar; "Eliminar" con parametros:eliminar. Todo vía usePermission().can('parametros', …).

Flujo mobile (camaroneras_mobile, feature parametros, offline-first)

  • Rutas: /parametros (picker de piscina) → /parametros/:poolId (lecturas). Card en Home solo con canVerParametros. La app ya exige sesión (go_router → /login).
  • Offline-first: tabla Drift WaterParams (schema v7). Lectura siempre desde Drift; sync() refresca desde red y conserva el cache si no hay conexión. El picker lee la tabla Pools (infra compartida) y hace su propio syncPools() al entrar.
  • Escrituras online: crear/editar/eliminar requieren red (patrón _netError → "Sin conexión…"); tras cada escritura se re-sincroniza la piscina.
  • Validación "al menos un valor" en el bottom sheet (espeja el @ValidateIf del backend).
  • Gating RBAC: FAB "Registrar" con canCrearParametros; iconos editar/eliminar con canEditar/canEliminarParametros.
  • Tests: repository (Drift in-memory: mapeo + replace borra lo ausente) + gating del FAB.