UMBRA/progress.md
Kyle Pope cea1c36d92 Fix logout, category filter, dialog width, and mark all tests complete
- 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>
2026-02-15 20:46:18 +08:00

12 KiB

UMBRA - Project Progress

Overview

Personal life administration web app with dark theme, accent color customization, and Docker deployment.

Stack: React + TypeScript | FastAPI + SQLAlchemy | PostgreSQL | Docker Compose


Milestone Tracker

Phase 1: Scaffolding & Infrastructure

  • docker-compose.yaml - 3-service architecture (db, backend, frontend)
  • .env / .env.example - Environment configuration
  • .gitignore - Root gitignore
  • Backend: FastAPI app skeleton (app/main.py, config.py, database.py)
  • Backend: requirements.txt with all Python dependencies
  • Backend: Alembic migration setup (alembic.ini, env.py, initial migration)
  • Backend: start.sh startup script
  • Backend: Dockerfile - Python 3.12-slim
  • Frontend: Vite + React scaffold (package.json, vite.config.ts, tsconfig.json)
  • Frontend: Tailwind CSS + PostCSS configuration
  • Frontend: index.html entry point
  • Frontend: nginx.conf - SPA serving + API proxy
  • Frontend: Dockerfile - Multi-stage node build + nginx serve
  • Verify docker-compose up --build boots all services

Phase 2: Auth & Layout

  • Backend: Settings model + schema
  • Backend: Auth router (PIN setup, login, logout, status with bcrypt + itsdangerous)
  • Frontend: LockScreen.tsx - PIN setup/login UI
  • Frontend: useAuth.ts hook (TanStack Query)
  • Frontend: AppLayout.tsx + Sidebar.tsx - Main layout with navigation
  • Frontend: Accent color theming system (useTheme.ts, CSS custom properties)
  • Frontend: 12 shadcn/ui components (button, card, input, dialog, select, badge, etc.)

Phase 3: Core Features

  • Backend: Todo model, schema, router (CRUD + toggle + filters)
  • Frontend: TodosPage, TodoList, TodoItem, TodoForm
  • Backend: Calendar Event model, schema, router (CRUD + date range filter)
  • Frontend: CalendarPage (FullCalendar integration), EventForm
  • Frontend: FullCalendar dark theme CSS overrides in index.css
  • Backend: Reminder model, schema, router (CRUD + dismiss)
  • Frontend: RemindersPage, ReminderList, ReminderForm

Phase 4: Project Management

  • Backend: Project model with tasks relationship + cascade delete
  • Backend: ProjectTask model, schema, router (nested CRUD under projects)
  • Frontend: ProjectsPage, ProjectCard, ProjectDetail, ProjectForm, TaskForm

Phase 5: People & Locations

  • Backend: Person model, schema, router (CRUD + search)
  • Frontend: PeoplePage, PersonCard, PersonForm
  • Backend: Location model, schema, router (CRUD + category filter)
  • Frontend: LocationsPage, LocationCard, LocationForm

