Skip to main content

Overview

The Tesis Rutas backend is built with FastAPI and follows Clean Architecture principles. It uses MongoDB for data persistence and JWT for authentication.

Prerequisites

  • Python 3.9+ installed
  • MongoDB running (local or Atlas)
  • pip or virtualenv for dependency management

Installation

1

Create virtual environment

python -m venv venv
2

Activate virtual environment

source venv/bin/activate
3

Install dependencies

pip install -r requirements.txt
Key dependencies:
  • fastapi - Modern web framework
  • uvicorn - ASGI server
  • pymongo - MongoDB driver
  • python-jose - JWT authentication
  • bcrypt - Password hashing
  • cloudinary - Image upload service
  • pydantic-settings - Configuration management
4

Configure environment

Create src/config/local_config.json:
{
  "MONGO_URI": "mongodb://localhost:27017",
  "MONGO_DB": "turismo_digital_uce",
  "JWT_SECRET_KEY": "your-secret-key-here",
  "JWT_ALGORITHM": "HS256",
  "JWT_EXPIRE_MINUTES": 60,
  "CLOUDINARY_CLOUD_NAME": "your-cloud-name",
  "CLOUDINARY_API_KEY": "your-api-key",
  "CLOUDINARY_API_SECRET": "your-api-secret"
}
Never commit local_config.json to version control. It’s already in .gitignore.
5

Start the server

uvicorn src.infrastructure.api.main:app --reload
The API will be available at http://localhost:8000

Clean Architecture Structure

The backend follows Clean Architecture with clear separation of concerns:
src/
β”œβ”€β”€ domain/                    # Enterprise business rules
β”‚   β”œβ”€β”€ entities/             # Core business objects
β”‚   β”‚   β”œβ”€β”€ destino.py        # Destination entity
β”‚   β”‚   β”œβ”€β”€ usuario.py        # User entity
β”‚   β”‚   β”œβ”€β”€ ruta_turistica.py # Route entity
β”‚   β”‚   └── multimedia.py     # Media entity
β”‚   β”œβ”€β”€ repositories/         # Repository interfaces
β”‚   └── value_objects/        # Value objects (Coordenadas)
β”œβ”€β”€ application/              # Application business rules
β”‚   β”œβ”€β”€ use_cases/           # Use case implementations
β”‚   β”‚   β”œβ”€β”€ agregar_destino.py
β”‚   β”‚   β”œβ”€β”€ editar_destino.py
β”‚   β”‚   β”œβ”€β”€ auth/            # Authentication use cases
β”‚   β”‚   β”œβ”€β”€ users/           # User management
β”‚   β”‚   └── Rutas/           # Route management
β”‚   └── services/            # Application services
β”œβ”€β”€ infrastructure/           # External interfaces
β”‚   β”œβ”€β”€ api/                 # FastAPI routes
β”‚   β”‚   β”œβ”€β”€ main.py          # App initialization
β”‚   β”‚   └── routers/         # API endpoints
β”‚   β”‚       β”œβ”€β”€ destinos_router.py
β”‚   β”‚       β”œβ”€β”€ rutas_router.py
β”‚   β”‚       β”œβ”€β”€ auth_router.py
β”‚   β”‚       └── usuario_router.py
β”‚   β”œβ”€β”€ database/            # MongoDB implementation
β”‚   β”‚   β”œβ”€β”€ mongo_config.py  # Connection manager
β”‚   β”‚   └── destino_repository_impl.py
β”‚   β”œβ”€β”€ security/            # JWT utilities
β”‚   └── services/            # External services (Cloudinary)
└── config/                   # Configuration
    β”œβ”€β”€ settings.py          # Pydantic settings
    └── local_config.json    # Local credentials (gitignored)

Architecture Layers

1

Domain Layer

Contains business entities and rules. No dependencies on external frameworks.
src/domain/entities/destino.py
from datetime import datetime
from typing import Optional
from src.domain.value_objects.coordenadas import Coordenadas

