Clone
Table of Contents
- Modelos de Datos
- Entidades del Dominio
- Ruta
- Punto de Ruta
- Estado del Camión
- Usuario
- Domicilio
- Preferencias de Notificación
- Notificación (Log)
- Responses de Endpoints
- GET /eta/{address_id}
- POST /alerts/breakdown
- POST /register
- POST /login
- POST /addresses
- GET /addresses
- PUT /preferences
- Eventos WebSocket
- Modelos Flutter (entidades)
- Siguiente paso
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 úniconombre(string) — Nombre descriptivoturno(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 puntoruta_id(string) — FK a rutasorden(int) — Secuencia (1, 2, 3...)nombre(string) — Nombre del waypointlat(float) — Latitudlng(float) — Longitudtiempo_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 rutascurrent_position_id(int) — FK a puntos_ruta.idlast_update(datetime ISO-8601) — Última actualizaciónstatus(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) — PKemail(string) — Email únicophone(string) — Teléfono opcionalfcm_token(string, nullable) — Token de Firebase Cloud Messagingcreated_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) — PKuser_id(int) — FK a usersalias(string) — Nombre dado por el usuariolat(float) — Latitudlng(float) — Longitudroute_id(string, nullable) — Ruta asignadacreated_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 usersnotify_proximity(bool) — Notificar cuando el camión está cercanotify_breakdown(bool) — Notificar averíasnotify_delay(bool) — Notificar retrasosnotify_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) — PKtipo(string) — Tipo de eventoruta_id(string) — FK a rutasaddress_id(int, nullable) — FK a addressesmensaje(string) — Texto enviadoeta_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
- Integración entre módulos — conectar A, B, C, D
- Troubleshooting