Kyle Pope d8bdae8ec3 Implement multi-user RBAC: database, auth, routing, admin API (Phases 1-6)
Phase 1: Add role, mfa_enforce_pending, must_change_password to users table.
Create system_config (singleton) and audit_log tables. Migration 026.

Phase 2: Add user_id FK to all 8 data tables (todos, reminders, projects,
calendars, people, locations, event_templates, ntfy_sent) with 4-step
nullable→backfill→FK→NOT NULL pattern. Migrations 027-034.

Phase 3: Harden auth schemas (extra="forbid" on RegisterRequest), add
MFA enforcement token serializer with distinct salt, rewrite auth router
with require_role() factory and registration endpoint.

Phase 4: Scope all 12 routers by user_id, fix dependency type bugs,
bound weather cache (SEC-15), multi-user ntfy dispatch.

Phase 5: Create admin router (14 endpoints), admin schemas, audit
service, rate limiting in nginx. SEC-08 CSRF via X-Requested-With.

Phase 6: Update frontend types, useAuth hook (role/isAdmin/register),
App.tsx (AdminRoute guard), Sidebar (admin link), api.ts (XHR header).

Security findings addressed: SEC-01, SEC-02, SEC-03, SEC-04, SEC-05,
SEC-06, SEC-07, SEC-08, SEC-12, SEC-13, SEC-15.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 19:06:25 +08:00
..
2026-02-15 16:13:41 +08:00
2026-02-15 16:13:41 +08:00
2026-02-15 16:13:41 +08:00

UMBRA Backend

A complete FastAPI backend for the UMBRA application with async SQLAlchemy, PostgreSQL, authentication, and comprehensive CRUD operations.

Features

  • FastAPI with async/await support
  • SQLAlchemy 2.0 with async engine
  • PostgreSQL with asyncpg driver
  • Alembic for database migrations
  • bcrypt for password hashing
  • itsdangerous for session management
  • PIN-based authentication with secure session cookies
  • Full CRUD operations for all entities
  • Dashboard with aggregated data
  • CORS enabled for frontend integration

Project Structure

backend/
├── alembic/                 # Database migrations
│   ├── versions/           # Migration files
│   ├── env.py             # Alembic environment
│   └── script.py.mako     # Migration template
├── app/
│   ├── models/            # SQLAlchemy models
│   ├── schemas/           # Pydantic schemas
│   ├── routers/           # API route handlers
│   ├── config.py          # Configuration
│   ├── database.py        # Database setup
│   └── main.py            # FastAPI application
├── requirements.txt       # Python dependencies
├── Dockerfile            # Docker configuration
├── alembic.ini          # Alembic configuration
└── start.sh             # Startup script

Setup

1. Install Dependencies

cd backend
pip install -r requirements.txt

2. Configure Environment

Create a .env file:

DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra
SECRET_KEY=your-secret-key-change-in-production

3. Create Database

createdb umbra

4. Run Migrations

alembic upgrade head

5. Start Server

# Using the start script
chmod +x start.sh
./start.sh

# Or directly with uvicorn
uvicorn app.main:app --reload

The API will be available at http://localhost:8000

API Documentation

Interactive API documentation is available at:

API Endpoints

Authentication

  • POST /api/auth/setup - Initial PIN setup
  • POST /api/auth/login - Login with PIN
  • POST /api/auth/logout - Logout
  • GET /api/auth/status - Check auth status

Todos

  • GET /api/todos - List todos (with filters)
  • POST /api/todos - Create todo
  • GET /api/todos/{id} - Get todo
  • PUT /api/todos/{id} - Update todo
  • DELETE /api/todos/{id} - Delete todo
  • PATCH /api/todos/{id}/toggle - Toggle completion

Calendar Events

  • GET /api/events - List events (with date range)
  • POST /api/events - Create event
  • GET /api/events/{id} - Get event
  • PUT /api/events/{id} - Update event
  • DELETE /api/events/{id} - Delete event

Reminders

  • GET /api/reminders - List reminders (with filters)
  • POST /api/reminders - Create reminder
  • GET /api/reminders/{id} - Get reminder
  • PUT /api/reminders/{id} - Update reminder
  • DELETE /api/reminders/{id} - Delete reminder
  • PATCH /api/reminders/{id}/dismiss - Dismiss reminder

Projects

  • GET /api/projects - List projects
  • POST /api/projects - Create project
  • GET /api/projects/{id} - Get project
  • PUT /api/projects/{id} - Update project
  • DELETE /api/projects/{id} - Delete project
  • GET /api/projects/{id}/tasks - List project tasks
  • POST /api/projects/{id}/tasks - Create project task
  • PUT /api/projects/{id}/tasks/{task_id} - Update task
  • DELETE /api/projects/{id}/tasks/{task_id} - Delete task

People

  • GET /api/people - List people (with search)
  • POST /api/people - Create person
  • GET /api/people/{id} - Get person
  • PUT /api/people/{id} - Update person
  • DELETE /api/people/{id} - Delete person

Locations

  • GET /api/locations - List locations (with category filter)
  • POST /api/locations - Create location
  • GET /api/locations/{id} - Get location
  • PUT /api/locations/{id} - Update location
  • DELETE /api/locations/{id} - Delete location

Settings

  • GET /api/settings - Get settings
  • PUT /api/settings - Update settings
  • PUT /api/settings/pin - Change PIN

Dashboard

  • GET /api/dashboard - Get dashboard data
  • GET /api/upcoming?days=7 - Get upcoming items

Database Schema

The application uses the following tables:

  • settings - Application settings and PIN
  • todos - Task items
  • calendar_events - Calendar events
  • reminders - Reminders
  • projects - Projects
  • project_tasks - Tasks within projects
  • people - Contacts/people
  • locations - Physical locations

Docker

Build and run with Docker:

docker build -t umbra-backend .
docker run -p 8000:8000 -e DATABASE_URL=... -e SECRET_KEY=... umbra-backend

Development

Create New Migration

alembic revision --autogenerate -m "Description of changes"

Apply Migrations

alembic upgrade head

Rollback Migration

alembic downgrade -1

Security Notes

  • Change SECRET_KEY in production
  • Use strong PINs (minimum 4 digits recommended)
  • Session cookies are httpOnly and last 30 days
  • All API endpoints (except auth) require authentication
  • PINs are hashed with bcrypt before storage