{
  "schema": "slm.agent_native_manifest.v1",
  "version": "2026-05-10.5",
  "app": {
    "id": "transportes-slm",
    "name": "Transportes SLM",
    "productionUrl": "https://app.transportesslm.com",
    "language": "es-MX"
  },
  "principle": "La app expone rutas, acciones, estados y selectores estables para que humanos y agentes operen la misma superficie sin depender de clicks ambiguos.",
  "routes": [
    {
      "id": "dashboard",
      "href": "/dashboard",
      "label": "Dashboard operativo",
      "purpose": "Resumen ejecutivo y entrada a trabajo reciente.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"dashboard\"]"
    },
    {
      "id": "viajes",
      "href": "/viajes",
      "label": "Viajes y operaciones",
      "purpose": "Buscar viajes, abrir detalle, editar o duplicar viajes.",
      "roles": [
        "admin",
        "oficina",
        "cliente"
      ],
      "stableSelector": "[data-agent-view=\"viajes\"]"
    },
    {
      "id": "detalle",
      "href": "/viajes",
      "label": "Detalle de viaje",
      "purpose": "Leer estado operativo, GPS, evidencias, gastos, viaticos y rentabilidad de un viaje.",
      "roles": [
        "admin",
        "oficina",
        "operador",
        "cliente"
      ],
      "stableSelector": "[data-agent-view=\"detalle\"]"
    },
    {
      "id": "calendario",
      "href": "/calendario",
      "label": "Calendario",
      "purpose": "Ver viajes por fecha, operador, unidad y estatus.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"calendario\"]"
    },
    {
      "id": "alertas",
      "href": "/alertas",
      "label": "Alertas",
      "purpose": "Priorizar atrasos, cobranza, evidencias y pendientes operativos.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"alertas\"]"
    },
    {
      "id": "reportes",
      "href": "/reportes",
      "label": "Reportes",
      "purpose": "Analizar rentabilidad, gastos, cobranza y calidad de datos.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"reportes\"]"
    },
    {
      "id": "unidades",
      "href": "/unidades",
      "label": "Unidades",
      "purpose": "Consultar unidades, documentos, mantenimiento y reglas tecnicas.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"unidades\"]"
    },
    {
      "id": "usuarios",
      "href": "/usuarios",
      "label": "Usuarios",
      "purpose": "Gestionar perfiles, roles y accesos.",
      "roles": [
        "admin"
      ],
      "stableSelector": "[data-agent-view=\"usuarios\"]"
    },
    {
      "id": "agent_ops",
      "href": "/agente",
      "label": "Agente",
      "purpose": "Revisar acciones, eventos, aprobaciones y ejecuciones propuestas por automatizaciones.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"agent_ops\"]"
    },
    {
      "id": "observabilidad",
      "href": "/observabilidad",
      "label": "Observabilidad",
      "purpose": "Revisar telemetria, auditoria y errores de sincronizacion.",
      "roles": [
        "admin",
        "oficina"
      ],
      "stableSelector": "[data-agent-view=\"observabilidad\"]"
    }
  ],
  "actions": [
    {
      "id": "trip_create",
      "label": "Crear viaje",
      "risk": "medium",
      "approval": "optional",
      "required": [
        "origen",
        "destino",
        "operador_id"
      ],
      "writes": [
        "viajes",
        "gastos",
        "viaticos_anticipos"
      ]
    },
    {
      "id": "trip_update_status",
      "label": "Actualizar estatus de viaje",
      "risk": "medium",
      "approval": "optional",
      "required": [
        "viaje_id",
        "estatus"
      ],
      "writes": [
        "viajes"
      ]
    },
    {
      "id": "trip_add_expense",
      "label": "Agregar gasto a viaje",
      "risk": "medium",
      "approval": "optional",
      "required": [
        "viaje_id",
        "tipo",
        "monto"
      ],
      "writes": [
        "gastos"
      ]
    },
    {
      "id": "trip_close",
      "label": "Cerrar viaje",
      "risk": "high",
      "approval": "required",
      "required": [
        "viaje_id"
      ],
      "writes": [
        "viajes",
        "nomina_variable_movimientos"
      ]
    },
    {
      "id": "customer_status_prepare",
      "label": "Preparar estatus para cliente",
      "risk": "low",
      "approval": "none",
      "required": [
        "viaje_id",
        "unidad"
      ],
      "writes": []
    },
    {
      "id": "customer_whatsapp_send",
      "label": "Enviar WhatsApp a cliente",
      "risk": "high",
      "approval": "required",
      "required": [
        "viaje_id",
        "target",
        "message"
      ],
      "writes": [
        "notificaciones",
        "agent_action_log"
      ]
    }
  ],
  "selectors": {
    "appShell": "[data-agent-app=\"slm\"]",
    "activeView": "[data-agent-view]",
    "navigationItem": "[data-agent-nav]",
    "routeId": "[data-agent-route]",
    "role": "[data-agent-role]",
    "actionButton": "[data-agent-action]",
    "entityId": "[data-agent-entity-id]",
    "form": "[data-agent-form]",
    "field": "[data-agent-field]",
    "tripRow": "[data-testid^=\"trip-table-row-\"]",
    "tripCard": "[data-testid^=\"trip-card-\"]",
    "tripDetail": "[data-testid=\"trip-detail-head\"]",
    "agentOps": "[data-testid=\"agent-ops-view\"]",
    "agentActionRow": "[data-agent-entity=\"agent-action\"]",
    "agentEventRow": "[data-agent-entity=\"agent-event\"]"
  },
  "statuses": {
    "actionStatuses": [
      "draft",
      "ready",
      "blocked",
      "pending_approval",
      "approved",
      "executed",
      "rejected",
      "cancelled",
      "failed"
    ],
    "eventStatuses": [
      "new",
      "acknowledged",
      "in_progress",
      "resolved",
      "dismissed"
    ],
    "tripStatuses": [
      "pendiente",
      "en_ruta",
      "en_planta",
      "rumbo_yarda",
      "en_yarda",
      "completado",
      "cancelado"
    ],
    "riskLevels": [
      "low",
      "medium",
      "high"
    ]
  },
  "entities": [
    {
      "id": "viaje",
      "table": "viajes",
      "primaryKey": "id",
      "label": "Viaje",
      "fields": {
        "id": {
          "type": "string",
          "required": true,
          "readonly": true
        },
        "origen": {
          "type": "string",
          "required": true
        },
        "destino": {
          "type": "string",
          "required": true
        },
        "fecha_salida": {
          "type": "date",
          "required": true
        },
        "fecha_llegada": {
          "type": "date",
          "required": false
        },
        "estatus": {
          "type": "enum",
          "values": [
            "pendiente",
            "en_ruta",
            "en_planta",
            "rumbo_yarda",
            "en_yarda",
            "completado",
            "cancelado"
          ],
          "required": true
        },
        "operador_id": {
          "type": "string",
          "required": false,
          "relation": "usuarios.id"
        },
        "operador": {
          "type": "string",
          "required": false
        },
        "cliente_id": {
          "type": "string",
          "required": false,
          "relation": "usuarios.id"
        },
        "cliente": {
          "type": "string",
          "required": false
        },
        "unidad_id": {
          "type": "string",
          "required": false,
          "relation": "unidades.id"
        },
        "unidad_numero": {
          "type": "string",
          "required": false
        },
        "tipo_carga": {
          "type": "string",
          "required": false
        },
        "ingreso": {
          "type": "number",
          "required": false,
          "sensitive": "financial"
        },
        "pago_operador_viaje": {
          "type": "number",
          "required": false,
          "sensitive": "financial"
        },
        "contenedores": {
          "type": "array",
          "required": false
        },
        "contenedores_texto": {
          "type": "string",
          "required": false
        },
        "notas": {
          "type": "string",
          "required": false
        },
        "cobranza_estatus": {
          "type": "enum",
          "values": [
            "pendiente",
            "vencida",
            "pagada"
          ],
          "required": false,
          "sensitive": "billing"
        }
      }
    },
    {
      "id": "unidad",
      "table": "unidades",
      "primaryKey": "id",
      "label": "Unidad",
      "fields": {
        "id": {
          "type": "string",
          "required": true,
          "readonly": true
        },
        "numero": {
          "type": "string",
          "required": true
        },
        "placa": {
          "type": "string",
          "required": false
        },
        "marca": {
          "type": "string",
          "required": false
        },
        "modelo": {
          "type": "string",
          "required": false
        },
        "tipo": {
          "type": "string",
          "required": false
        },
        "serie_tracto": {
          "type": "string",
          "required": false
        },
        "serie_motor": {
          "type": "string",
          "required": false
        }
      }
    },
    {
      "id": "usuario",
      "table": "usuarios",
      "primaryKey": "id",
      "label": "Usuario",
      "fields": {
        "id": {
          "type": "string",
          "required": true,
          "readonly": true
        },
        "nombre": {
          "type": "string",
          "required": true
        },
        "usuario": {
          "type": "string",
          "required": false
        },
        "rol": {
          "type": "enum",
          "values": [
            "admin",
            "oficina",
            "operador",
            "cliente"
          ],
          "required": true
        },
        "correo": {
          "type": "string",
          "required": false
        },
        "correo_entrega": {
          "type": "string",
          "required": false
        },
        "cliente_whatsapp": {
          "type": "string",
          "required": false,
          "sensitive": "contact"
        },
        "credito_dias": {
          "type": "number",
          "required": false
        }
      }
    },
    {
      "id": "gasto",
      "table": "gastos",
      "primaryKey": "id",
      "label": "Gasto",
      "fields": {
        "id": {
          "type": "string",
          "required": true,
          "readonly": true
        },
        "viaje_id": {
          "type": "string",
          "required": true,
          "relation": "viajes.id"
        },
        "tipo": {
          "type": "string",
          "required": true
        },
        "monto": {
          "type": "number",
          "required": true,
          "sensitive": "financial"
        },
        "litros": {
          "type": "number",
          "required": false
        },
        "descripcion": {
          "type": "string",
          "required": false
        },
        "fecha": {
          "type": "date",
          "required": true
        },
        "metodo_pago": {
          "type": "string",
          "required": false
        }
      }
    },
    {
      "id": "evidencia",
      "table": "evidencias",
      "primaryKey": "id",
      "label": "Evidencia",
      "fields": {
        "id": {
          "type": "string",
          "required": true,
          "readonly": true
        },
        "viaje_id": {
          "type": "string",
          "required": true,
          "relation": "viajes.id"
        },
        "tipo": {
          "type": "string",
          "required": true
        },
        "nota": {
          "type": "string",
          "required": false
        },
        "archivo_url": {
          "type": "string",
          "required": false,
          "sensitive": "document_url"
        },
        "fecha": {
          "type": "datetime",
          "required": false
        },
        "subido_por": {
          "type": "string",
          "required": false,
          "relation": "usuarios.id"
        }
      }
    }
  ],
  "forms": [
    {
      "id": "trip_form",
      "entity": "viaje",
      "selector": "[data-agent-form=\"trip\"]",
      "purpose": "Crear o editar un viaje con ruta, asignacion, costos base, contenedores y cobranza.",
      "submitAction": "trip.save",
      "fields": [
        {
          "name": "origen",
          "selector": "[data-agent-field=\"trip.origen\"]",
          "type": "text",
          "required": true
        },
        {
          "name": "destino",
          "selector": "[data-agent-field=\"trip.destino\"]",
          "type": "text",
          "required": true
        },
        {
          "name": "fecha_salida",
          "selector": "[data-agent-field=\"trip.fecha_salida\"]",
          "type": "date",
          "required": true
        },
        {
          "name": "fecha_llegada",
          "selector": "[data-agent-field=\"trip.fecha_llegada\"]",
          "type": "date",
          "required": false
        },
        {
          "name": "operador_id",
          "selector": "[data-agent-field=\"trip.operador_id\"]",
          "type": "select",
          "required": true
        },
        {
          "name": "cliente_id",
          "selector": "[data-agent-field=\"trip.cliente_id\"]",
          "type": "select",
          "required": true
        },
        {
          "name": "unidad_id",
          "selector": "[data-agent-field=\"trip.unidad_id\"]",
          "type": "select",
          "required": false
        },
        {
          "name": "tipo_carga",
          "selector": "[data-agent-field=\"trip.tipo_carga\"]",
          "type": "select",
          "required": false
        },
        {
          "name": "ingreso",
          "selector": "[data-agent-field=\"trip.ingreso\"]",
          "type": "number",
          "required": false,
          "sensitive": "financial"
        },
        {
          "name": "pago_operador_viaje",
          "selector": "[data-agent-field=\"trip.pago_operador_viaje\"]",
          "type": "number",
          "required": false,
          "sensitive": "financial"
        },
        {
          "name": "estatus",
          "selector": "[data-agent-field=\"trip.estatus\"]",
          "type": "select",
          "required": true
        },
        {
          "name": "contenedores_input",
          "selector": "[data-agent-field=\"trip.contenedores_input\"]",
          "type": "textarea",
          "required": false
        },
        {
          "name": "notas",
          "selector": "[data-agent-field=\"trip.notas\"]",
          "type": "text",
          "required": false
        },
        {
          "name": "factura_folio",
          "selector": "[data-agent-field=\"trip.factura_folio\"]",
          "type": "text",
          "required": false,
          "sensitive": "billing"
        },
        {
          "name": "cobranza_estatus",
          "selector": "[data-agent-field=\"trip.cobranza_estatus\"]",
          "type": "select",
          "required": false,
          "sensitive": "billing"
        }
      ]
    },
    {
      "id": "trip_expense_form",
      "entity": "gasto_viaje",
      "selector": "[data-agent-form=\"trip_expense\"]",
      "purpose": "Agregar gastos operativos a un viaje con bucket y campos de combustible cuando aplique.",
      "submitAction": "trip_expense.save",
      "fields": [
        {
          "name": "tipo",
          "selector": "[data-agent-field=\"trip_expense.tipo\"]",
          "type": "select",
          "required": true
        },
        {
          "name": "monto",
          "selector": "[data-agent-field=\"trip_expense.monto\"]",
          "type": "number",
          "required": true,
          "sensitive": "financial"
        },
        {
          "name": "fecha",
          "selector": "[data-agent-field=\"trip_expense.fecha\"]",
          "type": "date",
          "required": true
        },
        {
          "name": "litros",
          "selector": "[data-agent-field=\"trip_expense.litros\"]",
          "type": "number",
          "requiredWhen": "tipo=combustible"
        },
        {
          "name": "descripcion",
          "selector": "[data-agent-field=\"trip_expense.descripcion\"]",
          "type": "text",
          "required": false
        }
      ]
    },
    {
      "id": "evidence_form",
      "entity": "evidencia",
      "selector": "[data-agent-form=\"evidence\"]",
      "purpose": "Subir evidencia de viaje desde camara, galeria o dropzone con tipo y nota.",
      "submitAction": "evidence.upload",
      "fields": [
        {
          "name": "tipo",
          "selector": "[data-agent-field=\"evidence.tipo\"]",
          "type": "select",
          "required": true
        },
        {
          "name": "nota",
          "selector": "[data-agent-field=\"evidence.nota\"]",
          "type": "text",
          "required": false
        },
        {
          "name": "camera_file",
          "selector": "[data-agent-field=\"evidence.camera_file\"]",
          "type": "file",
          "required": false
        },
        {
          "name": "gallery_file",
          "selector": "[data-agent-field=\"evidence.gallery_file\"]",
          "type": "file",
          "required": false
        },
        {
          "name": "dropzone",
          "selector": "[data-agent-field=\"evidence.dropzone\"]",
          "type": "dropzone",
          "required": false
        }
      ]
    }
  ],
  "api": [
    {
      "id": "manifest",
      "method": "GET",
      "path": "/agent-manifest.json",
      "auth": "public",
      "purpose": "Contrato estatico para agentes, crawlers internos y automatizaciones sin sesion."
    },
    {
      "id": "agent_health",
      "method": "GET",
      "path": "/api/agent-health",
      "auth": "public",
      "purpose": "Healthcheck agent-native con version, capacidades y conteo de contratos disponibles."
    },
    {
      "id": "trip_gps",
      "method": "GET",
      "path": "/api/trip-gps",
      "auth": "app_session",
      "purpose": "Consulta de GPS para un viaje/unidad desde flujos autenticados."
    },
    {
      "id": "agent_schema",
      "method": "GET",
      "path": "/api/agent/schema",
      "auth": "public",
      "purpose": "Indice de schemas, permisos, playbooks y endpoints para agentes."
    },
    {
      "id": "agent_trips",
      "method": "GET",
      "path": "/api/agent/trips",
      "auth": "app_session",
      "query": [
        "query",
        "status",
        "unit",
        "cliente",
        "operador",
        "limit"
      ],
      "purpose": "Busqueda de viajes con respuesta resumida y estable para agentes."
    },
    {
      "id": "agent_trip_detail",
      "method": "GET",
      "path": "/api/agent/trips/:id",
      "auth": "app_session",
      "purpose": "Detalle de viaje con entidades relacionadas utiles para toma de decision."
    },
    {
      "id": "agent_unit_status",
      "method": "GET",
      "path": "/api/agent/units/status?unit=:numero",
      "auth": "app_session",
      "purpose": "Estado de unidad y viajes activos asociados."
    },
    {
      "id": "agent_actions",
      "method": "POST",
      "path": "/api/agent/actions",
      "auth": "app_session",
      "purpose": "Registrar o ejecutar acciones controladas con auditoria, idempotencia y aprobaciones."
    },
    {
      "id": "agent_action_detail",
      "method": "GET",
      "path": "/api/agent/actions/:id",
      "auth": "app_session",
      "roles": [
        "admin",
        "oficina"
      ],
      "purpose": "Detalle auditado de una accion agent-native."
    },
    {
      "id": "agent_events",
      "method": "GET",
      "path": "/api/agent/events",
      "auth": "app_session",
      "roles": [
        "admin",
        "oficina"
      ],
      "purpose": "Lista de eventos agent-native filtrable por estado y severidad."
    },
    {
      "id": "agent_event_resolve",
      "method": "POST",
      "path": "/api/agent/events/:id/resolve",
      "auth": "app_session",
      "roles": [
        "admin",
        "oficina"
      ],
      "purpose": "Resolver eventos agent-native con nota de resolucion trazable."
    },
    {
      "id": "agent_alerts",
      "method": "GET",
      "path": "/api/agent/alerts",
      "auth": "app_session",
      "roles": [
        "admin",
        "oficina",
        "operador",
        "cliente"
      ],
      "purpose": "Alertas operativas derivadas de viajes accesibles por rol."
    },
    {
      "id": "send_evidence_email",
      "method": "POST",
      "path": "/api/send-evidence-email",
      "auth": "app_session",
      "purpose": "Envio de evidencias por correo con control de sesion."
    }
  ],
  "permissions": {
    "autonomousAllowed": [
      "customer_status_prepare"
    ],
    "approvalOptional": [
      "trip_create",
      "trip_update_status",
      "trip_add_expense"
    ],
    "approvalRequired": [
      "trip_close",
      "customer_whatsapp_send"
    ],
    "prohibited": [
      "delete_trip_without_human_approval",
      "send_freeform_client_message_without_approval"
    ],
    "idempotency": {
      "requiredForApiWrites": true,
      "headerOrBody": [
        "Idempotency-Key",
        "idempotency_key"
      ]
    }
  },
  "errorContract": {
    "schema": "slm.agent_error.v1",
    "shape": {
      "ok": false,
      "error": {
        "code": "machine_readable_string",
        "message": "human_readable_spanish",
        "field": "optional_field_name",
        "retryable": "boolean",
        "details": "optional_structured_context"
      }
    }
  },
  "playbooks": [
    {
      "id": "customer_status_update",
      "intent": "Responder estatus operativo a cliente sin enviar libremente por WhatsApp.",
      "steps": [
        "Buscar viaje por unidad, cliente o contenedor en /api/agent/trips.",
        "Leer detalle en /api/agent/trips/:id y, si aplica, GPS con /api/trip-gps.",
        "Preparar customer_status_prepare con mensaje sugerido.",
        "Si el canal es WhatsApp externo, crear customer_whatsapp_send y esperar aprobacion humana."
      ],
      "forbidden": [
        "Enviar mensajes externos sin approval required aprobado."
      ]
    },
    {
      "id": "trip_status_change",
      "intent": "Actualizar estatus de viaje con trazabilidad.",
      "steps": [
        "Validar que el viaje exista y que el estatus nuevo este en statuses.tripStatuses.",
        "Registrar trip_update_status con idempotency_key.",
        "Ejecutar solo si no requiere aprobacion adicional por politica local.",
        "Verificar el cambio leyendo /api/agent/trips/:id."
      ]
    },
    {
      "id": "expense_capture",
      "intent": "Agregar gasto a viaje sin confundir campos financieros.",
      "steps": [
        "Leer schema gasto y contrato trip_expense_form.",
        "Validar viaje_id, tipo, monto numerico y fecha.",
        "Usar trip_add_expense con idempotency_key.",
        "Verificar que el gasto aparezca en related.gastos del detalle de viaje."
      ]
    },
    {
      "id": "evidence_review",
      "intent": "Revisar o subir evidencia manteniendo contexto de viaje.",
      "steps": [
        "Abrir detalle de viaje o usar /api/agent/trips/:id.",
        "Usar evidence_form para ubicar tipo, nota, archivos y accion evidence.upload.",
        "Nunca inferir evidencia faltante como entregada si no existe registro."
      ]
    }
  ],
  "tasks": [
    {
      "id": "find_trip",
      "intent": "Encontrar viaje por cliente, unidad, contenedor, operador o ruta.",
      "route": "viajes",
      "selectors": [
        "tripRow",
        "tripCard"
      ],
      "expectedResult": "Abrir detalle con contexto recuperable."
    },
    {
      "id": "prepare_customer_status",
      "intent": "Preparar un mensaje de estatus sin enviarlo automaticamente.",
      "route": "agent_ops",
      "actionId": "customer_status_prepare",
      "expectedResult": "Accion registrada y visible para revision."
    },
    {
      "id": "request_sensitive_approval",
      "intent": "Pedir aprobacion humana antes de WhatsApp, cierre o impacto financiero.",
      "route": "agent_ops",
      "actionStatuses": [
        "blocked",
        "pending_approval",
        "approved"
      ],
      "expectedResult": "Aprobacion trazable antes de ejecutar."
    },
    {
      "id": "audit_agent_activity",
      "intent": "Revisar que hizo o propuso una automatizacion.",
      "route": "agent_ops",
      "selectors": [
        "agentActionRow",
        "agentEventRow"
      ],
      "expectedResult": "Bitacora con payload, actor, riesgo, estado y resultado."
    }
  ],
  "dataSurfaces": {
    "actionLogTable": "agent_action_log",
    "eventQueueTable": "agent_event_queue",
    "publicManifest": "/agent-manifest.json",
    "runtimeManifest": "window.__SLM_AGENT_NATIVE_MANIFEST__",
    "runtimeState": "window.__SLM_AGENT_STATE__"
  }
}
