Architecture overview¶
Runtime entrypoint¶
xoloapi/server.py builds the FastAPI application, connects MongoDB and Redis in the lifespan hooks, and mounts routers under /api/v4.
Two architectural styles¶
1. Classic layered modules¶
Used mainly for:
- accounts
- users
- scopes
- licenses
- older ACL-adjacent flows
Flow:
controller -> service -> repository -> db
Responsibilities:
- controller: HTTP routing, validation, logging, dependency injection
- service: business rules and orchestration
- repository: persistence and query logic
- db: MongoDB and Redis client access
Common examples:
accountsusersscopeslicensesapikeysaclrbac
2. Vertical subsystems¶
Used for:
xoloapi/abac/xoloapi/ngac/
These packages keep their own controller/application/domain/infrastructure structure or local service composition so subsystem logic stays together.
admin_ui is a small exception: it is mostly controller- and template-driven rather than a full domain package.
For a module-by-module view of the feature packages under xoloapi/, see Project structure.
Error handling convention¶
Services and repositories use option.Result / Option instead of raising normal control-flow exceptions.
Typical pattern:
if result.is_err:
raise result.unwrap_err().to_http_exception()
return result.unwrap()
Dependency injection¶
FastAPI dependency factories create services at request time. This keeps wiring near the HTTP layer and avoids unnecessary global state.
The notable exception is xoloapi/policies/, where module-level singletons are deliberate because that subsystem is in memory.
Logging¶
Controllers and services log structured payloads built through:
xoloapi.log.format.build_log_payload()
The common pattern is:
infoon successerroron failure- include action names, identifiers, and elapsed time
For the full log-line shape and field reference, see Logging.
Configuration model¶
Configuration is import-time global state defined in xoloapi/config/__init__.py.
The active env file is selected with:
XOLO_ENV_FILE=.env.dev
Because settings are read at import time, environment selection must happen before importing the app.