1
03-models.md
hack_23031391_8ff9d8 edited this page 2026-05-23 02:38:38 +00:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Modelos de Datos

Schemas JSON completos de request/response para todos los endpoints.


Entidades del Dominio

Ruta

{
  "id": "RUTA-01",
  "nombre": "Ruta Centro Celaya",
  "turno": "matutino"
}

Campos:

  • id (string) — Identificador único
  • nombre (string) — Nombre descriptivo
  • turno (string) — "matutino" | "nocturno"

Punto de Ruta

{
  "id": 1,
  "ruta_id": "RUTA-01",
  "orden": 1,
  "nombre": "Plaza Principal",
  "lat": 20.5289,
  "lng": -100.8157,
  "tiempo_estimado_min": 5
}

Campos:

  • id (int) — ID único del punto
  • ruta_id (string) — FK a rutas
  • orden (int) — Secuencia (1, 2, 3...)
  • nombre (string) — Nombre del waypoint
  • lat (float) — Latitud
  • lng (float) — Longitud
  • tiempo_estimado_min (int) — Minutos estimados en este punto

Estado del Camión

{
  "route_id": "RUTA-01",
  "current_position_id": 3,
  "last_update": "2026-05-22T19:35:12.123456",
  "status": "EN_RUTA"
}

Campos:

  • route_id (string) — PK, FK a rutas
  • current_position_id (int) — FK a puntos_ruta.id
  • last_update (datetime ISO-8601) — Última actualización
  • status (string) — "EN_RUTA" | "AVERIADA" | "RETRASADA"

Usuario

{
  "id": 1,
  "email": "usuario@ejemplo.com",
  "phone": "+52 1234567890",
  "fcm_token": "firebase-device-token-here",
  "created_at": "2026-05-22T18:00:00"
}

Campos:

  • id (int) — PK
  • email (string) — Email único
  • phone (string) — Teléfono opcional
  • fcm_token (string, nullable) — Token de Firebase Cloud Messaging
  • created_at (datetime ISO-8601)

Nota: password_hash nunca se devuelve en responses.


Domicilio

{
  "id": 1,
  "user_id": 1,
  "alias": "Mi casa",
  "lat": 20.5200,
  "lng": -100.8100,
  "route_id": "RUTA-01",
  "created_at": "2026-05-22T18:30:00"
}

Campos:

  • id (int) — PK
  • user_id (int) — FK a users
  • alias (string) — Nombre dado por el usuario
  • lat (float) — Latitud
  • lng (float) — Longitud
  • route_id (string, nullable) — Ruta asignada
  • created_at (datetime ISO-8601)

Preferencias de Notificación

{
  "user_id": 1,
  "notify_proximity": true,
  "notify_breakdown": true,
  "notify_delay": true,
  "notify_route_start": false
}

Campos:

  • user_id (int) — PK, FK a users
  • notify_proximity (bool) — Notificar cuando el camión está cerca
  • notify_breakdown (bool) — Notificar averías
  • notify_delay (bool) — Notificar retrasos
  • notify_route_start (bool) — Notificar cuando la ruta inicia

Notificación (Log)

{
  "id": 1,
  "tipo": "aproximandose",
  "ruta_id": "RUTA-01",
  "address_id": 1,
  "mensaje": "El camión llega en ~8 minutos.",
  "eta_minutos": 8,
  "creada_en": "2026-05-22T19:35:00"
}

Campos:

  • id (int) — PK
  • tipo (string) — Tipo de evento
  • ruta_id (string) — FK a rutas
  • address_id (int, nullable) — FK a addresses
  • mensaje (string) — Texto enviado
  • eta_minutos (int, nullable)
  • creada_en (datetime ISO-8601)

Responses de Endpoints

GET /eta/{address_id}

Success (200):

{
  "address_id": 1,
  "route_id": "RUTA-01",
  "status": "EN_RUTA",
  "eta_minutos": 22,
  "ventana": {
    "inicio": "7:20 pm",
    "fin": "7:35 pm"
  },
  "mensaje": "El camión está en camino. Llegada estimada: 7:20 pm  7:35 pm."
}

Error (404):

{
  "detail": "Domicilio no encontrado o sin ruta asignada"
}

POST /alerts/breakdown

Request:

{
  "route_id": "RUTA-01"
}

Success (200):

{
  "message": "Alerta de avería enviada",
  "route_id": "RUTA-01",
  "notified_users": 3
}

Error (404):

{
  "detail": "Ruta no encontrada"
}

POST /register

Request:

{
  "email": "nuevo@ejemplo.com",
  "phone": "+52 1234567890",
  "password": "securepassword123",
  "fcm_token": "firebase-token-optional"
}

Success (201):

{
  "user_id": 5,
  "email": "nuevo@ejemplo.com",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1IiwiZXhwIjoxNzE2NDAwMDAwfQ.signature"
}

Error (400):

{
  "detail": "Email ya registrado"
}

