Update project docs: calendar phase complete, Stage 3 done
- ui_refresh.md: Stage 3 marked complete with full item list - progress.md: Added Phase 8-10 milestones, updated file inventory Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
084daf5c7f
commit
bad1332d1b
384
.claude/context/progress.md
Normal file
384
.claude/context/progress.md
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
# 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
|
||||||
|
- [x] `docker-compose.yaml` - 3-service architecture (db, backend, frontend)
|
||||||
|
- [x] `.env` / `.env.example` - Environment configuration
|
||||||
|
- [x] `.gitignore` - Root gitignore
|
||||||
|
- [x] Backend: FastAPI app skeleton (`app/main.py`, `config.py`, `database.py`)
|
||||||
|
- [x] Backend: `requirements.txt` with all Python dependencies
|
||||||
|
- [x] Backend: Alembic migration setup (`alembic.ini`, `env.py`, initial migration)
|
||||||
|
- [x] Backend: `start.sh` startup script
|
||||||
|
- [x] Backend: `Dockerfile` - Python 3.12-slim
|
||||||
|
- [x] Frontend: Vite + React scaffold (`package.json`, `vite.config.ts`, `tsconfig.json`)
|
||||||
|
- [x] Frontend: Tailwind CSS + PostCSS configuration
|
||||||
|
- [x] Frontend: `index.html` entry point
|
||||||
|
- [x] Frontend: `nginx.conf` - SPA serving + API proxy
|
||||||
|
- [x] Frontend: `Dockerfile` - Multi-stage node build + nginx serve
|
||||||
|
- [x] Verify `docker-compose up --build` boots all services
|
||||||
|
|
||||||
|
### Phase 2: Auth & Layout
|
||||||
|
- [x] Backend: Settings model + schema
|
||||||
|
- [x] Backend: Auth router (PIN setup, login, logout, status with bcrypt + itsdangerous)
|
||||||
|
- [x] Frontend: `LockScreen.tsx` - PIN setup/login UI
|
||||||
|
- [x] Frontend: `useAuth.ts` hook (TanStack Query)
|
||||||
|
- [x] Frontend: `AppLayout.tsx` + `Sidebar.tsx` - Main layout with navigation
|
||||||
|
- [x] Frontend: Accent color theming system (`useTheme.ts`, CSS custom properties)
|
||||||
|
- [x] Frontend: 12 shadcn/ui components (button, card, input, dialog, select, badge, etc.)
|
||||||
|
|
||||||
|
### Phase 3: Core Features
|
||||||
|
- [x] Backend: Todo model, schema, router (CRUD + toggle + filters)
|
||||||
|
- [x] Frontend: `TodosPage`, `TodoList`, `TodoItem`, `TodoForm`
|
||||||
|
- [x] Backend: Calendar Event model, schema, router (CRUD + date range filter)
|
||||||
|
- [x] Frontend: `CalendarPage` (FullCalendar integration), `EventForm`
|
||||||
|
- [x] Frontend: FullCalendar dark theme CSS overrides in `index.css`
|
||||||
|
- [x] Backend: Reminder model, schema, router (CRUD + dismiss)
|
||||||
|
- [x] Frontend: `RemindersPage`, `ReminderList`, `ReminderForm`
|
||||||
|
|
||||||
|
### Phase 4: Project Management
|
||||||
|
- [x] Backend: Project model with tasks relationship + cascade delete
|
||||||
|
- [x] Backend: ProjectTask model, schema, router (nested CRUD under projects)
|
||||||
|
- [x] Frontend: `ProjectsPage`, `ProjectCard`, `ProjectDetail`, `ProjectForm`, `TaskForm`
|
||||||
|
|
||||||
|
### Phase 5: People & Locations
|
||||||
|
- [x] Backend: Person model, schema, router (CRUD + search)
|
||||||
|
- [x] Frontend: `PeoplePage`, `PersonCard`, `PersonForm`
|
||||||
|
- [x] Backend: Location model, schema, router (CRUD + category filter)
|
||||||
|
- [x] Frontend: `LocationsPage`, `LocationCard`, `LocationForm`
|
||||||
|
|
||||||
|
### Phase 6: Dashboard & Upcoming
|
||||||
|
- [x] Backend: Dashboard aggregation endpoint (stats, events, todos, reminders)
|
||||||
|
- [x] Backend: Upcoming endpoint (unified items sorted by date)
|
||||||
|
- [x] Frontend: `DashboardPage` with all widgets + upcoming integration
|
||||||
|
- [x] Frontend: `StatsWidget` (projects, people, locations counts)
|
||||||
|
- [x] Frontend: `UpcomingWidget` (unified timeline with type icons)
|
||||||
|
- [x] Frontend: `TodoWidget` (upcoming todos with priority badges)
|
||||||
|
- [x] Frontend: `CalendarWidget` (today's events with color indicators)
|
||||||
|
- [x] Frontend: Active reminders section in dashboard
|
||||||
|
|
||||||
|
### Phase 6b: Project Subtasks
|
||||||
|
- [x] Backend: Self-referencing `parent_task_id` FK on `project_tasks` with CASCADE delete
|
||||||
|
- [x] Backend: Alembic migration `002_add_subtasks.py`
|
||||||
|
- [x] Backend: Schema updates — `parent_task_id` in create, nested `subtasks` in response, `model_rebuild()`
|
||||||
|
- [x] Backend: Chained `selectinload` for two-level subtask loading, parent validation on create
|
||||||
|
- [x] Frontend: `ProjectTask` type updated with `parent_task_id` and `subtasks`
|
||||||
|
- [x] Frontend: `TaskForm` accepts `parentTaskId` prop, context-aware dialog title
|
||||||
|
- [x] Frontend: `ProjectDetail` — expand/collapse chevrons, subtask progress bars, indented subtask cards
|
||||||
|
|
||||||
|
### Phase 7: Settings & Polish
|
||||||
|
- [x] Backend: Settings router (get/update settings, change PIN)
|
||||||
|
- [x] Frontend: `SettingsPage` (accent color picker, upcoming range, PIN change)
|
||||||
|
- [x] Integration fixes: All frontend API paths match backend routes
|
||||||
|
- [x] Integration fixes: HTTP methods (PUT for updates, PATCH for toggle/dismiss)
|
||||||
|
- [x] Integration fixes: Type definitions match backend response schemas
|
||||||
|
- [x] Integration testing (end-to-end CRUD verification) <-- POST-BUILD
|
||||||
|
- [x] Final styling pass (responsive sidebar, empty states, loading skeletons)
|
||||||
|
|
||||||
|
### Phase 8: UI Refresh — Stages 1-2 (Dashboard & Global Shell)
|
||||||
|
- [x] Dashboard overhaul: contextual greeting, week timeline, stat cards, upcoming widget, weather
|
||||||
|
- [x] Typography: Sora headings + DM Sans body
|
||||||
|
- [x] Sidebar refinement: accent hover states, border-left active indicator, collapse animation
|
||||||
|
- [x] Custom scrollbar styling, staggered animations, skeleton loading states
|
||||||
|
- [x] Stylesheet (`stylesheet.md`) established as design system reference
|
||||||
|
|
||||||
|
### Phase 9: Calendar Redesign & Improvements
|
||||||
|
- [x] Multi-calendar backend with virtual birthday events from People
|
||||||
|
- [x] Calendar sidebar with visibility toggles and color indicators
|
||||||
|
- [x] Sheet component for slide-in form panels (replaced Dialog for all 4 forms)
|
||||||
|
- [x] All-day event fixes: slim CSS bars, exclusive end-date offset handling
|
||||||
|
- [x] Materialized recurring events: backend service, recurrence UI, scope dialog
|
||||||
|
- [x] LocationPicker with OSM Nominatim + local DB search (EventForm + LocationForm)
|
||||||
|
- [x] First day of week setting (Sunday/Monday) with FullCalendar sync
|
||||||
|
- [x] Dashboard parent template exclusion, DayBriefing null guards + night logic
|
||||||
|
- [x] Recurrence crash fixes: null stripping, _rule_int helper, first-occurrence generation
|
||||||
|
|
||||||
|
### Phase 10: UI Refresh — Stage 3+ (Remaining Pages)
|
||||||
|
- [ ] Stage 4: CRUD pages (Todos, Reminders, Projects) — refined filters, cards, empty states
|
||||||
|
- [ ] Stage 5: Entity pages (People, Locations) — avatar placeholders, consistent badges
|
||||||
|
- [ ] Stage 6: Settings & Login — full-width layout, UMBRA branding
|
||||||
|
- [ ] Stage 7: Final polish — consistency audit, animation review, accessibility pass
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Review Findings — Round 1 (Senior Review)
|
||||||
|
|
||||||
|
### Critical:
|
||||||
|
- [x] C1: CORS `allow_origins=["*"]` with `allow_credentials=True` — already restricted to `["http://localhost:5173"]` (`main.py`)
|
||||||
|
- [x] C2: `datetime.now(timezone.utc)` in naive column — changed to `datetime.now()` (`todos.py`)
|
||||||
|
- [x] C3: Session cookie missing `secure` flag — added `secure=True` + `_set_session_cookie` helper (`auth.py`)
|
||||||
|
- [x] C4: No PIN length validation on backend — added `field_validator` for min 4 chars (`schemas/settings.py`)
|
||||||
|
|
||||||
|
### High:
|
||||||
|
- [x] H1: No brute-force protection on login — added in-memory rate limiting (5 attempts / 5 min) (`auth.py`)
|
||||||
|
- [x] H2: `echo=True` on SQLAlchemy engine — set to `False` (`database.py`)
|
||||||
|
- [x] H3: Double commit pattern — removed auto-commit from `get_db`, routers handle commits (`database.py`)
|
||||||
|
- [ ] H4: `Person.relationship` column shadows SQLAlchemy name — deferred (requires migration + schema changes across stack)
|
||||||
|
- [x] H5: Upcoming events missing lower bound filter — added `>= today_start` (`dashboard.py`)
|
||||||
|
- [x] H6: `ReminderForm.tsx` doesn't slice `remind_at` — added `.slice(0, 16)` for datetime-local input
|
||||||
|
|
||||||
|
### Medium:
|
||||||
|
- [x] M1: Default `SECRET_KEY` is predictable — added stderr warning on startup (`config.py`)
|
||||||
|
- [x] M3: `create_all` in lifespan conflicts with Alembic — removed (`main.py`)
|
||||||
|
- [x] M6: No confirmation dialog before destructive actions — added `window.confirm()` on all delete buttons
|
||||||
|
- [x] M7: Authenticated users can still navigate to `/login` — added `Navigate` redirect in `LockScreen.tsx`
|
||||||
|
- [x] L1: Error handling in LockScreen used `error: any` — replaced with `getErrorMessage` helper
|
||||||
|
|
||||||
|
## Code Review Findings — Round 2 (Senior Review)
|
||||||
|
|
||||||
|
### Critical:
|
||||||
|
- [x] C1: Default SECRET_KEY only warns, doesn't block production — added env-aware fail-fast (`config.py`)
|
||||||
|
- [x] C2: `secure=True` cookie breaks HTTP development — made configurable via `COOKIE_SECURE` setting (`auth.py`, `config.py`)
|
||||||
|
- [x] C3: No enum validation on status/priority fields — added `Literal` types (`schemas/project_task.py`, `todo.py`, `project.py`)
|
||||||
|
- [x] C4: Race condition in PIN setup (TOCTOU) — added `select().with_for_update()` (`auth.py`)
|
||||||
|
|
||||||
|
### High:
|
||||||
|
- [x] H1: Rate limiter memory leak — added stale key cleanup, `del` empty entries (`auth.py`)
|
||||||
|
- [ ] H2: Dashboard runs 7 sequential DB queries — deferred (asyncpg single-session limitation)
|
||||||
|
- [ ] H3: Subtask eager loading fragile at 2 levels — accepted (business logic enforces single nesting)
|
||||||
|
- [x] H4: No `withCredentials` on Axios for Vite dev — added to `api.ts`
|
||||||
|
- [x] H5: Logout doesn't invalidate session server-side — added in-memory `_revoked_sessions` set (`auth.py`)
|
||||||
|
|
||||||
|
### Medium:
|
||||||
|
- [ ] M1: TodosPage fetches all then filters client-side — deferred (acceptable for personal app scale)
|
||||||
|
- [x] M2: Dashboard uses `.toISOString()` violating CLAUDE.md rules — replaced with local date formatter (`DashboardPage.tsx`)
|
||||||
|
- [x] M3: No CSP header in nginx — added CSP + Referrer-Policy, removed deprecated X-XSS-Protection (`nginx.conf`)
|
||||||
|
- [x] M4: Event date filtering misses range-spanning events — fixed range overlap logic (`events.py`)
|
||||||
|
- [x] M5: `accent_color` accepts arbitrary strings — added `Literal` validation for allowed colors (`schemas/settings.py`)
|
||||||
|
- [x] M6: Logout `delete_cookie` doesn't match `set_cookie` attributes — matched all cookie params (`auth.py`)
|
||||||
|
- [x] M7: bcrypt silently truncates PIN at 72 bytes — added max 72 char validation (`schemas/settings.py`)
|
||||||
|
|
||||||
|
### Low:
|
||||||
|
- [x] L1: `as any` type casts in frontend forms — replaced with proper `Type['field']` casts (`TaskForm.tsx`, `ProjectForm.tsx`)
|
||||||
|
- [x] L2: Unused imports in `events.py` — false positive, all imports are used
|
||||||
|
- [ ] L3: Upcoming endpoint mixes date/datetime string sorting — deferred (works correctly for ISO format)
|
||||||
|
- [ ] L4: Backend port 8000 exposed directly, bypassing nginx — deferred (useful for dev)
|
||||||
|
- [ ] L5: `parseInt(id!)` without NaN validation — deferred (low risk, route-level protection)
|
||||||
|
- [x] L6: `X-XSS-Protection` header is deprecated — removed, replaced with CSP (`nginx.conf`)
|
||||||
|
- [x] L7: Missing `Referrer-Policy` header — added `strict-origin-when-cross-origin` (`nginx.conf`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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):
|
||||||
|
3. ~~**Alembic migration test**~~ - DONE: Tables create correctly on first boot
|
||||||
|
4. ~~**Auth flow test**~~ - DONE: PIN setup works, PIN change works, session persistence works, logout added
|
||||||
|
5. ~~**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):
|
||||||
|
6. ~~**Responsive sidebar**~~ - DONE: Mobile hamburger menu with overlay, desktop collapse/expand
|
||||||
|
7. ~~**Toast notifications**~~ - DONE: All forms now show meaningful error messages via `getErrorMessage()`
|
||||||
|
8. ~~**Empty states**~~ - DONE: All pages show icon + message + action button when empty
|
||||||
|
9. ~~**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
|
||||||
|
│ ├── 002_add_subtasks.py
|
||||||
|
│ ├── 003_add_location_to_events.py
|
||||||
|
│ ├── 004_add_starred_field.py
|
||||||
|
│ ├── 005_add_weather_fields.py
|
||||||
|
│ ├── 006_add_calendars.py
|
||||||
|
│ ├── 007_add_recurrence_fields.py
|
||||||
|
│ └── 008_add_first_day_of_week.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
|
||||||
|
│ └── calendar.py
|
||||||
|
├── services/
|
||||||
|
│ └── recurrence.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/ (14 components: + sheet, location-picker)
|
||||||
|
├── layout/ (AppLayout, Sidebar)
|
||||||
|
├── auth/ (LockScreen)
|
||||||
|
├── dashboard/ (DashboardPage, StatsWidget, UpcomingWidget, TodoWidget, CalendarWidget, ProjectsWidget)
|
||||||
|
├── todos/ (TodosPage, TodoList, TodoItem, TodoForm)
|
||||||
|
├── calendar/ (CalendarPage, CalendarSidebar, 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
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
251
.claude/projects/ui_refresh.md
Normal file
251
.claude/projects/ui_refresh.md
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
# UMBRA UI Refresh — Planning Document
|
||||||
|
|
||||||
|
## Current UI Audit (2026-02-20)
|
||||||
|
|
||||||
|
### Global Observations
|
||||||
|
- **Theme:** Dark background (~#0a0a0a), dark card surfaces (~#1a1a2e), blue/cyan accent
|
||||||
|
- **Sidebar:** Fixed left ~200px, solid blue highlight on active item, Lucide icons + labels, collapse chevron
|
||||||
|
- **Typography:** System sans-serif, white headings, muted gray subtext — functional but lacks personality
|
||||||
|
- **Cards:** Rounded borders with subtle gray stroke, no shadows, no hover effects, no transitions
|
||||||
|
- **Layout:** Full-width content area with no max-width constraint — cards stretch awkwardly on wide displays
|
||||||
|
- **Action buttons:** Consistent "+ Add X" blue filled buttons top-right on every page — good pattern
|
||||||
|
- **Empty states:** Centered icon + message — functional but lifeless
|
||||||
|
- **Scrollbars:** Default browser scrollbars — clash with dark theme
|
||||||
|
|
||||||
|
### Page-by-Page Notes
|
||||||
|
|
||||||
|
#### Login
|
||||||
|
- Centered dark card, lock icon, PIN input, blue "Unlock" button
|
||||||
|
- Clean and minimal — works well structurally
|
||||||
|
- Missing UMBRA branding/identity — feels like a generic auth screen
|
||||||
|
- No ambient atmosphere (no gradients, no glow, no texture)
|
||||||
|
|
||||||
|
#### Dashboard
|
||||||
|
- 4 stat cards across top (Total Projects, In Progress, People, Locations) with colored Lucide icons
|
||||||
|
- "Upcoming (7 days)" section — flat list of events with "Event" badge right-aligned
|
||||||
|
- Bottom row: "Upcoming Todos" + "Today's Events" side by side
|
||||||
|
- **Issues:**
|
||||||
|
- Stat cards are flat rectangles with label/number/icon — no visual weight or hierarchy
|
||||||
|
- Icon colors (purple, purple, green, orange) feel arbitrary — no semantic meaning
|
||||||
|
- Upcoming list wastes horizontal space — event name far left, badge far right, nothing in between
|
||||||
|
- Bottom widgets have massive empty space when few/no items
|
||||||
|
- No week summary or schedule preview — missed opportunity for at-a-glance context
|
||||||
|
- "Welcome back. Here's your overview." is generic placeholder text
|
||||||
|
- No time-of-day awareness or contextual greeting
|
||||||
|
|
||||||
|
#### Todos
|
||||||
|
- Search bar + "All Priorities" dropdown + category filter + "Show completed" checkbox
|
||||||
|
- All controls on single line — functional but cramped and visually flat
|
||||||
|
- Empty state: centered checkbox icon + message
|
||||||
|
- **Issues:** Filter controls are unstyled native elements mixed with custom — inconsistent
|
||||||
|
|
||||||
|
#### Calendar (Month)
|
||||||
|
- FullCalendar month view with colored event dots/pills
|
||||||
|
- Color coding: blue (default), purple, green (multi-day), orange, yellow
|
||||||
|
- **Issues:**
|
||||||
|
- Prev/next navigation arrows are tiny unstyled squares (~16px) — nearly invisible
|
||||||
|
- "today" button is plain text with no visual emphasis
|
||||||
|
- Event text truncates on small cells with no tooltip or expand affordance
|
||||||
|
- Multi-day events (green/orange bars) visually dominate and obscure day cells
|
||||||
|
- No visual distinction for today's date in month grid
|
||||||
|
|
||||||
|
#### Calendar (Week)
|
||||||
|
- Time grid with events as colored blocks — time + title visible
|
||||||
|
- Today column has yellowish-brown tint overlay
|
||||||
|
- **Issues:**
|
||||||
|
- The "today" tint is murky (#8B8000-ish overlay) — looks dirty rather than highlighted
|
||||||
|
- Past-time columns also have this tint, making it confusing
|
||||||
|
- No current-time indicator line
|
||||||
|
|
||||||
|
#### Calendar (Day)
|
||||||
|
- Full-day column with same murky brown-yellow background
|
||||||
|
- **Issues:** When empty, entire content area is just a brown column — unappealing
|
||||||
|
- No visual distinction between past hours and future hours
|
||||||
|
|
||||||
|
#### Reminders
|
||||||
|
- Tab bar: Active / Dismissed / All — clean blue active state
|
||||||
|
- Empty state similar to Todos
|
||||||
|
- Very sparse — large empty space below tabs
|
||||||
|
|
||||||
|
#### Projects
|
||||||
|
- 3-column card grid
|
||||||
|
- Each card: ALL-CAPS name, status badge pill, "Progress" label with thin bar, task count, calendar icon + due date
|
||||||
|
- **Issues:**
|
||||||
|
- ALL-CAPS names are aggressive and hard to scan
|
||||||
|
- Status badges ("not started" / "in progress") are small outlined pills — low contrast
|
||||||
|
- Progress bars are extremely thin (~2px) and low-contrast against dark surface
|
||||||
|
- "Progress" label + "0/3 tasks" on same line wastes vertical space
|
||||||
|
- Cards have uneven internal spacing — description shows on some, not others
|
||||||
|
- No hover state or click affordance — cards don't feel interactive
|
||||||
|
|
||||||
|
#### People
|
||||||
|
- 3-column card grid
|
||||||
|
- Each card: name, category badge (Friends = blue, Work = gray), birthday, edit/delete icons top-right
|
||||||
|
- **Issues:**
|
||||||
|
- Cards feel sparse — just 3 lines of info in a large rectangle
|
||||||
|
- No avatar placeholder — missed opportunity for visual anchoring
|
||||||
|
- Edit (pencil) and delete (trash) icons are small and far from the name
|
||||||
|
- Category badge colors don't match Locations page (Work = gray here, purple there)
|
||||||
|
|
||||||
|
#### Locations
|
||||||
|
- 3-column card grid with location pin icon beside name
|
||||||
|
- Category badges: home = blue, work = purple
|
||||||
|
- Address shown as subtitle
|
||||||
|
- **Issues:** Badge color system inconsistent with People page
|
||||||
|
|
||||||
|
#### Settings
|
||||||
|
- Three stacked sections: Appearance, Dashboard, Security
|
||||||
|
- Left-aligned at ~50% width, entire right half is empty
|
||||||
|
- Accent color picker: 5 colored circles (cyan, blue, purple, orange, green)
|
||||||
|
- **Issues:**
|
||||||
|
- Massive dead space on right — feels incomplete
|
||||||
|
- Color circles have no labels or tooltips
|
||||||
|
- Sections could use visual separation beyond just spacing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design Critique (Frontend Design Review)
|
||||||
|
|
||||||
|
### 1. Surface & Depth — "Everything lives on the same plane"
|
||||||
|
The biggest visual issue is that every element — cards, sidebar, content area, stat widgets — exists at the same depth. There are no shadows, no layering, no elevation changes. Modern dark UIs use subtle elevation to create hierarchy:
|
||||||
|
- Cards should float slightly above the background with soft box-shadows (`0 1px 3px rgba(0,0,0,0.3)`)
|
||||||
|
- The sidebar should feel like a separate layer with a subtle border or shadow on its right edge
|
||||||
|
- Hover states should lift cards slightly (`translateY(-1px)` + shadow increase)
|
||||||
|
- Active/selected states should have a gentle inner glow or border luminance shift
|
||||||
|
|
||||||
|
### 2. Typography — "Functional but forgettable"
|
||||||
|
The current type system is plain system sans-serif with two weights (bold headings, normal body). For a personal life manager named "UMBRA," typography should reinforce brand identity:
|
||||||
|
- Consider a distinctive heading font (geometric sans like Outfit, Sora, or General Sans)
|
||||||
|
- Body text needs slightly more line-height for readability on dark backgrounds (1.6 minimum)
|
||||||
|
- The ALL-CAPS project names are too aggressive — use sentence case with semibold weight instead
|
||||||
|
- Stat card numbers should be larger and use tabular figures for alignment
|
||||||
|
- Muted text (#6b7280-range) is too low-contrast on dark backgrounds — bump to #9ca3af minimum
|
||||||
|
|
||||||
|
### 3. Color System — "Arbitrary accents without semantic meaning"
|
||||||
|
Colors are applied without a clear system:
|
||||||
|
- Stat card icons use purple/purple/green/orange — why purple twice? No semantic connection
|
||||||
|
- Category badges are inconsistent: Work is gray on People, purple on Locations
|
||||||
|
- The calendar today overlay (#8B8000-ish) clashes with the cool-toned theme
|
||||||
|
- **Recommendation:** Establish a semantic color palette:
|
||||||
|
- Accent (cyan/blue): interactive elements, active states, links
|
||||||
|
- Success (emerald): completed, on-track
|
||||||
|
- Warning (amber): upcoming, due soon
|
||||||
|
- Danger (rose): overdue, delete
|
||||||
|
- Neutral (slate): secondary text, borders, disabled
|
||||||
|
- Category colors should be consistent app-wide (same color for "Work" everywhere)
|
||||||
|
|
||||||
|
### 4. Spacing & Density — "Too much air, not enough content"
|
||||||
|
- Dashboard stat cards have generous internal padding but minimal content — lots of dead space
|
||||||
|
- The Upcoming list is a single-column spanning the full width with text far-left and badge far-right
|
||||||
|
- Settings page uses only half the viewport width
|
||||||
|
- Cards on People/Locations show 3 lines of info in ~150px tall containers
|
||||||
|
- **Recommendation:** Use a tighter grid system. Dashboard should use a 2-column or asymmetric layout below stats. Cards should breathe but not float in empty space. Consider max-width containers (1200-1400px).
|
||||||
|
|
||||||
|
### 5. Interactivity — "Static pages, not a living app"
|
||||||
|
Zero motion, zero feedback:
|
||||||
|
- No hover states on any cards or interactive elements
|
||||||
|
- No transitions on page changes
|
||||||
|
- No loading states or skeleton screens
|
||||||
|
- No micro-interactions (checkbox toggle, card expand, badge pulse)
|
||||||
|
- Scrollbars are default browser chrome — jarring in dark theme
|
||||||
|
- **Recommendation:** Add CSS transitions on all interactive elements (150-200ms ease). Custom scrollbar styling with `scrollbar-color` and `::-webkit-scrollbar`. Subtle scale/shadow on card hover.
|
||||||
|
|
||||||
|
### 6. Dashboard Specific — "A bulletin board, not a command center"
|
||||||
|
The dashboard is the first thing you see and it should feel alive:
|
||||||
|
- Missing: week-at-a-glance schedule/timeline
|
||||||
|
- Missing: contextual greeting (time of day + name)
|
||||||
|
- Missing: quick actions or shortcuts
|
||||||
|
- Stat cards don't link context — "5 Projects" but which ones matter right now?
|
||||||
|
- Bottom widgets (Upcoming Todos / Today's Events) are equal-width but Today's Events is more urgent
|
||||||
|
- **Recommendation:** Redesign dashboard as a "morning briefing" — today's schedule, this week's priorities, active project progress, quick-add shortcuts
|
||||||
|
|
||||||
|
### 7. Component Quality — "Default HTML with Tailwind"
|
||||||
|
Several components feel like unstyled defaults:
|
||||||
|
- Calendar nav arrows are default FullCalendar squares — need custom styled buttons
|
||||||
|
- Filter dropdowns on Todos look like native `<select>` elements
|
||||||
|
- Progress bars are 2px thin lines — should be thicker (6-8px) with rounded ends and gradient fills
|
||||||
|
- Badge pills lack padding consistency and weight
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Stages
|
||||||
|
|
||||||
|
### Stage 1: Dashboard Overhaul — COMPLETED
|
||||||
|
- [x] Redesign dashboard layout: greeting, week summary, stat cards, upcoming events, today's schedule
|
||||||
|
- [x] Establish new card component with shadows, hover states, transitions
|
||||||
|
- [x] Add custom scrollbar styling globally
|
||||||
|
- [x] Set up CSS custom properties for the refined color system
|
||||||
|
- [x] **Deliverable:** Polished dashboard + `stylesheet.md` capturing the new design language
|
||||||
|
- [x] Typography: Sora headings + DM Sans body
|
||||||
|
- [x] Contextual greeting (time-of-day aware)
|
||||||
|
- [x] Week-at-a-glance timeline with today highlight + event dots
|
||||||
|
- [x] Stat cards with gradient backgrounds, semantic icon colors, tabular numbers
|
||||||
|
- [x] Upcoming widget with type badges + priority pills
|
||||||
|
- [x] Today's Events + Upcoming Todos + Active Reminders sidebar widgets
|
||||||
|
- [x] Weather widget with location search
|
||||||
|
- [x] Staggered fade-in/slide-up animations
|
||||||
|
- [x] Smart nudge bar (contextual tips below week timeline)
|
||||||
|
|
||||||
|
### Stage 2: Global Shell & Navigation — COMPLETED
|
||||||
|
- [x] Sidebar refinement: accent-colored hover states, border-left active indicator, collapse animation
|
||||||
|
- [x] Separator between nav items and utility items (Settings, Logout)
|
||||||
|
- [x] Global transitions and loading states (skeleton screens)
|
||||||
|
- [x] Custom scrollbar applied everywhere (accent-tinted on hover)
|
||||||
|
|
||||||
|
### Stage 3: Calendar Redesign & Improvements — COMPLETED
|
||||||
|
- [x] Multi-calendar backend: user-created calendars with color, virtual birthday calendar from People
|
||||||
|
- [x] Calendar sidebar with collapsible calendar list, visibility toggles, color indicators
|
||||||
|
- [x] Custom-styled toolbar: prev/next/today buttons, segmented Month/Week/Day view switcher
|
||||||
|
- [x] Calendar header alignment with global UMBRA header (h-16), no border wrapper
|
||||||
|
- [x] ResizeObserver for sidebar collapse → calendar auto-resizes
|
||||||
|
- [x] Sheet component (`sheet.tsx`): slide-in panel replacing Dialog for all forms
|
||||||
|
- [x] All 4 forms migrated to Sheet: EventForm, TodoForm, ReminderForm, LocationForm
|
||||||
|
- [x] Form layout improvements: 2-column grids for related fields, wider textareas
|
||||||
|
- [x] All-day event fixes: slim CSS bars, exclusive end-date offset (display ↔ save)
|
||||||
|
- [x] Materialized recurring events backend: migration, model, service, router
|
||||||
|
- [x] Recurrence UI: structured picker (every N days, weekly, monthly nth weekday, monthly date)
|
||||||
|
- [x] Edit/delete scope dialog for recurring events ("This event only" / "This and all future")
|
||||||
|
- [x] Drag-drop/resize guards for recurring events (reverts with info toast)
|
||||||
|
- [x] LocationPicker component with OSM Nominatim integration + local DB search
|
||||||
|
- [x] LocationPicker integrated into EventForm and LocationForm
|
||||||
|
- [x] First day of week setting (Sunday/Monday) in Settings with calendar sync
|
||||||
|
- [x] FullCalendar reactivity fix: key prop for firstDay remount
|
||||||
|
- [x] Dashboard/upcoming queries: parent template exclusion filter (no duplicates)
|
||||||
|
- [x] DayBriefing: null guards on end_datetime, reminders in night briefing, pre-5AM today awareness
|
||||||
|
- [x] Recurrence crash fixes: null field stripping, _rule_int helper, first-occurrence generation
|
||||||
|
|
||||||
|
### Stage 4: CRUD Pages (Todos, Reminders, Projects)
|
||||||
|
- Refined filter bar components
|
||||||
|
- Improved card designs (Projects: progress bars, status badges)
|
||||||
|
- Better empty states with contextual illustrations or suggestions
|
||||||
|
- Consistent hover/click affordances
|
||||||
|
|
||||||
|
### Stage 5: Entity Pages (People, Locations)
|
||||||
|
- Avatar placeholders for People cards
|
||||||
|
- Consistent category badge colors app-wide
|
||||||
|
- Denser card layout with more visible info
|
||||||
|
|
||||||
|
### Stage 6: Settings & Login
|
||||||
|
- Settings: full-width responsive layout, labeled color picker, section cards
|
||||||
|
- Login: UMBRA branding, ambient background effect
|
||||||
|
|
||||||
|
### Stage 7: Final Polish
|
||||||
|
- Cross-page consistency audit
|
||||||
|
- Animation timing review
|
||||||
|
- Accessibility pass (contrast ratios, focus states)
|
||||||
|
- Performance review (no layout shifts, smooth transitions)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## User Requirements
|
||||||
|
- Maintain dark minimalist theme with accent colors
|
||||||
|
- More modern, softer, cleaner aesthetic
|
||||||
|
- Less dead space in UI elements
|
||||||
|
- Themed scrollbars matching the dark UI
|
||||||
|
- Dashboard: include a summary of the current week
|
||||||
|
- Incremental implementation — dashboard first, then style guide, then remaining pages
|
||||||
|
|
||||||
|
## Refresh Scope
|
||||||
|
_~~Dashboard first (Stage 1) → style-guide.md~~ → Stage 3 (Calendar) next → remaining stages in order._
|
||||||
|
|
||||||
|
**Current status:** Stages 1-3 complete. Stylesheet established. Calendar redesign with recurrence, multi-calendar, sheet forms, and LocationPicker done. Next up: Stage 4 (CRUD Pages).
|
||||||
Loading…
x
Reference in New Issue
Block a user