UMBRA/CLAUDE.md

5.0 KiB

CLAUDE.md - UMBRA

Hard Rules

  • Naive datetimes only. The DB uses TIMESTAMP WITHOUT TIME ZONE. Never send timezone-aware strings (no Z suffix, no .toISOString()). Use local datetime formatting helpers instead.
  • Eager load relationships in async SQLAlchemy. Any response_model that includes a relationship (e.g. ProjectResponse.tasks) must use selectinload() when querying. Lazy loading raises MissingGreenlet in async context.
  • Never shadow SQLAlchemy names. Model columns must not be named relationship, column, metadata, or other SQLAlchemy reserved names. The person.py model aliases the import as sa_relationship for this reason.
  • Frontend date inputs require exact formats. <input type="date"> needs YYYY-MM-DD, <input type="datetime-local"> needs YYYY-MM-DDThh:mm. Backend may return 2026-02-15T00:00:00 which must be sliced/converted before binding.
  • All API routes are prefixed with /api. Frontend axios base URL is /api. Nginx proxies /api/ to backend:8000. Never duplicate the prefix.

Tech Stack

Backend

  • Python 3.12 (slim Docker image - no curl, use urllib for healthchecks)
  • FastAPI with async lifespan, Pydantic v2 (model_dump(), ConfigDict(from_attributes=True))
  • SQLAlchemy 2.0 async with Mapped[] type hints, mapped_column(), async_sessionmaker
  • PostgreSQL 16 (Alpine) via asyncpg
  • Alembic for migrations
  • Auth: PIN-based with bcrypt + itsdangerous signed cookies (not JWT)

Frontend

  • React 18 + TypeScript + Vite 6
  • TanStack Query v5 for server state (useQuery, useMutation, invalidateQueries)
  • FullCalendar 6 (dayGrid, timeGrid, interaction plugins)
  • Tailwind CSS 3 with custom dark theme + accent color CSS variables
  • Sonner for toast notifications
  • Lucide React for icons
  • Custom shadcn/ui-style components in frontend/src/components/ui/

Infrastructure

  • Docker Compose - 3 services: db, backend, frontend
  • Nginx (Alpine) serves frontend SPA, proxies /api/ to backend
  • Frontend served on port 80, backend on port 8000
  • progress.md - Project tracker, milestone status, fix history, outstanding items

Project Structure

backend/app/
  main.py          # FastAPI app, router registration, health endpoint
  config.py        # Pydantic BaseSettings (DATABASE_URL, SECRET_KEY)
  database.py      # Async engine, session factory, get_db dependency
  models/          # SQLAlchemy 2.0 models (Mapped[] style)
  schemas/         # Pydantic v2 request/response schemas
  routers/         # One router per feature (auth, todos, events, etc.)

frontend/src/
  App.tsx           # Routes + ProtectedRoute wrapper
  lib/api.ts        # Axios instance + getErrorMessage helper
  hooks/            # useAuth, useSettings, useTheme
  types/index.ts    # TypeScript interfaces matching backend schemas
  components/
    ui/             # 12 base components (Button, Dialog, Input, etc.)
    layout/         # AppLayout + Sidebar
    auth/           # LockScreen (PIN setup/login)
    dashboard/      # DashboardPage + widgets
    calendar/       # CalendarPage + EventForm
    todos/          # TodosPage + TodoList + TodoItem + TodoForm
    reminders/      # RemindersPage + ReminderList + ReminderForm
    projects/       # ProjectsPage + ProjectCard + ProjectDetail + forms
    people/         # PeoplePage + PersonCard + PersonForm
    locations/      # LocationsPage + LocationCard + LocationForm
    settings/       # SettingsPage (accent color, PIN change)

Essential Commands

# Build and run all services
docker-compose up --build

# Rebuild single service after changes
docker-compose up --build backend
docker-compose up --build frontend

# View logs
docker-compose logs -f
docker-compose logs -f backend

# Reset database (destroys all data)
docker-compose down -v && docker-compose up --build

# Stop everything
docker-compose down

API Routes

All routes require auth (signed cookie) except /api/auth/* and /health.

Prefix Resource
/api/auth PIN setup/login/logout/status
/api/todos Todos CRUD + toggle
/api/events Calendar events CRUD
/api/reminders Reminders CRUD + dismiss
/api/projects Projects + nested tasks CRUD
/api/people People CRUD
/api/locations Locations CRUD
/api/settings Settings + PIN change
/api/dashboard Dashboard aggregation
/api/upcoming Unified upcoming items

Stop Conditions

  • Do not add timezone info to datetime strings sent to the backend
  • Do not use datetime.utcnow() - use datetime.now(timezone.utc) instead (deprecated in 3.12)
  • Do not return relationships from async endpoints without selectinload()
  • Do not use curl in backend Docker healthchecks (not available in python:slim)
  • Do not use git push --force or destructive git operations without explicit approval