- Add logout button to sidebar with destructive hover styling - Fix case-sensitive todo category filter with .toLowerCase() - Widen dialog popups from max-w-lg to max-w-xl with mobile margin - Update CLAUDE.md with commit-and-push instruction - Update progress.md: all CRUD tests verified, all outstanding items resolved Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.1 KiB
5.1 KiB
CLAUDE.md - UMBRA
IMPORTANT:
- When you've completed an edit, commit with details and push to main
Hard Rules
- Naive datetimes only. The DB uses
TIMESTAMP WITHOUT TIME ZONE. Never send timezone-aware strings (noZsuffix, no.toISOString()). Use local datetime formatting helpers instead. - Eager load relationships in async SQLAlchemy. Any
response_modelthat includes a relationship (e.g.ProjectResponse.tasks) must useselectinload()when querying. Lazy loading raisesMissingGreenletin async context. - Never shadow SQLAlchemy names. Model columns must not be named
relationship,column,metadata, or other SQLAlchemy reserved names. Theperson.pymodel aliases the import assa_relationshipfor this reason. - Frontend date inputs require exact formats.
<input type="date">needsYYYY-MM-DD,<input type="datetime-local">needsYYYY-MM-DDThh:mm. Backend may return2026-02-15T00:00:00which 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
urllibfor 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
Authority Links
- 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()- usedatetime.now(timezone.utc)instead (deprecated in 3.12) - Do not return relationships from async endpoints without
selectinload() - Do not use
curlin backend Docker healthchecks (not available in python:slim) - Do not use
git push --forceor destructive git operations without explicit approval