Rela AIRela AI Docs
Seguridad Alimentaria

HACCP — Control Sanitario Verificable

Planes HACCP, CCPs con grace period real, acciones correctivas que generan work orders y cadena de custodia por lote. Certificable ante SQF / BRC / FSSC 22000.

HACCP — Control Sanitario Verificable

El módulo HACCP de Rela AI no es un tablero de desviaciones. Es una implementación auditable de los 7 principios HACCP integrada con el resto del pipeline industrial: desde el sensor que mide temperatura hasta la orden de trabajo que el técnico cierra con evidencia.

¿Para qué sirve?

  • Monitorear en línea cada Punto Crítico de Control (CCP) del plan HACCP con rangos, grace periods y supresión de falsos positivos.
  • Disparar acción correctiva + work order asignado con plazo en cada desviación real.
  • Generar evidencia auditable (cadena de custodia por lote, audit trail con hash) aceptable ante SQF / BRC / FSSC 22000.

¿Cómo funciona?

Cada CCP define un rango aceptable + grace period + regla de supresión de sensores muertos. Las lecturas entran por POST /api/v1/haccp/readings (push desde el sensor) o vía MQTT/OPC UA; el pipeline valida contra el rango, descarta transitorios dentro del grace period, suprime el 0 falso de sensores muertos, y si hay desviación real abre acción correctiva + work order + entrada en cadena de custodia del lote.

Resumen ejecutivo

De registro reactivo a sistema de control. Antes, una desviación de temperatura generaba un registro textual sin trazabilidad. Hoy genera: una alerta consolidada en el inbox unificado, un work order urgente asignado al responsable, una entrada auditable de configuración, y — si el lote fue retenido — un registro en la cadena de custodia del batch.

Antes vs después

DimensiónAntesDespués
Transitorios (door-open, defrost)9 deviaciones falsas por apertura0 — grace_period_seconds respetado
Sensor muerto enviando 0"Critical low" fantasmaSuprimido por sensor_watchdog + H2
Inbox del operador3 silos: anomaly, energy, HACCP1 fila consolidada, severidad canónica
Incidente sostenido de 30 min~180 deviaciones persistidas1 deviation con sample_count=180 y max_deviation
Acción correctivaRegistro textual sin dueñoWork order urgente prefijo HAC-, asignado, trazable
Cambio de límite críticoSin rastro_audit_trail con prev→new, actor, timestamp
Plan HACCP vencido de revisiónNadie se enteraAlerta plan_review_overdue vía heartbeat
Lote en hold por desviaciónBuscar en CA texto libreQuery directa GET /batches/{id}/history

¿Qué es un CCP? ¿Qué es un Plan HACCP?

  • Plan HACCP: el documento regulatorio. Agrupa el análisis de peligros, el diagrama de flujo del proceso, los CCPs que controlan los riesgos, y los procedimientos de verificación. Cada plan tiene un review_frequency_days y un next_review_at.
  • CCP (Critical Control Point): un punto específico del proceso donde un peligro se controla. Pertenece a un plan (o es legacy sin plan), monitorea una métrica de un asset_id, y tiene límites críticos, grace period, acciones correctivas y responsable.
flowchart LR
  A[Sensor/PLC/SCADA] --> B[Ingesta machine_events<br/>o POST /haccp/readings]
  B --> C{Sensor stale?}
  C -- Si --> SKIP[Skip: sensor_watchdog]
  C -- No --> D[evaluate_limits<br/>high/low band]
  D -->|Dentro| BUF[Limpia buffer]
  D -->|Fuera| E{grace_period<br/>cumplido?}
  E -- No --> BUF2[Abre/extiende buffer]
  E -- Sí --> F[record_deviation<br/>con dedup M3]
  F -->|is_new=true| G[alert_aggregator<br/>source_system=haccp]
  F -->|is_new=false| H[merge en deviation existente]
  G --> I[Inbox unificado]
  F --> J[Corrective Action]
  J --> K[Work Order HAC-xxx]
  J --> L[Batch disposition<br/>si hold/rework/destroy]

Crear un CCP

Desde el dashboard

  1. Seguridad Alimentaria → HACCP → Plans.
  2. Crea un plan con análisis de peligros, diagrama de flujo y cadencia de revisión.
  3. Nuevo CCP dentro del plan:
    • Nombre, activo (validado contra _assets), fuente de datos, métrica.
    • Tipo de peligro: biológico / químico / físico / alérgeno.
    • Límites críticos high/low (al menos uno).
    • Tiempo de gracia en segundos: la UI explica que un valor de 300 significa "5 minutos de excursión permitidos antes de generar deviation".
    • Acciones correctivas estructuradas (descripción + minutos estimados + rol requerido + método de verificación).
    • Persona responsable.