POST /login

Request:

{
  "email": "usuario@ejemplo.com",
  "password": "securepassword123"
}

Success (200):

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user_id": 1,
  "email": "usuario@ejemplo.com"
}

Error (401):

{
  "detail": "Credenciales inválidas"
}

POST /addresses

Request:

{
  "alias": "Trabajo",
  "lat": 20.5300,
  "lng": -100.8200
}

Success (201):

{
  "address_id": 2,
  "alias": "Trabajo",
  "lat": 20.5300,
  "lng": -100.8200,
  "route_id": "RUTA-02",
  "created_at": "2026-05-22T19:00:00"
}

Error (400):

{
  "detail": "Coordenadas fuera de la zona de servicio"
}

GET /addresses

Success (200):

{
  "addresses": [
    {
      "address_id": 1,
      "alias": "Mi casa",
      "lat": 20.5200,
      "lng": -100.8100,
      "route_id": "RUTA-01"
    },
    {
      "address_id": 2,
      "alias": "Trabajo",
      "lat": 20.5300,
      "lng": -100.8200,
      "route_id": "RUTA-02"
    }
  ]
}

PUT /preferences

Request:

{
  "notify_proximity": true,
  "notify_breakdown": false,
  "notify_delay": true,
  "notify_route_start": true
}

Success (200):

{
  "message": "Preferencias actualizadas",
  "preferences": {
    "notify_proximity": true,
    "notify_breakdown": false,
    "notify_delay": true,
    "notify_route_start": true
  }
}

Eventos WebSocket

Estructura base

{
  "tipo": "string",
  "address_id": 1,
  "eta_minutos": 8,
  "mensaje": "string",
  "hora_utc": "2026-05-22T19:35:00.123456"
}

Ruta Iniciada

{
  "tipo": "ruta_iniciada",
  "address_id": 1,
  "eta_minutos": null,
  "mensaje": "El camión de tu zona comenzó su recorrido.",
  "hora_utc": "2026-05-22T19:00:00.123456"
}

Aproximándose

{
  "tipo": "aproximandose",
  "address_id": 1,
  "eta_minutos": 8,
  "mensaje": "El camión llega en ~8 minutos. Saca tu basura ahora.",
  "hora_utc": "2026-05-22T19:35:00.123456"
}

Falla Mecánica

{
  "tipo": "falla_mecanica",
  "address_id": 1,
  "eta_minutos": null,
  "mensaje": "El camión de tu zona presenta una falla mecánica. Te avisaremos cuando se resuelva.",
  "hora_utc": "2026-05-22T20:15:00.123456"
}

Ruta Tarde

{
  "tipo": "ruta_tarde",
  "address_id": 1,
  "eta_minutos": 45,
  "mensaje": "La ruta se ha retrasado debido a tráfico. Nueva estimación: 45 minutos.",
  "hora_utc": "2026-05-22T19:10:00.123456"
}

Completado

{
  "tipo": "completado",
  "address_id": 1,
  "eta_minutos": 0,
  "mensaje": "El camión pasó por tu zona. ¡Gracias por separar tu basura!",
  "hora_utc": "2026-05-22T19:43:00.123456"
}

Modelos Flutter (entidades)

ETAInfo

class ETAInfo {
  final int addressId;
  final String routeId;
  final String status;
  final int etaMinutos;
  final Ventana ventana;
  final String mensaje;
  
  ETAInfo.fromJson(Map<String, dynamic> json)
      : addressId = json['address_id'],
        routeId = json['route_id'],
        status = json['status'],
        etaMinutos = json['eta_minutos'],
        ventana = Ventana.fromJson(json['ventana']),
        mensaje = json['mensaje'];
}

class Ventana {
  final String inicio;
  final String fin;
  
  Ventana.fromJson(Map<String, dynamic> json)
      : inicio = json['inicio'],
        fin = json['fin'];
}

NotificationEvent

class NotificationEvent {
  final String tipo;
  final int addressId;
  final int? etaMinutos;
  final String mensaje;
  final DateTime hora;
  
  NotificationEvent.fromJson(Map<String, dynamic> json)
      : tipo = json['tipo'],
        addressId = json['address_id'],
        etaMinutos = json['eta_minutos'],
        mensaje = json['mensaje'],
        hora = DateTime.parse(json['hora_utc']);
}

User

class User {
  final int id;
  final String email;
  final String? phone;
  final String token;
  
  User.fromJson(Map<String, dynamic> json)
      : id = json['user_id'],
        email = json['email'],
        phone = json['phone'],
        token = json['token'];
}

Address

class Address {
  final int id;
  final String alias;
  final double lat;
  final double lng;
  final String? routeId;
  
  Address.fromJson(Map<String, dynamic> json)
      : id = json['address_id'],
        alias = json['alias'],
        lat = json['lat'],
        lng = json['lng'],
        routeId = json['route_id'];
}

Siguiente paso