Skip to Content
ContributeBackendArchitecture

Backend Architecture

A FastAPI application backed by PostgreSQL (SQLAlchemy ORM) and Celery workers on a Redis broker, with authentication via email/password, Google OAuth, and GitHub OAuth. For the directory layout, see the Backend Overview.

Layering

Requests flow through three layers:

  • Routers (app/routers/) — FastAPI route handlers, grouped by resource.
  • Services (app/services/) and CRUD (app/crud.py) — business logic and database access.
  • Models (app/models/) and schemas (app/schemas/) — SQLAlchemy ORM models and Pydantic request/response types.

app/main.py creates the app, registers routers, and wires middleware (CORS, authentication) and exception handlers. FastAPI dependency injection supplies the database session, current user, and feature gates to handlers.

Request flow

  1. Authentication middleware validates the request.
  2. Dependencies resolve (database session, current user, tenant scope).
  3. Pydantic validates the request body.
  4. The handler runs service or CRUD logic.
  5. A Pydantic-validated response is returned.

Tenant isolation is applied automatically per request rather than threaded through call arguments — organization/user/project scope is stamped onto new rows and added as a WHERE filter to queries, backed by PostgreSQL row-level security. See Multi-tenancy.

Logging

Backend startup calls set_logger() from rhesis.backend.logging.logging_config. The logger chooses handlers from runtime configuration:

Runtime conditionOutput
JSON_LOGGER_ENABLED=trueJSON logs on stdout (severity, module, message) — never colored
Interactive TTY (and JSON off)Colored plain-text logs on stdout
Non-TTY stdout (and JSON off)Plain-text logs on stdout
DEV_MODE=true (any of the above)Additionally writes a timestamped plain-text file under LOG_DIR
Celery worker (node name -n main@… / architect@…)Adds worker_role to JSON; [ROLE] - prefix in plain/color

DEV_MODE=true enables Uvicorn hot reload and --log-level debug in start.sh. The Celery worker uses two separate log-level variables instead of DEV_MODE: LOG_LEVEL for application logs and CELERY_WORKER_LOGLEVEL for Celery’s own task-lifecycle messages (defaults to LOG_LEVEL, overridable independently). Set DEV_MODE=true in apps/backend/.env when running via ./rh dev; leave it unset or false everywhere else (Docker Compose local, cloud deployments).

All configured handlers wrap their formatter in RedactingFormatter, which scrubs bearer tokens, JWTs, API keys, database URLs, cookies, passwords, and private keys from final log output.