Kyle Pope ed98924716 Action remaining QA suggestions + performance optimizations
S-02: Extract extract_credential_raw_id() helper in services/passkey.py
  — replaces 2 inline rawId parsing blocks in passkeys.py
S-03: Add PasskeyLoginResponse type, use in useAuth passkeyLoginMutation
S-04: Add Cancel button to disable-passwordless dialog
W-03: Invalidate auth queries on disable ceremony error/cancel

Perf-2: Session cap uses ID-only query + bulk UPDATE instead of loading
  full ORM objects and flipping booleans individually
Perf-3: Remove passkey_count from /auth/status hot path (polled every
  15s). Use EXISTS for has_passkeys boolean. Count derived from passkeys
  list query in PasskeySection (passkeys.length).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:34:00 +08:00
..
2026-02-15 16:13:41 +08:00
2026-02-15 16:13:41 +08:00

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

pip install -r requirements.txt

2. Configure Environment

Copy .env.example to .env and configure:

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

alembic upgrade head

4. Start Server

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:

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).