CLAUDE.md: - UI components count 12→16, list updated with Sheet, LocationPicker, etc. - Calendar section lists all 5 components (CalendarSidebar, TemplateForm, etc.) - Projects section lists all 8 components (KanbanBoard, TaskDetailPanel, etc.) - Hooks section adds useCalendars - API routes table adds /calendars, /event-templates, /weather, /locations search - Settings description adds first day of week - Fix ui_refresh.md authority link path, remove stale progress.md link ui_refresh.md: - Stage 3 additions: event template UX fixes, Sheet conversion, auto-prefill, template creation title, LocationPicker mount guard - Updated current status line Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
153 lines
7.7 KiB
Markdown
153 lines
7.7 KiB
Markdown
# CLAUDE.md - UMBRA
|
|
|
|
## CRUCIAL CONTEXT EFFICIENCY
|
|
|
|
### Subagent Discipline
|
|
- Prefer inline work for tasks under ~5 tool calls. Subagents have overhead — don't delegate trivially.
|
|
- When using subagents, include output rules: "Final response under 2000 characters. List outcomes, not process."
|
|
- Never call TaskOutput twice for the same subagent. If it times out, increase the timeout — don't re-read.
|
|
|
|
### File Reading
|
|
- Read files with purpose. Before reading a file, know what you're looking for.
|
|
- Use Grep to locate relevant sections before reading entire large files.
|
|
- Never re-read a file you've already read in this session.
|
|
- For files over 500 lines, use offset/limit to read only the relevant section.
|
|
|
|
### Responses
|
|
- Don't echo back file contents you just read — the user can see them.
|
|
- Don't narrate tool calls ("Let me read the file..." / "Now I'll edit..."). Just do it.
|
|
- Keep explanations proportional to complexity. Simple changes need one sentence, not three paragraphs.
|
|
|
|
## Deployment & Access
|
|
|
|
- **UMBRA is hosted on a remote machine** at `http://10.0.69.35` (not localhost).
|
|
- **Login PIN:** `1993`
|
|
- **Rebuilds are manual.** Do not run `docker-compose` commands — the user will rebuild on the remote machine when needed.
|
|
- **Browser automation** can access the live app at `http://10.0.69.35`.
|
|
|
|
## Operational Procedures
|
|
|
|
- Before making any changes or edits to code, create a branch. Once work is completed, commit and push to the branch automatically, then merge into main and push.
|
|
- When required: For backend work invoke the 'backend-engineer' subagent, for work on the front end, invoke the 'frontend-engineer' subagent. To review work use the 'senior-code-reviewer' subagent and for any research use the 'research-analyst' subagent.
|
|
- For any frontend UI related work you MUST use the frontend design skill AND reference the [stylesheet](.claude/context/stylesheet.md) to ensure visual consistency. The stylesheet defines all colors, typography, spacing, component patterns, and design principles for UMBRA. Do not invent new patterns.
|
|
|
|
## Known Issues
|
|
|
|
- **Git push auth flake.** The first `git push` to the Gitea remote will fail with an authentication error. Simply retry the same push command — the second attempt succeeds.
|
|
|
|
## 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**
|
|
|
|
## Authority Links
|
|
|
|
- [ui_refresh.md](.claude/projects/ui_refresh.md) - UI overhaul project plan, audit findings, implementation stages
|
|
- [stylesheet.md](.claude/context/stylesheet.md) - Design system & visual reference for all frontend work
|
|
|
|
## 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, useCalendars
|
|
types/index.ts # TypeScript interfaces matching backend schemas
|
|
components/
|
|
ui/ # 16 base components (Button, Dialog, Sheet, Card, Input, Select, etc.)
|
|
layout/ # AppLayout + Sidebar
|
|
auth/ # LockScreen (PIN setup/login)
|
|
dashboard/ # DashboardPage + widgets (Stats, Calendar, Todo, Upcoming, Countdown, etc.)
|
|
calendar/ # CalendarPage, CalendarSidebar, CalendarForm, EventForm, TemplateForm
|
|
todos/ # TodosPage + TodoList + TodoItem + TodoForm
|
|
reminders/ # RemindersPage + ReminderList + ReminderForm
|
|
projects/ # ProjectsPage, ProjectCard, ProjectDetail, ProjectForm, KanbanBoard, TaskRow, TaskForm, TaskDetailPanel
|
|
people/ # PeoplePage + PersonCard + PersonForm
|
|
locations/ # LocationsPage + LocationCard + LocationForm
|
|
settings/ # SettingsPage (accent color, PIN change, first day of week)
|
|
```
|
|
|
|
## Essential Commands
|
|
|
|
```bash
|
|
# 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 (incl. recurring) |
|
|
| `/api/event-templates` | Event templates CRUD |
|
|
| `/api/calendars` | User calendars CRUD + visibility |
|
|
| `/api/reminders` | Reminders CRUD + dismiss |
|
|
| `/api/projects` | Projects + nested tasks CRUD |
|
|
| `/api/people` | People CRUD |
|
|
| `/api/locations` | Locations CRUD + search |
|
|
| `/api/settings` | Settings + PIN change |
|
|
| `/api/dashboard` | Dashboard aggregation |
|
|
| `/api/upcoming` | Unified upcoming items |
|
|
| `/api/weather` | Weather data proxy |
|
|
|
|
## 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
|