FlotillasGPS - Sistema completo de monitoreo de flotillas GPS

Sistema completo para monitoreo y gestion de flotas de vehiculos con:
- Backend FastAPI con PostgreSQL/TimescaleDB
- Frontend React con TypeScript y TailwindCSS
- App movil React Native con Expo
- Soporte para dispositivos GPS, Meshtastic y celulares
- Video streaming en vivo con MediaMTX
- Geocercas, alertas, viajes y reportes
- Autenticacion JWT y WebSockets en tiempo real

Documentacion completa y guias de usuario incluidas.
This commit is contained in:
FlotillasGPS Developer
2026-01-21 08:18:00 +00:00
commit 51d78bacf4
248 changed files with 50171 additions and 0 deletions

268
backend/app/main.py Normal file
View File

@@ -0,0 +1,268 @@
"""
Aplicación principal FastAPI para Adan Fleet Monitor.
Sistema de monitoreo de flotillas GPS con soporte para:
- Tracking en tiempo real
- Gestión de vehículos y conductores
- Alertas y geocercas
- Video vigilancia
- Reportes y análisis
"""
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import JSONResponse
from app.core.config import settings
from app.core.database import close_db, init_db
from app.core.exceptions import register_exception_handlers
from app.api.v1 import api_router
from app.api.websocket import ubicaciones_router, alertas_router
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
Manejador del ciclo de vida de la aplicación.
Ejecuta código de inicialización al arrancar y
limpieza al cerrar la aplicación.
"""
# Startup
print(f"Starting {settings.APP_NAME} v{settings.APP_VERSION}")
print(f"Environment: {settings.ENVIRONMENT}")
print(f"Debug mode: {settings.DEBUG}")
# Inicializar base de datos (crear tablas si no existen)
if settings.ENVIRONMENT == "development":
try:
await init_db()
print("Database initialized")
except Exception as e:
print(f"Warning: Could not initialize database: {e}")
yield # La aplicación se ejecuta aquí
# Shutdown
print("Shutting down...")
await close_db()
print("Database connections closed")
# Crear aplicación FastAPI
app = FastAPI(
title=settings.APP_NAME,
description="""
## Adan Fleet Monitor API
Sistema de monitoreo de flotillas GPS.
### Funcionalidades principales:
- **Tracking en tiempo real** de vehículos
- **Gestión de flota**: vehículos, conductores, dispositivos
- **Alertas inteligentes**: velocidad, geocercas, batería
- **Viajes automáticos**: detección de inicio/fin
- **Geocercas**: zonas circulares y poligonales
- **Video vigilancia**: integración con cámaras
- **Reportes**: PDF, Excel, dashboards
### WebSocket endpoints:
- `/ws/ubicaciones` - Ubicaciones en tiempo real
- `/ws/alertas` - Alertas en tiempo real
- `/ws/vehiculo/{id}` - Seguimiento de un vehículo
- `/ws/flota` - Monitoreo de toda la flota
""",
version=settings.APP_VERSION,
docs_url="/docs" if settings.DEBUG else None,
redoc_url="/redoc" if settings.DEBUG else None,
openapi_url="/openapi.json" if settings.DEBUG else None,
lifespan=lifespan,
)
# ============================================================================
# Middlewares
# ============================================================================
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=settings.CORS_ALLOW_CREDENTIALS,
allow_methods=settings.CORS_ALLOW_METHODS,
allow_headers=settings.CORS_ALLOW_HEADERS,
)
# Compresión GZip
app.add_middleware(GZipMiddleware, minimum_size=1000)
# Middleware de logging de requests
@app.middleware("http")
async def log_requests(request: Request, call_next):
"""
Middleware para logging de requests.
Registra el tiempo de respuesta de cada request.
"""
start_time = datetime.now(timezone.utc)
response = await call_next(request)
# Calcular tiempo de procesamiento
process_time = (datetime.now(timezone.utc) - start_time).total_seconds()
response.headers["X-Process-Time"] = str(process_time)
# Log en modo debug
if settings.DEBUG:
print(
f"{request.method} {request.url.path} "
f"- {response.status_code} "
f"- {process_time:.3f}s"
)
return response
# Middleware de seguridad
@app.middleware("http")
async def security_headers(request: Request, call_next):
"""
Middleware para agregar headers de seguridad.
"""
response = await call_next(request)
# Headers de seguridad
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["X-XSS-Protection"] = "1; mode=block"
if not settings.DEBUG:
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
return response
# ============================================================================
# Registrar exception handlers
# ============================================================================
register_exception_handlers(app)
# ============================================================================
# Routers
# ============================================================================
# API REST v1
app.include_router(api_router, prefix=settings.API_V1_PREFIX)
# WebSocket endpoints
app.include_router(ubicaciones_router)
app.include_router(alertas_router)
# ============================================================================
# Endpoints base
# ============================================================================
@app.get("/", tags=["Root"])
async def root():
"""
Endpoint raíz de la API.
Returns:
Información básica de la API.
"""
return {
"name": settings.APP_NAME,
"version": settings.APP_VERSION,
"status": "online",
"environment": settings.ENVIRONMENT,
"docs": "/docs" if settings.DEBUG else "disabled",
}
@app.get("/health", tags=["Health"])
async def health_check():
"""
Health check endpoint.
Verifica el estado de la aplicación y sus dependencias.
Returns:
Estado de salud de la aplicación.
"""
health = {
"status": "healthy",
"timestamp": datetime.now(timezone.utc).isoformat(),
"version": settings.APP_VERSION,
"checks": {
"api": "ok",
},
}
# Verificar base de datos
try:
from app.core.database import check_db_connection
await check_db_connection()
health["checks"]["database"] = "ok"
except Exception as e:
health["checks"]["database"] = f"error: {str(e)}"
health["status"] = "degraded"
# Verificar Redis (si está configurado)
if settings.REDIS_URL:
try:
import aioredis
redis = await aioredis.from_url(settings.REDIS_URL)
await redis.ping()
await redis.close()
health["checks"]["redis"] = "ok"
except Exception as e:
health["checks"]["redis"] = f"error: {str(e)}"
health["status"] = "degraded"
return health
@app.get("/ready", tags=["Health"])
async def readiness_check():
"""
Readiness check para Kubernetes.
Verifica si la aplicación está lista para recibir tráfico.
Returns:
Estado de preparación.
"""
try:
from app.core.database import check_db_connection
await check_db_connection()
return {"ready": True}
except Exception:
return JSONResponse(
status_code=503,
content={"ready": False, "reason": "Database not ready"},
)
# ============================================================================
# Entry point para desarrollo
# ============================================================================
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app.main:app",
host=settings.HOST,
port=settings.PORT,
reload=settings.DEBUG,
workers=1 if settings.DEBUG else settings.WORKERS,
log_level="debug" if settings.DEBUG else "info",
)