262 lines
7.1 KiB
Markdown
262 lines
7.1 KiB
Markdown
# API REST — Referencia
|
|
|
|
> Base URL: `http://10.82.68.125:8000/api/v1` · Docs interactivos: `http://localhost:8000/docs`
|
|
|
|
Todos los endpoints (excepto `/auth/*`) requieren header:
|
|
```
|
|
Authorization: Bearer <JWT_TOKEN>
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 Autenticación
|
|
|
|
### POST `/auth/register`
|
|
Crea un usuario nuevo (rol CIUDADANO por defecto).
|
|
|
|
**Request:**
|
|
```json
|
|
{ "full_name": "Juan Pérez", "email": "juan@example.com", "password": "secret123" }
|
|
```
|
|
**Response 201:**
|
|
```json
|
|
{ "access_token": "eyJ...", "token_type": "bearer", "role": "CIUDADANO" }
|
|
```
|
|
|
|
### POST `/auth/login`
|
|
**Request:**
|
|
```json
|
|
{ "email": "demo@celaya.gob.mx", "password": "Celaya2026" }
|
|
```
|
|
**Response 200:**
|
|
```json
|
|
{ "access_token": "eyJ...", "token_type": "bearer", "role": "CIUDADANO" }
|
|
```
|
|
**Response 401:** `{"detail": "Credenciales inválidas"}`
|
|
|
|
### POST `/auth/oauth`
|
|
Login/registro vía OAuth (Google, Facebook, Apple).
|
|
```json
|
|
{ "provider": "google", "oauth_id": "abc123", "email": "juan@gmail.com", "full_name": "Juan", "push_token": "..." }
|
|
```
|
|
|
|
### GET `/me`
|
|
Devuelve el usuario actual.
|
|
**Response:** `{ "id": 1, "full_name": "...", "email": "...", "role": "CIUDADANO" }`
|
|
|
|
---
|
|
|
|
## 🏠 Domicilios (`/addresses`)
|
|
|
|
### GET `/addresses/`
|
|
Lista tus domicilios.
|
|
**Response:** `[{"id":1, "label":"Casa", "street":"...", "lat":20.5, "lng":-100.8, "route_id":"RUTA-01", "is_default":true}, ...]`
|
|
|
|
### POST `/addresses/`
|
|
Crea un domicilio. Si pasas `lat`/`lng`, se asigna ruta automáticamente.
|
|
```json
|
|
{ "label": "Casa", "street": "Hidalgo 245", "colony": "Centro", "lat": 20.5215, "lng": -100.8142, "is_default": true }
|
|
```
|
|
|
|
### PATCH `/addresses/{id}`
|
|
Actualiza un domicilio. Solo campos modificados.
|
|
```json
|
|
{ "is_default": true }
|
|
```
|
|
|
|
### DELETE `/addresses/{id}` → 204
|
|
|
|
---
|
|
|
|
## ⏰ ETA (`/eta`)
|
|
|
|
### GET `/eta/address/{id}` — núcleo del sistema
|
|
**Privacy-by-design:** nunca devuelve coordenadas del camión.
|
|
|
|
**Response 200:**
|
|
```json
|
|
{
|
|
"status": "EN_CAMINO",
|
|
"message": "El camión llegará a tu zona entre las 7:20 y 7:35",
|
|
"eta_minutes": 12,
|
|
"window_start": "07:20",
|
|
"window_end": "07:35",
|
|
"progress": 45.2,
|
|
"route_name": "Zona Centro - Las Arboledas",
|
|
"passes_today": true
|
|
}
|
|
```
|
|
|
|
**Estados posibles:**
|
|
- `PROGRAMADO` — la ruta aún no empieza hoy
|
|
- `EN_CAMINO` — el camión va en ruta
|
|
- `LLEGANDO` — faltan ≤10 minutos
|
|
- `PASO` — ya pasó por la zona
|
|
- `NO_SERVICIO` — no aplica hoy
|
|
|
|
### GET `/eta/schedule/{address_id}`
|
|
Devuelve días y horario aproximado.
|
|
```json
|
|
{ "route_id":"RUTA-01", "route_name":"Zona Centro - Las Arboledas",
|
|
"days_of_week":["Lunes","Miércoles","Viernes"], "approximate_time":"06:00 - 07:40",
|
|
"truck_id": 101 }
|
|
```
|
|
|
|
### POST `/eta/rate`
|
|
Califica el servicio.
|
|
```json
|
|
{ "address_id": 1, "rating": 5, "comment": "Excelente puntualidad" }
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Reportes ciudadanos (`/reports`)
|
|
|
|
### POST `/reports/`
|
|
Crea un reporte con folio único.
|
|
```json
|
|
{ "address_id": 1, "report_type": "NO_PASO", "description": "El camión no pasó hoy" }
|
|
```
|
|
**Response 201:**
|
|
```json
|
|
{ "id":5, "folio":"MRL-20260523-F6EC92", "status":"PENDIENTE",
|
|
"report_type":"NO_PASO", "description":"...", "created_at":"...", "address_label":"Casa" }
|
|
```
|
|
|
|
**Tipos:** `NO_PASO` · `RETRASO` · `ACUMULACION` · `OTRO`
|
|
|
|
### GET `/reports/`
|
|
Tus reportes (no los de otros usuarios).
|
|
|
|
### GET `/reports/{id}`
|
|
Detalle con la etiqueta del domicilio.
|
|
|
|
---
|
|
|
|
## 👮 Staff (`/staff`) — solo EMPLEADO o ADMIN
|
|
|
|
### GET `/staff/dashboard`
|
|
Métricas motivacionales del empleado.
|
|
```json
|
|
{
|
|
"employee_name": "Carlos Hernández",
|
|
"streak_days": 19,
|
|
"punctuality_pct": 88,
|
|
"bonus_accumulated_mxn": 950,
|
|
"next_milestone_days": 11,
|
|
"next_milestone_mxn": 500,
|
|
"reports_generated": 5,
|
|
"motivation_quote": "Tu puntualidad permite que miles de familias planifiquen su día",
|
|
"rating_label": "BUENO"
|
|
}
|
|
```
|
|
|
|
### GET `/staff/schedule`
|
|
Horario preestablecido con descansos.
|
|
|
|
### GET `/staff/categories`
|
|
Las 8 categorías disponibles para reportes operativos.
|
|
|
|
### POST `/staff/operational-reports`
|
|
Crea un reporte operativo (folio `OP-...`).
|
|
```json
|
|
{ "category": "FALLA_MECANICA", "severity": "MEDIA", "description": "Frenos haciendo ruido", "route_id": "RUTA-01", "truck_id": 12 }
|
|
```
|
|
|
|
**Categorías:** `NO_ARRANQUE` · `FALLA_MECANICA` · `ACCIDENTE` · `OBSTACULO` · `TRAFICO` · `COMBUSTIBLE` · `CLIMA` · `OTRO`
|
|
|
|
### GET `/staff/operational-reports`
|
|
Lista tus reportes operativos.
|
|
|
|
---
|
|
|
|
## 🛡️ Admin (`/admin`) — solo ADMIN
|
|
|
|
### GET `/admin/stats`
|
|
KPIs globales del sistema.
|
|
```json
|
|
{
|
|
"total_ciudadanos": 185, "total_domicilios": 302, "total_reportes": 280,
|
|
"reportes_24h": 8, "promedio_calificacion": 4.07,
|
|
"reportes_por_estado": {"PENDIENTE": 84, "EN_PROCESO": 56, "RESUELTO": 112, "CERRADO": 28},
|
|
"reportes_por_tipo": {"NO_PASO": 98, "RETRASO": 84, ...},
|
|
"rutas_activas": 15
|
|
}
|
|
```
|
|
|
|
### GET `/admin/reports?status=PENDIENTE&report_type=NO_PASO`
|
|
Lista TODOS los reportes ciudadanos (no solo los tuyos). Filtros opcionales.
|
|
|
|
### PATCH `/admin/reports/{id}/status?status=EN_PROCESO`
|
|
Cambia el estado de un reporte. Estados válidos: `PENDIENTE | EN_PROCESO | RESUELTO | CERRADO`.
|
|
|
|
### GET `/admin/routes`
|
|
Lista todas las rutas con su estado actual.
|
|
|
|
### GET `/admin/users?role=CIUDADANO`
|
|
Lista usuarios con conteos de domicilios y reportes.
|
|
|
|
### PATCH `/admin/users/{id}/role?role=EMPLEADO`
|
|
Cambia el rol de un usuario. Roles: `CIUDADANO | EMPLEADO | ADMIN`.
|
|
|
|
### GET `/admin/feedback`
|
|
Últimas 50 calificaciones del servicio.
|
|
|
|
---
|
|
|
|
## 🔒 Códigos de respuesta
|
|
|
|
| Código | Significado |
|
|
|--------|-------------|
|
|
| 200 | OK |
|
|
| 201 | Creado |
|
|
| 204 | Sin contenido (DELETE exitoso) |
|
|
| 400 | Bad request (validación falló) |
|
|
| 401 | No autenticado / token inválido |
|
|
| 403 | Sin permisos para este recurso |
|
|
| 404 | Recurso no encontrado o no te pertenece |
|
|
| 500 | Error del servidor |
|
|
|
|
---
|
|
|
|
## 🧪 Ejemplos con curl
|
|
|
|
### Flujo completo: ciudadano → reporte → admin lo resuelve
|
|
|
|
```bash
|
|
BASE=http://10.82.68.125:8000/api/v1
|
|
|
|
# 1. Login ciudadano
|
|
CTOKEN=$(curl -s -X POST $BASE/auth/login -H "Content-Type: application/json" \
|
|
-d '{"email":"demo@celaya.gob.mx","password":"Celaya2026"}' | jq -r .access_token)
|
|
|
|
# 2. Listar domicilios
|
|
curl -s $BASE/addresses/ -H "Authorization: Bearer $CTOKEN" | jq
|
|
|
|
# 3. Ver ETA del domicilio 1
|
|
curl -s $BASE/eta/address/1 -H "Authorization: Bearer $CTOKEN" | jq
|
|
|
|
# 4. Crear reporte
|
|
REPORT=$(curl -s -X POST $BASE/reports/ -H "Authorization: Bearer $CTOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"address_id":1,"report_type":"NO_PASO","description":"Hoy no pasó"}')
|
|
echo $REPORT | jq
|
|
|
|
REPORT_ID=$(echo $REPORT | jq -r .id)
|
|
|
|
# 5. Login admin
|
|
ATOKEN=$(curl -s -X POST $BASE/auth/login -H "Content-Type: application/json" \
|
|
-d '{"email":"admin@celaya.gob.mx","password":"Admin2026"}' | jq -r .access_token)
|
|
|
|
# 6. Admin ve TODOS los reportes
|
|
curl -s $BASE/admin/reports -H "Authorization: Bearer $ATOKEN" | jq '. | length'
|
|
|
|
# 7. Admin cambia el estado a EN_PROCESO
|
|
curl -s -X PATCH "$BASE/admin/reports/$REPORT_ID/status?status=EN_PROCESO" \
|
|
-H "Authorization: Bearer $ATOKEN" | jq
|
|
|
|
# 8. El ciudadano vuelve a consultar y ve el cambio
|
|
curl -s $BASE/reports/$REPORT_ID -H "Authorization: Bearer $CTOKEN" | jq .status
|
|
# → "EN_PROCESO" ✓
|
|
```
|