Skip to main content

Overview

Tesis Rutas is built using Clean Architecture principles, ensuring separation of concerns, testability, and maintainability. The system consists of a FastAPI backend, React frontend, and cloud services for data storage and media management.
Clean Architecture organizes code into distinct layers with clear dependencies flowing from outer (infrastructure) to inner (domain) layers.

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                        Presentation Layer                    │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   React Frontend (Vite + React Router + Leaflet)       │ │
│  │   - Interactive Maps (Leaflet, react-leaflet)          │ │
│  │   - UI Components (Radix UI, Tailwind CSS)             │ │
│  │   - State Management (Context API)                     │ │
│  │   - Forms (react-hook-form)                            │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
                              ↕ HTTP/REST + JWT
┌─────────────────────────────────────────────────────────────┐
│                    Infrastructure Layer                      │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   FastAPI REST API                                     │ │
│  │   - Routers (destinos, rutas, auth, usuarios)          │ │
│  │   - JWT Authentication & Role-Based Access             │ │
│  │   - CORS Middleware                                    │ │
│  │   - File Upload Handling                               │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   External Services                                    │ │
│  │   - MongoDB Repository Implementations                 │ │
│  │   - Cloudinary Media Storage                           │ │
│  │   - JWT Token Service                                  │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                     Application Layer                        │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   Use Cases (Business Logic Orchestration)             │ │
│  │   - AgregarDestinoUseCase                              │ │
│  │   - EditarDestinoUseCase                               │ │
│  │   - CrearRutaTuristicaUseCase                          │ │
│  │   - RegisterUsuarioUseCase                             │ │
│  │   - LoginUsuarioUseCase                                │ │
│  │   - AgregarMultimediaDestinoUseCase                    │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                       Domain Layer                           │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   Entities (Pure Business Objects)                     │ │
│  │   - Destino                                            │ │
│  │   - RutaTuristica                                      │ │
│  │   - RutaPOI                                            │ │
│  │   - Usuario                                            │ │
│  │   - Multimedia                                         │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   Value Objects                                        │ │
│  │   - Coordenadas (latitude, longitude)                  │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   Repository Interfaces                                │ │
│  │   - IDestinoRepository                                 │ │
│  │   - IRutaRepository                                    │ │
│  │   - IUsuarioRepository                                 │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      Data Storage Layer                      │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   MongoDB Atlas (Database)                             │ │
│  │   - destinos collection                                │ │
│  │   - rutas collection                                   │ │
│  │   - usuarios collection                                │ │
│  └────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────┐ │
│  │   Cloudinary (Media Storage)                           │ │
│  │   - destinations/{id}/ folders                         │ │
│  │   - Image & video hosting                              │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Technology Stack

Backend

FastAPI

Modern Python web framework with automatic API documentation, async support, and type validationVersion: 0.121.1

Pydantic

Data validation using Python type annotationsVersion: 2.12.4

PyMongo

Official MongoDB driver for PythonVersion: 4.15.3

python-jose

JWT token creation and validationVersion: 3.5.0
Key backend dependencies from requirements.txt:
fastapi==0.121.1
uvicorn==0.38.0
pymongo==4.15.3
pydantic==2.12.4
pydantic-settings==2.11.0
python-jose==3.5.0
bcrypt==5.0.0
cloudinary==1.44.1
python-dotenv==1.2.1
python-multipart==0.0.20

Frontend

React 19

Modern UI library with latest featuresVersion: 19.2.0

Vite

Lightning-fast build tool and dev serverVersion: 7.2.4

React Router

Client-side routing with protected routesVersion: 7.10.1

Leaflet

Interactive map visualizationVersion: 1.9.4
Key frontend dependencies from frontend/package.json:
{
  "dependencies": {
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-router-dom": "^7.10.1",
    "leaflet": "^1.9.4",
    "react-leaflet": "^5.0.0",
    "axios": "^1.13.2",
    "react-hook-form": "^7.70.0",
    "@radix-ui/react-dialog": "^1.1.15",
    "@radix-ui/react-select": "^2.2.6",
    "tailwindcss": "^4.1.18",
    "@turf/turf": "^7.3.2"
  }
}

Cloud Services

Purpose: Primary database for storing destinations, routes, and user dataCollections:
  • destinos - Heritage destination documents
  • rutas - Tourist route documents
  • usuarios - User accounts and authentication