Desde la API

# 1) Crear plan
POST /api/v1/haccp/plans
{
  "name": "Plan UHT Leche 1L",
  "product_type": "Leche UHT 1L",
  "process_flow": ["Recepción", "Filtrado", "Pasteurización", "Envasado"],
  "hazards": [
    {
      "stage_name": "Pasteurización",
      "hazard_description": "Supervivencia de patógenos si T<72°C",
      "hazard_type": "biological",
      "severity": "critical",
      "likelihood": "possible",
      "control_measure": "Temperatura ≥ 72°C por 15s",
      "is_ccp": true
    }
  ],
  "verification_procedures": [
    { "description": "Calibración del sensor de temperatura", "frequency_days": 30, "responsible_role": "qa_lead" }
  ],
  "review_frequency_days": 365
}

# 2) Crear CCP vinculado al plan
POST /api/v1/haccp/ccps
{
  "name": "Temperatura Pasteurizador",
  "asset_id": "64f...pasteurizer",
  "source_id": "src_plc_uht",
  "monitoring_metric": "temperature",
  "hazard_type": "biological",
  "critical_limit_high": 85,
  "critical_limit_low": 72,
  "unit": "C",
  "grace_period_seconds": 15,
  "corrective_steps": [
    { "description": "Detener feed pump", "estimated_minutes": 1, "required_role": "operator" },
    { "description": "Verificar temperatura hold tank", "estimated_minutes": 5, "required_role": "qa_lead",
      "verification_method": "Firma QA en CCP-01" }
  ],
  "responsible_person_id": "person_tech01",
  "plan_id": "64f...plan"
}

Monitoreo — las cuatro capas de protección

1. Sensor staleness (HACCP-H2)

Si el sensor_watchdog marca la fuente como stale (sin readings dentro del intervalo esperado), HACCP salta la evaluación. Un termómetro muerto enviando 0.0 no puede fabricar una "critical low" falsa.

2. Grace period real (HACCP-H1)

Un reading fuera de banda abre un buffer persistente en _haccp_deviation_buffers (MongoDB, no memoria — un restart del worker no descarta el tiempo acumulado). Solo cuando elapsed >= grace_period_seconds Y el reading sigue fuera de banda, se persiste la deviation. Transitorios resueltos (apertura de puerta, defrost cycle) nunca se registran.

3. Dedup por incidente (HACCP-M3)

Una excursión sostenida de 30 min no genera 5 filas separadas. Dentro de _HACCP_DEDUP_WINDOW_MINUTES (15 min default) los samples subsecuentes del mismo (ccp_id, direction) se mergean en la deviation existente: sample_count++, last_seen_at, max_reading/max_deviation rastrean el peor valor del incidente.

4. Inbox unificado (HACCP-H3)

Toda deviation confirmada publica al Alert Aggregator con source_system="haccp". Severidad canónica mapeada desde hazard_type:

HazardSeveridad
biologicalcritical
chemicalhigh
physicalwarning
allergen / unknownwarning (HACCP nunca baja a info)

Consolidación natural: un pico de temperatura que dispare anomaly_detection + energy + HACCP aparece como una sola fila por asset con source_systems = [anomaly, energy, haccp].

Ingesta directa — POST /api/v1/haccp/readings (HACCP-L2)

Para fuentes que no pasan por /machine/events (tablet de registro manual, termómetro HACCP dedicado con webhook propio):

POST /api/v1/haccp/readings
{
  "source_id": "tablet-qa-01",
  "metadata": { "temperature": 80.5 }
}
 200 OK
{ "source_id": "tablet-qa-01", "deviations": [ { ccp_id, reading, direction, deviation, ... } ] }

El mismo pipeline completo (staleness / grace / dedup / aggregator) se aplica. No hay "path secundario".

Acción correctiva → Work Order (HACCP-H5)

Cuándo un operador registra una corrective action:

POST /api/v1/haccp/deviations/{deviation_id}/corrective-action
{
  "description": "Lote aislado, temperatura del producto verificada <4°C",
  "taken_by": "Jane Operator",
  "product_disposition": "hold",
  "batch_id": "B-2026-03-15-A",
  "notes": "Freezer compressor inspeccionado, OK"
}

El sistema crea una task en el kanban:

  • task_code = HAC-xxx (prefijo distinguible de mantenimiento MAI-xxx).
  • priority = urgent (food safety no espera triage semanal).
  • status = todo, assigned_to = taken_by.
  • Back-links denormalizados: haccp_deviation_id, haccp_ccp_id, haccp_batch_id, haccp_product_disposition.
  • Description narrativa con contexto completo de deviation.

Cadena de custodia por lote (HACCP-L4)

