2026-02-21 09:53:31 -05:00
""" FastAPI application entry point. """
from fastapi import FastAPI
from fastapi . middleware . cors import CORSMiddleware
from fastapi . staticfiles import StaticFiles
import os
from app . core . config import settings
2026-02-22 10:59:26 -05:00
from app . core . database import init_db , engine
from sqlmodel import Session , select
from app . models . taxi import Taxi
2026-02-22 16:00:52 -05:00
from app . models . shuttle import Shuttle
from app . models . business import Business
from app . models . coupon import Coupon
2026-02-21 09:53:31 -05:00
from app . api . routes import router as routes_router
from app . api . bus_stops import router as bus_stops_router
from app . api . schedules import router as schedules_router
from app . api . coupons import router as coupons_router
from app . api . taxis import router as taxis_router
from app . api . auth import router as auth_router
from app . api . users import router as users_router
from app . api . favorites import router as favorites_router
from app . api . telemetry import router as telemetry_router
from app . api . businesses import router as businesses_router
from app . api . analytics import router as analytics_router
from app . api . reports import router as reports_router
from app . api . shuttles import router as shuttles_router
2026-02-22 10:23:15 -05:00
from contextlib import asynccontextmanager
2026-02-22 16:00:52 -05:00
from alembic . config import Config
from alembic import command
import random
from datetime import datetime , timedelta
2026-02-22 10:23:15 -05:00
@asynccontextmanager
async def lifespan ( app : FastAPI ) :
2026-02-22 16:00:52 -05:00
# Run migrations
try :
alembic_cfg = Config ( " alembic.ini " )
command . upgrade ( alembic_cfg , " head " )
print ( " DEBUG: Database migrations completed successfully " )
except Exception as e :
print ( f " WARNING: Database migrations failed: { e } " )
# Fallback to init_db if alembic fails or isn't configured
try :
init_db ( )
except :
pass
2026-02-22 10:59:26 -05:00
# Seed sample data if empty
with Session ( engine ) as session :
2026-02-22 16:00:52 -05:00
# 1. Taxis
2026-02-22 10:59:26 -05:00
taxi_count = session . exec ( select ( Taxi ) ) . first ( )
if not taxi_count :
sample_taxis = [
Taxi (
owner_name = " Don José (Sibu Demo) " ,
phone_number = " +507 6000-0001 " ,
license_plate = " T-001-SIBU " ,
corregimiento = " Boquete " ,
shift = " dia " ,
rating = 4.9 ,
english_speaking = True
) ,
Taxi (
owner_name = " María C. (Sibu Demo) " ,
phone_number = " +507 6000-0002 " ,
license_plate = " T-002-SIBU " ,
corregimiento = " Boquete " ,
shift = " tarde " ,
rating = 5.0 ,
english_speaking = False
)
]
session . add_all ( sample_taxis )
session . commit ( )
2026-02-22 16:00:52 -05:00
# 2. Shuttles
shuttle_count = session . exec ( select ( Shuttle ) ) . first ( )
if not shuttle_count :
shuttles_data = [
{ ' route_name ' : ' Boquete > Santa Catalina ' , ' origin ' : ' Boquete ' , ' destination ' : ' Santa Catalina ' , ' vehicle_type ' : ' Mini Van ' , ' company_name ' : ' Chiriqui Transfers ' , ' trip_type ' : ' one_way ' , ' price_per_person ' : 35.0 , ' estimated_duration ' : ' 4.5 horas ' , ' departure_times ' : ' 8:00 AM ' , ' contact_whatsapp ' : ' +50760000000 ' , ' is_active ' : True } ,
{ ' route_name ' : ' Boquete > Bocas del Toro ' , ' origin ' : ' Boquete ' , ' destination ' : ' Bocas del Toro ' , ' vehicle_type ' : ' Van + Bote ' , ' company_name ' : ' Hello Panama ' , ' trip_type ' : ' one_way ' , ' price_per_person ' : 30.0 , ' estimated_duration ' : ' 3.5 horas ' , ' departure_times ' : ' 8:00 AM ' , ' contact_whatsapp ' : ' +50760000000 ' , ' is_active ' : True }
]
for data in shuttles_data :
session . add ( Shuttle ( * * data ) )
session . commit ( )
# 3. Businesses & Coupons (Tourist spots)
biz_count = session . exec ( select ( Business ) ) . first ( )
if not biz_count :
tourist_spots = [
{ " name " : " Finca El Explorador " , " area " : " Boquete " , " lat " : 8.7845 , " lng " : - 82.4350 } ,
{ " name " : " Cascada San Ramón " , " area " : " Boquete " , " lat " : 8.8120 , " lng " : - 82.4650 }
]
for spot in tourist_spots :
biz = Business ( name = spot [ " name " ] , address = f " Sector { spot [ ' area ' ] } " , phone = " 6000-0000 " , category = " Area Turistica " , area = spot [ " area " ] , latitude = spot [ " lat " ] , longitude = spot [ " lng " ] )
session . add ( biz )
session . flush ( )
coupon = Coupon ( title = f " Oferta en { biz . name } " , description = f " Descuento especial en { biz . name } " , business_id = biz . id , business_name = biz . name , business_address = biz . address , business_phone = biz . phone , category = biz . category , discount_percentage = 15 , valid_from = datetime . now ( ) . isoformat ( ) , valid_until = ( datetime . now ( ) + timedelta ( days = 30 ) ) . isoformat ( ) , is_active = True )
session . add ( coupon )
session . commit ( )
2026-02-22 10:23:15 -05:00
yield
2026-02-21 09:53:31 -05:00
app = FastAPI (
title = " SIBU Transportation API " ,
description = " API for SIBU public transportation system " ,
version = " 1.0.0 " ,
debug = settings . debug ,
2026-02-22 10:23:15 -05:00
lifespan = lifespan
2026-02-21 09:53:31 -05:00
)
# CORS middleware
2026-02-24 10:46:17 -05:00
origins = [ " * " ] # Permitir todos para producción corregida
2026-02-21 14:26:27 -05:00
2026-02-21 09:53:31 -05:00
app . add_middleware (
CORSMiddleware ,
2026-02-22 16:00:52 -05:00
allow_origins = origins ,
2026-02-21 09:53:31 -05:00
allow_credentials = True ,
allow_methods = [ " * " ] ,
allow_headers = [ " * " ] ,
)
# Ensure upload directories exist
for sub in [ " profiles " , " vehicles " , " businesses " ] :
os . makedirs ( os . path . join ( " uploads " , sub ) , exist_ok = True )
# Mount static files
app . mount ( " /uploads " , StaticFiles ( directory = " uploads " ) , name = " uploads " )
# Include routers
app . include_router ( routes_router )
app . include_router ( bus_stops_router )
app . include_router ( schedules_router )
app . include_router ( coupons_router )
app . include_router ( taxis_router )
app . include_router ( auth_router )
app . include_router ( users_router )
app . include_router ( favorites_router )
app . include_router ( telemetry_router )
app . include_router ( businesses_router )
app . include_router ( analytics_router , prefix = " /api/analytics " , tags = [ " analytics " ] )
app . include_router ( reports_router )
app . include_router ( shuttles_router )
@app.get ( " / " )
async def root ( ) :
""" Root endpoint. """
return { " message " : " SIBU Transportation API " , " version " : " 1.0.0 " }
@app.get ( " /health " )
async def health ( ) :
""" Health check endpoint. """
return { " status " : " healthy " , " environment " : settings . environment }