Connection: Managed through MongoDBConnection singleton class (src/infrastructure/database/mongo_config.py)
class MongoDBConnection:
    _client = None
    _db = None
    
    @classmethod
    def connect(cls):
        cls._client = MongoClient(settings.mongo_uri, 
                                 serverSelectionTimeoutMS=5000)
        cls._db = cls._client[settings.mongo_db]

Clean Architecture Layers

1. Domain Layer (Core Business Logic)

The innermost layer containing pure business objects with no external dependencies. Location: src/domain/
Business objects representing core concepts.Destino Entity (src/domain/entities/destino.py):
class Destino:
    def __init__(
        self,
        nombre: str,
        ubicacion: str,
        importancia: str,
        coordenadas: Coordenadas,
        anio_construccion: list[int],
        arquitecto: Optional[str] = None,
        area_construccion: Optional[float] = None,
        funcion: Optional[str] = None,
        multimedia: Optional[list[dict]] = None,
        id: Optional[str] = None,
        fecha_creacion: Optional[datetime] = None,
        activo: bool = True
    ):
        self.nombre = nombre.strip()
        self.ubicacion = ubicacion.strip()
        self.importancia = importancia.strip()
        
        if not anio_construccion or len(anio_construccion) not in (1, 2):
            raise ValueError("El año de construcción debe contener uno o dos valores válidos.")
        
        self.anio_construccion = anio_construccion
        self.coordenadas = coordenadas
        # ... additional fields
RutaTuristica Entity (src/domain/entities/ruta_turistica.py):
@dataclass
class RutaTuristica:
    nombre: str
    descripcion: Optional[str]
    categoria: str
    puntos: List[RutaPOI] = field(default_factory=list)
    creado_en: datetime = field(default_factory=datetime.utcnow)

2. Application Layer (Use Cases)

Orchestrates business logic by coordinating entities and repository operations. Location: src/application/use_cases/
From src/application/use_cases/agregar_destino.py:
class AgregarDestinoUseCase:
    def __init__(self, repository: IDestinoRepository):
        self.repository = repository

    def ejecutar(self, data: dict) -> str:
        coordenadas = Coordenadas(
            latitud=data["coordenadas"]["latitud"],
            longitud=data["coordenadas"]["longitud"]
        )

        destino = Destino(
            nombre=data["nombre"],
            ubicacion=data["ubicacion"],
            importancia=data["importancia"],
            coordenadas=coordenadas,
            anio_construccion=data["anio_construccion"],
            arquitecto=data.get("arquitecto"),
            area_construccion=data.get("area_construccion"),
            funcion=data.get("funcion")
        )

        return self.repository.crear_destino(destino)
Key Features:
  • Depends on repository interface, not implementation
  • Validates and transforms input data
  • Creates domain entities
  • Returns simple types (IDs, success indicators)
Available Use Cases:

Destinations

  • AgregarDestinoUseCase
  • EditarDestinoUseCase
  • EliminarDestinoUseCase
  • CambiarEstadoDestinoUseCase
  • AgregarMultimediaDestinoUseCase
  • EliminarMultimediaDestinoUseCase

Routes

  • CrearRutaTuristicaUseCase
  • ActualizarRutaTuristicaUseCase
  • EliminarRutaTuristicaUseCase
  • ListarRutasTuristicasUseCase
  • ObtenerRutaTuristicaUseCase
  • GenerarRutaDesdePOIUseCase
  • SugerirPoisProximosUseCase

Authentication

  • RegisterUsuarioUseCase
  • LoginUsuarioUseCase
  • AuthUseCases

Users

  • ActualizarUsuarioUseCase
  • AgregarFavoritoUseCase
  • AsignarRolAdminOnlyUseCase

3. Infrastructure Layer

Implements technical details like API routes, database access, and external service integration. Location: src/infrastructure/
FastAPI routers handling HTTP requests.Main Application (src/infrastructure/api/main.py):
app = FastAPI(title="Turismo Digital UCE API")

# CORS Configuration
origins = [
    "http://localhost:5173",
    "http://127.0.0.1:5173",
    "https://tesis-rutas.vercel.app",
]

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.include_router(usuario_router.router)
Routers:
  • destinos_router.py - Destination CRUD operations
  • rutas_router.py - Route management
  • auth_router.py - Authentication endpoints
  • usuario_router.py - User management

