Backend Overview
Summary
Poolia.BACK is a FastAPI-based backend for a pool management platform. It exposes REST endpoints for authentication, users, pools, pool readings, visits, technician invitations, photo uploads, and a role-aware messaging system. Data is stored in MongoDB and modeled with Beanie documents; file uploads are stored in Azure Blob Storage.
The codebase follows a conventional layered structure:
- API routers define HTTP endpoints and request/response contracts.
- Services contain business rules and cross-entity workflows.
- Repositories encapsulate persistence access for Beanie documents.
- Models define MongoDB documents.
- Schemas define request and response payloads.
- Core contains configuration, database bootstrapping, and security helpers.
Stack
- Framework: FastAPI
- ASGI server: Uvicorn
- Database: MongoDB
- ODM: Beanie
- Validation / settings: Pydantic v2 + pydantic-settings
- Authentication: JWT with
python-jose - Password hashing: Passlib + bcrypt, with SHA-256 prehashing before bcrypt
- File storage: Azure Blob Storage
- Local orchestration: Docker Compose
Runtime architecture
Application entry point
The application starts in app.main.
Main responsibilities:
- instantiate the FastAPI app
- configure permissive CORS
- register all routers
- initialize the database on startup
- expose a basic
/healthendpoint
Startup flow
- FastAPI application is created with
settings.app_name. - CORS middleware is added with
allow_origins=["*"],allow_methods=["*"], andallow_headers=["*"]. - Routers are mounted under their prefixes.
- On startup,
init_db()initializes Beanie against MongoDB. - The service begins accepting requests.
Project structure
backend/
app/
api/
dependencies/
routers/
core/
config.py
db.py
security.py
models/
repositories/
schemas/
scripts/
services/
main.py
requirements.txt
Configuration
The backend uses a Settings class derived from BaseSettings and reads values from environment variables or .env.
Current primary settings:
mongo_urimongo_dbapp_nameblob_service_connection_stringblob_service_container_name
This configuration is intentionally small and focused on infrastructure and naming.
Persistence model
MongoDB is accessed through Motor and initialized through Beanie. The application registers the following document models during startup:
UserPoolPoolValuesVisitInvitePhotoAlertConfigMessageThreadMessage
This means the backend stores both operational pool data and communication/media data in the same MongoDB database, while binary file content lives in Azure Blob Storage.
Security model
Authentication
Authentication is token-based:
/auth/registercreates a user and returns a bearer token/auth/loginvalidates credentials and returns a bearer token- protected routes use
OAuth2PasswordBearer(tokenUrl="auth/login") - token decoding resolves the current user by the JWT
subclaim
Password handling
Passwords are not hashed directly with bcrypt. Instead, the code first computes a SHA-256 digest and then hashes that digest with bcrypt. Verification applies the same prehashing strategy before comparison.
Authorization
Authorization is currently implemented selectively:
- messaging routes require an authenticated user
GET /users/meandPOST /users/me/change-passwordrequire an authenticated user- the messaging service enforces role-aware access to pools (
admin,owner,technician)
A large portion of CRUD endpoints for users, pools, visits, invites, and pool values is currently exposed without authentication guards at the router layer. That is important to document because it reflects the present implementation, not an aspirational design.
Domain areas
Users and auth
Users have a role (admin, owner, technician) and a lifecycle status (active, blocked, pending, deleted). Auth is JWT-based and login updates the user's last login timestamp.
Pools
Pools are the central business entity. A pool belongs to one owner, may have multiple assigned technicians, has a geographic location, and can optionally store physical attributes such as volume and depth.
Pool values and visits
Water quality readings live in PoolValues. Visits track technician activity against a pool and may reference one pool-values record. There is also a convenience workflow that creates both a visit and a pool-values snapshot together.
Alert configuration
Each pool can have threshold configuration for pH, chlorine, and temperature. If no configuration exists, the service creates a default one on demand.
Invites
Owners can invite technicians to pools. Invites carry a status (pending, accepted, declined) and default expiration logic.
Photos
Photos may be attached to users, visits, pools, threads, or individual messages. The metadata is stored in MongoDB; the file object itself is uploaded to Azure Blob Storage.
Messaging
The messaging subsystem is the most structured role-aware area in the project. It models discussion threads per pool, supports messages of type question and answer, tracks cached last-message data on the thread, and allows attaching photos to individual messages.
Layering and responsibilities
Routers
Routers are intentionally thin. They mainly:
- receive validated input
- inject dependencies such as
current_user - delegate to services
- declare response models and status codes
Services
Services implement the real business rules, such as:
- owner / technician validation for pool assignment
- preventing duplicate pending invites
- pairing a visit with a water-reading snapshot
- role-based access checks for messaging
- photo upload orchestration and metadata persistence
- default alert-config creation
Repositories
Repositories isolate persistence calls so that services do not directly encode every Beanie query. This keeps services focused on validation and orchestration.
Notable implementation characteristics
Positive patterns
- Clear separation between routers, services, and repositories
- Pydantic aliases are used consistently for API-facing camelCase fields
- Messaging includes meaningful authorization checks and thread cache updates
- Azure Blob access was moved toward lazy initialization in services, which is friendlier for scripts and documentation generation
- Generated documentation scripts were added under
app/scripts, which keeps automated documentation close to the backend codebase
Current limitations and caveats
- CORS is fully open
- Many non-messaging routes are not yet protected by authentication dependencies
- Error messages mix English and Spanish
- Some endpoint naming uses both
snake_caseandcamelCasepath parameters (invite_idvsinviteId,pool_idvspoolId) - The
logoutendpoint is currently only a placeholder response and does not revoke tokens - Configuration is small and infrastructure-focused, but secrets still need proper environment management outside development
Local development
The repository includes a Docker Compose setup with:
mongo:7exposed on local port27018- the FastAPI application exposed on port
8000 - a bind mount of
./backendinto/app - Uvicorn running with
--reload
This makes the project easy to run locally and aligns well with iterative API development.
Documentation strategy
The backend now supports automatic documentation artifact generation. The codebase already includes scripts to export:
- OpenAPI JSON
- OpenAPI Markdown
- models reference
- router map
- services map
- settings reference
Those artifacts can be published into the separate Poolia.DOCS repository, while the manual overview, API, and code-reference pages remain human-written entry points.
Recommended reading order
For someone new to the project, the best path is:
- Read this overview
- Read the API page for external behavior
- Read the code reference page for internal structure
- Use generated docs for precise technical lookup