Phase 6: Dashboard & Upcoming

  • Backend: Dashboard aggregation endpoint (stats, events, todos, reminders)
  • Backend: Upcoming endpoint (unified items sorted by date)
  • Frontend: DashboardPage with all widgets + upcoming integration
  • Frontend: StatsWidget (projects, people, locations counts)
  • Frontend: UpcomingWidget (unified timeline with type icons)
  • Frontend: TodoWidget (upcoming todos with priority badges)
  • Frontend: CalendarWidget (today's events with color indicators)
  • Frontend: Active reminders section in dashboard

Phase 7: Settings & Polish

  • Backend: Settings router (get/update settings, change PIN)
  • Frontend: SettingsPage (accent color picker, upcoming range, PIN change)
  • Integration fixes: All frontend API paths match backend routes
  • Integration fixes: HTTP methods (PUT for updates, PATCH for toggle/dismiss)
  • Integration fixes: Type definitions match backend response schemas
  • Integration testing (end-to-end CRUD verification) <-- POST-BUILD
  • Final styling pass (responsive sidebar, empty states, loading skeletons)

Integration Fixes Applied

These were caught during review and fixed:

Issue Fix
Settings field upcoming_days_range Renamed to upcoming_days
CalendarEvent fields start/end Renamed to start_datetime/end_datetime
Reminder field dismissed Renamed to is_dismissed, added is_active
Project status values Changed from active/on_hold to not_started/in_progress/completed
Calendar API path /calendar/events Fixed to /events
All update forms using api.patch Fixed to api.put (backend uses PUT)
Todo toggle using generic PATCH Fixed to api.patch('/todos/{id}/toggle')
Reminder dismiss using generic PATCH Fixed to api.patch('/reminders/{id}/dismiss')
Settings update using PATCH Fixed to api.put
PIN change path /auth/change-pin Fixed to /settings/pin
Dashboard data shape mismatch Aligned TodoWidget, CalendarWidget with actual API response
Missing UpcomingWidget in dashboard Added with /api/upcoming fetch

Post-Build Fixes Applied

These were found during first Docker build and integration testing:

Issue Fix
Person.relationship column shadowed SQLAlchemy's relationship() function Aliased import to sa_relationship in person.py
Missing backend/app/__init__.py Created empty __init__.py for Python package recognition
Backend port 8000 not exposed in docker-compose.yaml Added ports, healthcheck, and condition: service_healthy
get_db() redundant session.close() inside async with Removed finally: await session.close()
datetime.utcnow() deprecated in Python 3.12 Replaced with datetime.now(timezone.utc) in todos.py
Calendar date selection wiped start/end fields Added formatInitialDate() to convert date-only to datetime-local format
Dashboard "today's events" used server UTC time Added client_date query param so frontend sends its local date
Calendar drag-and-drop didn't persist Added eventDrop handler with backend PUT call
Timed event drag-and-drop sent timezone-aware datetimes to naive DB column Used toLocalDatetime() helper instead of .toISOString()
All-day event dates empty when editing (datetime vs date format mismatch) Added formatForInput() to normalize values for date vs datetime-local inputs
Project create/update MissingGreenlet error (lazy load in async context) Re-fetch with selectinload(Project.tasks) after commit in projects.py
Generic error toasts gave no useful information Added getErrorMessage() helper to api.ts, updated all 8 form components
Sidebar not responsive on mobile Split into desktop sidebar + mobile overlay with hamburger menu in AppLayout
Plain "Loading..." text on all pages Created Skeleton, ListSkeleton, GridSkeleton, DashboardSkeleton components
Basic empty states with no visual cue Created EmptyState component with icon, message, and action button across all pages
No logout button Added logout button to sidebar footer with LogOut icon and destructive hover style
Todo category filter was case sensitive Changed to case-insensitive comparison with .toLowerCase()
Dialog/popup forms too narrow and cramped Widened DialogContent from max-w-lg to max-w-xl with mobile margin

Outstanding Items (Resume Here If Halted)

Critical (blocks deployment):

  1. Docker build verification - DONE: All 3 services boot successfully
  2. npm install verification - DONE: Frontend packages install correctly

Important (blocks functionality):

  1. Alembic migration test - DONE: Tables create correctly on first boot
  2. Auth flow test - DONE: PIN setup works, PIN change works, session persistence works, logout added
  3. End-to-end CRUD test - DONE: All features verified — Calendar, Projects, Todos (create/edit/filter/search), People (CRUD + search), Locations (CRUD + filter), Reminders (CRUD + dismiss), Settings (accent color + PIN)

Nice to have (polish):

  1. Responsive sidebar - DONE: Mobile hamburger menu with overlay, desktop collapse/expand
  2. Toast notifications - DONE: All forms now show meaningful error messages via getErrorMessage()
  3. Empty states - DONE: All pages show icon + message + action button when empty
  4. Loading skeletons - DONE: Animated skeleton placeholders replace plain "Loading..." text

File Inventory (100+ files total)

Backend (40 files)

backend/
├── Dockerfile
├── requirements.txt
├── start.sh
├── .gitignore
├── alembic.ini
├── alembic/
│   ├── env.py
│   ├── script.py.mako
│   └── versions/
│       └── 001_initial_migration.py
└── app/
    ├── main.py
    ├── config.py
    ├── database.py
    ├── models/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── todo.py
    │   ├── calendar_event.py
    │   ├── reminder.py
    │   ├── project.py
    │   ├── project_task.py
    │   ├── person.py
    │   └── location.py
    ├── schemas/
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── todo.py
    │   ├── calendar_event.py
    │   ├── reminder.py
    │   ├── project.py
    │   ├── project_task.py
    │   ├── person.py
    │   └── location.py
    └── routers/
        ├── __init__.py
        ├── auth.py
        ├── dashboard.py
        ├── todos.py
        ├── events.py
        ├── reminders.py
        ├── projects.py
        ├── people.py
        ├── locations.py
        └── settings.py

Frontend (60+ files)

frontend/
├── Dockerfile
├── nginx.conf
├── package.json
├── vite.config.ts
├── tsconfig.json
├── tsconfig.node.json
├── postcss.config.js
├── tailwind.config.ts
├── components.json
├── index.html
├── .gitignore
└── src/
    ├── main.tsx
    ├── App.tsx
    ├── index.css (includes FullCalendar dark overrides)
    ├── lib/
    │   ├── utils.ts
    │   └── api.ts
    ├── hooks/
    │   ├── useAuth.ts
    │   ├── useSettings.ts
    │   └── useTheme.ts
    ├── types/
    │   └── index.ts
    └── components/
        ├── ui/ (12 components)
        ├── layout/ (AppLayout, Sidebar)
        ├── auth/ (LockScreen)
        ├── dashboard/ (DashboardPage, StatsWidget, UpcomingWidget, TodoWidget, CalendarWidget, ProjectsWidget)
        ├── todos/ (TodosPage, TodoList, TodoItem, TodoForm)
        ├── calendar/ (CalendarPage, EventForm)
        ├── reminders/ (RemindersPage, ReminderList, ReminderForm)
        ├── projects/ (ProjectsPage, ProjectCard, ProjectDetail, ProjectForm, TaskForm)
        ├── people/ (PeoplePage, PersonCard, PersonForm)
        ├── locations/ (LocationsPage, LocationCard, LocationForm)
        └── settings/ (SettingsPage)

Root

docker-compose.yaml
.env / .env.example
.gitignore
progress.md

How to Resume Development

If development is halted, pick up from the Outstanding Items section above:

  1. Check which items are still marked incomplete in the Milestone Tracker
  2. Address Critical items first (Docker build verification)
  3. Then Important items (auth flow, CRUD testing)
  4. Finally Polish items (responsive, loading states)

Quick Start Commands

# Build and run everything
docker-compose up --build

# Rebuild just backend after changes
docker-compose up --build backend

# Rebuild just frontend after changes
docker-compose up --build frontend

# View logs
docker-compose logs -f

# View specific service logs
docker-compose logs -f backend
docker-compose logs -f frontend

# Reset database (destructive)
docker-compose down -v && docker-compose up --build

# Stop everything
docker-compose down

First-Time Setup

  1. Run docker-compose up --build
  2. Navigate to http://localhost
  3. You'll see the PIN setup screen (first run)
  4. Create a PIN and you'll be redirected to the dashboard
  5. Use the sidebar to navigate between features