4. Presentation Layer (Frontend)

React application providing user interface. Location: frontend/src/
From frontend/src/router/AppRouter/AppRouter.jsx:
<Routes>
  <Route element={<MainLayout />}>
    {/* Public Routes */}
    <Route path="/" element={<Home />} />
    <Route path="/login" element={<Login />} />
    <Route path="/register" element={<Register />} />
    <Route path="/destinos" element={<DestinosList />} />
    <Route path="/destinos/:id" element={<DestinoDetalle />} />
    <Route path="/rutas" element={<Rutas />} />
    <Route path="/rutas/:id" element={<RutaDetalle />} />
    <Route path="/mapa" element={<MapaPage />} />
    
    {/* Protected Routes - Editor/Admin */}
    <Route
      path="/admin/destinos/crear"
      element={
        <ProtectedRoute allowedRoles={["editor", "administrador"]}>
          <CrearDestino />
        </ProtectedRoute>
      }
    />
    
    {/* Protected Routes - Admin Only */}
    <Route
      path="/admin/usuarios"
      element={
        <ProtectedRoute allowedRoles={["administrador"]}>
          <UsuariosAdmin />
        </ProtectedRoute>
      }
    />
  </Route>
</Routes>
Key Frontend Components:

Map Components

  • MapView - Main map container
  • MapaBase - Leaflet base configuration
  • MapaPOI - Point of Interest markers
  • MapaSidebar - Map controls and filters

UI Components

  • Radix UI primitives (Dialog, Select, etc.)
  • Custom Card, Button, Input components
  • Form components with react-hook-form
  • Tailwind CSS styling

Context Providers

  • AuthContext - User authentication state
  • DestinosContext - Destinations data management

Hooks

  • useAuth - Authentication operations
  • useRutas - Routes data fetching
  • useMapaDestinos - Map data transformation
  • useDestinosContext - Destination CRUD

Configuration Management

Settings are managed through environment variables and configuration files. Settings Class (src/config/settings.py):
class Settings(BaseSettings):
    app_name: str = "FARM Turismo API"
    debug: bool = True
    
    # MongoDB
    mongo_uri: str = None
    mongo_db: str = "turismo_digital_uce"
    
    # Cloudinary
    cloudinary_cloud_name: str | None = None
    cloudinary_api_key: str | None = None
    cloudinary_api_secret: str | None = None
    
    # JWT
    jwt_secret_key: str | None = None
    jwt_algorithm: str = "HS256"
    jwt_expire_minutes: int = 60
    
    class Config:
        env_file = ".env"
        env_file_encoding = "utf-8"
Configuration can be loaded from environment variables, .env file, or local_config.json for local development.

Security Architecture

Authentication Flow

Role-Based Access Control

Permissions:
  • View all public destinations
  • Browse tourist routes
  • View interactive maps
  • Register account
Restrictions:
  • Cannot create or modify content
  • Cannot access admin features

Data Flow Example

Here’s how a complete operation flows through the architecture layers:
1

User Creates Destination

Admin user fills out the create destination form in the React frontend.
2

Frontend Validation

React Hook Form validates required fields before submission.
3

API Request

Frontend sends POST request to /destinos/ with JWT token in Authorization header.
4

Authentication Middleware

FastAPI dependency require_admin verifies JWT and checks admin role.
5

Router Handler

destinos_router.py receives the request and extracts data.
6

Use Case Execution

AgregarDestinoUseCase is instantiated with repository implementation.
7

Entity Creation

Domain entity Destino is created with validation logic.
8

Repository Operation

DestinoRepositoryImpl saves the document to MongoDB.
9

Response

Success response with new destination ID flows back to frontend.
10

UI Update

Frontend redirects to destinations list showing the new entry.

Benefits of This Architecture

Testability

Each layer can be tested independently with mock dependencies

Maintainability

Clear separation of concerns makes code easier to understand and modify

Flexibility

Easy to swap implementations (e.g., change database from MongoDB to PostgreSQL)

Scalability

Layers can be scaled independently based on performance needs

Domain Focus

Business logic remains pure and independent of frameworks

Type Safety

Pydantic models and TypeScript provide compile-time validation

Next Steps

Development Guide

Set up your local environment and start contributing

API Reference

Explore all available endpoints and data models

Frontend Components

Learn about React components and state management

Deployment

Deploy the application to production

Build docs developers (and LLMs) love