Si la corrective action incluye batch_id + product_disposition != "none", se registra una entrada inmutable en _haccp_batch_dispositions:

GET /api/v1/haccp/batches/B-2026-03-15-A/history
 [
  {
    "batch_id": "B-2026-03-15-A",
    "disposition": "hold",
    "corrective_action_id": "...",
    "deviation_id": "...",
    "taken_by": "Jane Operator",
    "recorded_at": "2026-03-15T14:02:45Z"
  },
  { ... "disposition": "destroy", "recorded_at": "2026-03-16T09:12:00Z" }
]

Ante un inspector que pregunta "¿qué pasó con el lote X?", una sola query responde con la cadena completa.

Audit trail de configuración (HACCP-M5)

Cada mutación de un CCP queda registrada en _audit_trail con actor, timestamp y diff prev→new:

  • ccp_creatednew_state con los 14 campos regulatoriamente relevantes.
  • ccp_updated — solo los campos que cambiaron (no saturar con updated_at).
  • ccp_deletedprevious_state preservado para reconstrucción.

Cuándo un auditor pregunta "¿quién cambió critical_limit_high de 75 a 72 el 3 de marzo?", la respuesta está en el audit trail con email del actor, hora exacta, y valores ambos.

Heartbeat de revisión de planes (HACCP-M6)

POST /internal/haccp-health-check — job periódico (Cloud Scheduler) que:

  1. Lista planes HACCP con next_review_at <= now.
  2. Emite una alerta warning al aggregator por cada uno con extra.kind = "plan_review_overdue".
  3. No duplica el silent-sensor detection (ese ya lo hace sensor_watchdog + H2).

Un plan con revisión vencida ya no se silencia: aparece en el mismo inbox que los incidentes operativos del día.

Dashboard HACCP

  • Tiles de CCPs: lectura actual, límites, sample_count, max_deviation del incidente activo si hay.
  • Planes: estado enabled, next_review_at, botón "Mark as reviewed".
  • Deviations: lista ordenada last_seen_at desc. Cada fila con link al work order HAC-xxx.
  • Batch history: tab por batch_id con la cadena de disposiciones.

Arquitectura técnica

  • haccp_service — CRUD CCPs + plans + checking pipeline.
  • thresholds.py (módulo compartido) — evaluate_limits() reutilizado por HACCP y cold_chain (HACCP-M4).
  • _haccp_ccps, _haccp_plans, _haccp_deviations, _haccp_deviation_buffers, _haccp_corrective_actions, _haccp_batch_dispositions — todas per-tenant.
  • alert_aggregator_service.ingest_alert — integración fire-and-forget.
  • audit_trail_service.log_action — fire-and-forget sobre CCP mutations.

Tests que codifican el contrato

  • test_check_ccp_reading_grace_* — H1 (grace buffer behavior).
  • test_check_ccp_reading_skips_stale_source — H2.
  • test_check_ccp_reading_biological_feeds_aggregator_as_critical — H3.
  • test_create_ccp_*, test_update_ccp_* — M2 (asset validation) + M5 (audit).
  • test_record_deviation_merges_into_open_deviation_in_window — M3.
  • test_record_corrective_action_creates_work_order_with_expected_shape — H5.
  • test_heartbeat_flags_overdue_plans — M6.
  • test_record_corrective_action_logs_batch_disposition — L4.
  • test_get_haccp_plan_with_ccps_attaches_linked_ccps — H4.

Limitaciones y pendientes

  • ProductDisposition no bloquea sistemas downstream. Un hold registra la disposición pero no integra con ERP/MES para impedir el envío. Eso es trabajo del módulo de operations, no de HACCP.
  • Sin heartbeat de silent sensors propio. Reutilizamos sensor_watchdog; si esa cadena se rompe, HACCP no detecta silencios (solo los filtra si ya fueron marcados stale).
  • CorrectiveStep no se ejecuta como checklist. La UI puede usar corrective_steps para mostrar pasos, pero el sistema no verifica que cada paso se complete individualmente — eso es UX del dashboard, no backend.

Beneficios clave

  • Transitorios no contaminan el registro — grace respetado.
  • Sensores muertos no generan falsos positivos — staleness filter.
  • Un inbox, no cuatro — integración con alert_aggregator.
  • Incidente = una fila, aunque dure horas — dedup interno con peak tracking.
  • Acciones correctivas son trabajo real en el kanban — work orders urgentes con back-links.
  • Auditabilidad completa — audit trail sobre CCPs + cadena de custodia sobre lotes.
  • Planes HACCP formales — agrupan peligros + CCPs + verificación, certificables.
  • Lógica compartida con cold_chain — una sola matemática de threshold detection.

En esta página