# UMBRA Backend FastAPI backend for the UMBRA life management application with async SQLAlchemy, PostgreSQL, multi-user RBAC, and comprehensive security. ## Features - **FastAPI** with async/await and Pydantic v2 - **SQLAlchemy 2.0** async engine with `Mapped[]` types - **PostgreSQL 16** via asyncpg - **Alembic** database migrations (001-061) - **Authentication**: Argon2id passwords + signed httpOnly cookies + optional TOTP MFA + passkey (WebAuthn/FIDO2) - **Multi-user RBAC**: admin/standard roles, per-user resource scoping - **Session management**: DB-backed sessions, sliding window expiry, concurrent session cap - **Account security**: Account lockout (10 failures = 30-min lock), CSRF protection, rate limiting - **APScheduler** for background notification dispatch ## Project Structure ``` backend/ ├── alembic/versions/ # 61 database migrations ├── app/ │ ├── models/ # 21 SQLAlchemy 2.0 models │ ├── schemas/ # 14 Pydantic v2 schema modules │ ├── routers/ # 17 API routers │ ├── services/ # Auth, session, passkey, TOTP, audit, recurrence, etc. │ ├── jobs/ # APScheduler notification dispatch │ ├── config.py # Pydantic Settings (env vars) │ ├── database.py # Async engine + session factory │ └── main.py # FastAPI app + CSRF middleware ├── requirements.txt ├── Dockerfile ├── alembic.ini └── start.sh ``` ## Setup ### 1. Install Dependencies ```bash pip install -r requirements.txt ``` ### 2. Configure Environment Copy `.env.example` to `.env` and configure: ```bash DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/umbra SECRET_KEY=generate-a-strong-random-key ENVIRONMENT=production # WebAuthn / Passkeys (required for passkey auth) WEBAUTHN_RP_ID=your-domain.com WEBAUTHN_RP_NAME=UMBRA WEBAUTHN_ORIGIN=https://your-domain.com ``` ### 3. Run Migrations ```bash alembic upgrade head ``` ### 4. Start Server ```bash uvicorn app.main:app --host 0.0.0.0 --port 8000 ``` ## API Routes All routes require authentication (signed session cookie) except `/api/auth/*` and `/health`. | Prefix | Description | |--------|-------------| | `/api/auth` | Login, logout, register, setup, status, password, TOTP, passkeys | | `/api/admin` | User management, system config, audit logs (admin only) | | `/api/todos` | Task management with categories and priorities | | `/api/events` | Calendar events with recurrence support | | `/api/event-invitations` | Event invitation RSVP and management | | `/api/event-templates` | Reusable event templates | | `/api/calendars` | Calendar CRUD | | `/api/shared-calendars` | Calendar sharing with permission levels | | `/api/reminders` | Reminder management with snooze | | `/api/projects` | Projects with tasks, comments, and collaboration | | `/api/people` | Contact management | | `/api/locations` | Location management | | `/api/connections` | User connections (friend requests) | | `/api/notifications` | In-app notification centre | | `/api/settings` | User preferences and ntfy configuration | | `/api/dashboard` | Aggregated dashboard data | | `/api/weather` | Weather widget data | ## Authentication UMBRA supports three authentication methods: 1. **Password** (Argon2id) - Primary login method 2. **TOTP MFA** - Optional second factor via authenticator apps 3. **Passkeys** (WebAuthn/FIDO2) - Optional passwordless login via biometrics, security keys, or password managers Passkey login bypasses TOTP (a passkey is inherently two-factor: possession + biometric/PIN). ## Security - CSRF protection via `X-Requested-With` header middleware - All Pydantic schemas use `extra="forbid"` (mass-assignment prevention) - Nginx rate limiting on auth, registration, and admin endpoints - DB-backed account lockout after 10 failed attempts - Timing-safe dummy hash for non-existent users (prevents enumeration) - SSRF validation on ntfy webhook URLs - Naive datetimes throughout (Docker runs UTC) ## Docker The backend runs as non-root `appuser` in `python:3.12-slim`: ```bash docker build -t umbra-backend . docker run -p 8000:8000 --env-file .env umbra-backend ``` In production, use Docker Compose (see root `docker-compose.yaml`).