class Destino:
    def __init__(
        self,
        nombre: str,
        ubicacion: str,
        importancia: str,
        coordenadas: Coordenadas,
        anio_construccion: list[int],
        id: Optional[str] = None,
        activo: bool = True
    ):
        self.nombre = nombre.strip()
        self.ubicacion = ubicacion.strip()
        self.importancia = importancia.strip()
        self.coordenadas = coordenadas
        self.anio_construccion = anio_construccion
        self.id = id
        self.activo = activo

    def to_dict(self) -> dict:
        return {
            "_id": self.id,
            "nombre": self.nombre,
            "ubicacion": self.ubicacion,
            "coordenadas": self.coordenadas.to_dict(),
            "activo": self.activo
        }
2

Application Layer

Implements use cases that orchestrate business logic.
src/application/use_cases/agregar_destino.py
class AgregarDestinoUseCase:
    def __init__(self, destino_repository):
        self.destino_repository = destino_repository

    def ejecutar(self, data: dict) -> str:
        # Business logic
        destino = self._crear_entidad(data)
        return self.destino_repository.agregar(destino)
3

Infrastructure Layer

Handles external concerns: API, database, authentication.
src/infrastructure/api/main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI(title="Turismo Digital UCE API")

# CORS Configuration
origins = [
    "http://localhost:5173",  # Vite frontend
    "http://127.0.0.1:5173",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include routers
app.include_router(destinos_router.router)
app.include_router(rutas_router.router)
app.include_router(auth_router.router)

@app.get("/")
def root():
    return {"message": "API de Turismo Digital UCE funcionando correctamente πŸš€"}

API Endpoints

The API exposes the following routers:

Destinos (Destinations)

src/infrastructure/api/routers/destinos_router.py
from fastapi import APIRouter, Depends

router = APIRouter(prefix="/destinos", tags=["Destinos"])

@router.post("/")  # Create destination (admin only)
@router.get("/")   # List all destinations
@router.put("/{id}")  # Update destination (admin only)
@router.delete("/{id}")  # Delete destination (admin only)

Rutas (Routes)

router = APIRouter(prefix="/rutas", tags=["Rutas"])

@router.post("/")  # Create route
@router.get("/")   # List routes
@router.get("/{id}")  # Get route details

Auth (Authentication)

router = APIRouter(prefix="/auth", tags=["Auth"])

@router.post("/register")  # Register new user
@router.post("/login")     # Login and get JWT token

Testing Endpoints

Navigate to http://localhost:8000/docs for interactive API documentation (Swagger UI).Features:
  • Try endpoints directly from the browser
  • See request/response schemas
  • Test authentication flows

Running with Hot Reload

The --reload flag enables auto-restart on code changes:
uvicorn src.infrastructure.api.main:app --reload --host 0.0.0.0 --port 8000
Options:
  • --reload - Auto-reload on file changes
  • --host 0.0.0.0 - Listen on all network interfaces
  • --port 8000 - Custom port (default: 8000)
  • --log-level debug - Verbose logging

Troubleshooting

Ensure you’re running uvicorn from the project root directory, not from inside src/.
# Correct (from project root)
uvicorn src.infrastructure.api.main:app --reload

# Wrong (from src/ directory)
uvicorn infrastructure.api.main:app --reload
Check if MongoDB is running:
# Local MongoDB
sudo systemctl status mongod

# Or test connection
mongosh --eval "db.adminCommand('ping')"
Verify MONGO_URI in local_config.json is correct.
Ensure http://localhost:5173 is in the origins list in main.py:
origins = [
    "http://localhost:5173",
    "http://127.0.0.1:5173",
]
Generate a secure secret key:
python -c "import secrets; print(secrets.token_urlsafe(32))"
Add it to local_config.json as JWT_SECRET_KEY.

Next Steps

Database Setup

Configure MongoDB and understand the schema

Frontend Setup

Set up the React frontend

Build docs developers (and LLMs) love