Rappi2 is an asynchronous FastAPI application structured as a modular monolith. Rather than splitting into microservices, the codebase divides responsibility across well-defined layers — routers, models, schemas, services, middleware, and core infrastructure — while keeping a single deployable unit. Persistence is split between PostgreSQL (transactional records) and MongoDB (high-volume, geospatial, and document data), with every layer using Python’sDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/JorLOrT/rappi2/llms.txt
Use this file to discover all available pages before exploring further.
async/await throughout.
Application layers
Each layer has a single responsibility and communicates with adjacent layers only through defined interfaces.| Layer | Directory | Responsibility |
|---|---|---|
| Routers | api/ | HTTP endpoints, request validation, dependency injection, response serialization |
| SQLAlchemy models | models/ | PostgreSQL table definitions and ORM relationships |
| Pydantic schemas | schemas/ | Request/response contracts and data validation |
| Business services | services/ | Domain logic, external integrations, MongoDB operations |
| Middleware | middleware/ | Cross-cutting concerns (audit logging, CORS) |
| Core infrastructure | core/ | Database sessions, MongoDB client, security utilities, application settings |
PostgreSQL layer
Transactional tables managed via SQLAlchemy async sessions. Covers orders, users, payments, assignments, and routes.
MongoDB layer
Document collections managed via Motor. Covers GPS pings, geofences, audit logs, evidence files (GridFS), and notifications.
Hybrid persistence
Rappi2 deliberately uses two databases, each chosen for the kind of data it stores best. PostgreSQL holds the relational, transactional core:usuarios,roles,permisos,tokens— identity and accessclientes,clientes_direcciones— customer recordsordenes,pagos,facturas— order lifecycle and billingconductores,vehiculos,asignaciones— fleet and dispatchrutas_planificadas,paradas— planned routesincidencias— incidents tied to assignments
gps_tracking— continuous GPS pings from drivers, with a2dsphereindex on thelocationfield (GeoJSONPoint)geocercas— polygon geofences with a2dsphereindex ongeometryfor$geoIntersectsqueriesauditoria— one document per HTTP request, with a TTL index that expires records after 90 daysevidencias— metadata records linked to incident reports; binary files stored in GridFS (evidencias_filesbucket)notificaciones— per-recipient notification documents with read/unread state
Async everywhere
Every I/O operation in Rappi2 is non-blocking:- FastAPI runs on an ASGI server (Uvicorn/Hypercorn) and handles all requests as coroutines.
- SQLAlchemy async (
AsyncSessionfromsqlalchemy.ext.asyncio) issues PostgreSQL queries without blocking the event loop. - Motor (
AsyncIOMotorDatabase,AsyncIOMotorGridFSBucket) provides fully async MongoDB access, including streaming GridFS uploads and downloads.
lifespan) opens the MongoDB connection pool at startup, ensures all indexes are created, and closes the pool cleanly on shutdown.
Middleware
Two middleware layers wrap every request: CORSMiddleware (from Starlette) enforces allowed origins, methods, and headers based onsettings.CORS_ORIGINS.
AuditMiddleware intercepts every request not on the exclusion list (/, /docs, /redoc, /openapi.json, /favicon.ico) and writes a document to the auditoria MongoDB collection. It captures:
usuario_id— extracted from theAuthorization: BearerJWT if presentruta— the request pathmetodo— HTTP methodip— client IP, respectingX-Forwarded-Forstatus_code— from the downstream responsepayload_hash— SHA-256 of the first 1 KB of the request body for mutating methods
Audit logging can be disabled by setting
AUDIT_ENABLED=false in the environment. When disabled, the middleware is a no-op pass-through.