Backend and API Gateway built with FastAPI, SQLAlchemy 2 (async), PostgreSQL, and MongoDB (Motor).
| Layer | Technology |
|---|---|
| Framework | FastAPI 0.121+ |
| Language | Python 3.12+ |
| Database | PostgreSQL + asyncpg, MongoDB + Motor |
| ORM | SQLAlchemy 2 (async) |
| Migrations | Alembic |
| Auth | JWT (PyJWT) + Argon2 password hashing |
| Metrics | prometheus-client + psutil |
| Package mgmt | Poetry |
| Linting | Ruff, Bandit, mypy |
| Testing | pytest + pytest-asyncio + httpx |
├── app/
│ ├── main.py # FastAPI app factory + lifespan
│ ├── api/ # Versioned API router
│ ├── core/ # Config, logging, security, middleware, metrics
│ ├── db/ # Database engines, dependencies, exceptions (Postgres + MongoDB)
│ ├── domains/ # Feature modules (auth, health, …)
│ ├── schemas/ # Shared response schemas
│ └── seed/ # Database seed scripts
├── alembic/ # Database migrations
├── tests/ # Test suite (unit, integration, e2e)
├── logs/ # JSON log files (auto-created)
├── scripts/ # Utility scripts
├── alembic.ini # Alembic configuration
├── pyproject.toml # Poetry config, tool settings
├── Makefile # Common commands
└── run.py # Dev entry point
Each sub-module has its own README with detailed documentation:
- app/core/README.md — configuration, logging, security, middleware, metrics
- app/db/README.md — database layer, sessions, exceptions
- app/domains/auth/README.md — authentication, authorization, session management
- alembic/README — migration system and commands
- Python 3.12+
- PostgreSQL (running locally or in a container)
- MongoDB (running locally or in a container)
- Poetry (package manager) — install guide
git clone <repository-url>
cd backend
make install
# or: poetry installCreate a .env file in the project root. All variables have sensible defaults for local development, so a minimal .env can be empty — but you should at least set a proper JWT secret:
# .env
# Environment: development | test | production
ENVIRONMENT=development
# PostgreSQL
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=syncdesk_db
# MongoDB
MONGO_USER=
MONGO_PASSWORD=
MONGO_HOST=localhost
MONGO_PORT=27017
MONGO_DB=syncdesk_db
# JWT (change the secrets in any non-local environment)
ACCESS_TOKEN_SIGNING_KEY=change-me-in-production
REFRESH_TOKEN_SIGNING_KEY=change-me-in-production
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=60
SESSION_EXPIRE_DAYS=180
# CORS (comma-separated origins, or * for all)
CORS_ALLOW_ORIGINS=["*"]
# Project metadata
PROJECT_NAME=SyncDesk API
PROJECT_VERSION=0.1.0Full variable reference is in the core/ docs.
When ENVIRONMENT=development, the app:
- connects to MongoDB on startup,
- and automatically creates the PostgreSQL database and all tables (drops and recreates).
Make sure both PostgreSQL and MongoDB are running:
make devWarning: Postgres auto-setup drops all tables every startup in development. Use only for local development.
# Apply all migrations
make migrate
# Seed initial roles and permissions
make seedSee alembic/README for full migration commands.
# Development (with hot reload)
make dev
# Production
make runThe API will be available at http://127.0.0.1:8000.
- Interactive docs: http://127.0.0.1:8000/docs
- ReDoc: http://127.0.0.1:8000/redoc
- Health check:
GET / - Metrics:
GET /metrics
The seed script populates roles, permissions, and their associations:
make seedDefault seed data:
| Roles | Permissions |
|---|---|
admin |
All user:*, role:*, permission:* permissions |
user |
All session:* permissions (login, refresh, logout) |
# All tests
make test
# E2E tests only
make test-e2eTests run with ENVIRONMENT=test, which targets a separate {POSTGRES_DB}_test database. Coverage is reported to the terminal.
This project includes a complete Docker setup so all developers can run the same environment on any OS.
If you do not have a .env, copy from .env.example and adjust values if needed.
Required database vars for Docker Compose:
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=syncdesk_db
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
MONGO_HOST=localhost
MONGO_PORT=27017
MONGO_DB=syncdesk_dbPOSTGRES_HOST is automatically overridden to db, and MONGO_HOST to mongo, inside the API container.
docker compose up --buildWhat happens automatically:
- PostgreSQL container starts and becomes healthy
- MongoDB container starts and becomes healthy
- API container waits for PostgreSQL readiness
- API container waits for MongoDB readiness
- Alembic runs:
alembic upgrade head - FastAPI starts on
http://localhost:8000
docker compose downTo also remove Postgres and Mongo persisted data:
docker compose down -v# Lint (ruff + bandit)
make lint
# Auto-format
make format
# Type checking
make typecheckPre-commit is configured with Ruff, mypy, and Bandit. Install the hooks once:
poetry run pre-commit installOr run all checks manually (lint + format + typecheck + bandit + tests):
make pre-commit| Command | Description |
|---|---|
make install |
Install all dependencies via Poetry |
make dev |
Run dev server with hot reload |
make run |
Run production server |
make test |
Run full test suite with coverage |
make test-e2e |
Run end-to-end tests only |
make lint |
Run Ruff and Bandit linters |
make format |
Auto-format code with Ruff |
make typecheck |
Run mypy type checking |
make migrate |
Apply all pending Alembic migrations |
make makemigration m="msg" |
Auto-generate a new Alembic migration |
make seed |
Seed roles, permissions, and associations |
make pre-commit |
Run all checks (lint + format + types + tests) |
All domain endpoints are mounted under /api:
| Prefix | Description |
|---|---|
POST /api/auth/register |
User registration |
POST /api/auth/login |
Login (returns tokens) |
POST /api/auth/refresh |
Refresh token rotation |
POST /api/auth/logout |
Revoke session |
GET /api/auth/me |
Current user profile |
/api/users/ |
User management (CRUD) |
/api/roles/ |
Role management (CRUD) |
/api/permissions/ |
Permission management (CRUD) |
GET / |
Health check |
GET /metrics |
Prometheus metrics |
GET /metrics/{prefix} |
Filtered metrics by prefix |
All protected endpoints require a Authorization: Bearer <access_token> header. See the auth docs for full details on the authentication flow.
Structured JSON logs are written to:
logs/app.json— INFO and abovelogs/error.json— ERROR and above- Console — DEBUG and above
Files rotate at 10 MB with 5 backups. See core/ docs for details.
The following security improvements have been identified but are deferred for a future release:
| # | Severity | Issue | Notes |
|---|---|---|---|
| 2 | 🔴 Critical | Hardcoded JWT secret default | config.py uses a placeholder if env vars are missing. Add startup validation before production deployment. |
| 3 | 🟠 High | No rate limiting on login/register | A middleware stub exists but is not yet implemented. Recommend a Redis-backed solution for multi-instance deployments. |
| 11 | 🔵 Low | HS256 symmetric algorithm | Consider RS256/ES256 for microservice architectures where verifying services should not hold the signing secret. |