Files
taskpile/CLAUDE.md
Alvis f1d51b8cc8 Add side panels, task selection, graph animation, and project docs
- Foldable left panel (user profile) and right panel (task details)
- Clicking a task in the list or graph node selects it and shows details
- Both views (task list + graph) always mounted via absolute inset-0 for
  correct canvas dimensions; tabs toggle visibility with opacity
- Graph node selection animation: other nodes repel outward (charge -600),
  then selected node smoothly slides to center (500ms cubic ease-out),
  then charge restores to -120 and graph stabilizes
- Graph re-fits on tab switch and panel resize via ResizeObserver
- Fix UUID string IDs throughout (backend returns UUIDs, not integers)
- Add TaskDetailPanel, UserPanel components
- Add CLAUDE.md project documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 11:23:06 +00:00

3.2 KiB

Taskpile

A task manager with force-directed graph visualization.

Architecture

  • Frontend: Next.js 14 (App Router) + React 18 + Tailwind CSS 3 + TypeScript
  • Backend: Rust (Axum 0.7) + SQLite (via SQLx)
  • Graph: react-force-graph-2d for force-directed visualization

Project Structure

frontend/
  src/app/page.tsx          — Main page: tabs, panels, task state management
  src/app/layout.tsx        — Root layout
  src/components/
    GraphView.tsx            — Force graph with node selection, drag-to-center
    TaskList.tsx             — Pending/completed task list with selection
    TaskItem.tsx             — Individual task card
    AddTaskForm.tsx          — New task form
    TaskDetailPanel.tsx      — Right panel: selected task details
    UserPanel.tsx            — Left panel: user profile (example data)
    ForceGraphClient.tsx     — ForceGraph2D ref wrapper for dynamic import
  src/lib/
    api.ts                   — API client (fetch wrappers)
    types.ts                 — TypeScript interfaces
  src/__tests__/
    unit/                    — Jest unit tests (API, TaskItem)
    e2e/                     — Jest integration tests (full user flows)

backend/
  src/main.rs               — Axum server on port 3001
  src/models.rs             — Task, GraphNode, GraphEdge structs
  src/db.rs                 — SQLite pool + migrations
  src/graph.rs              — Deterministic edge generation (~30% pairs)
  src/routes/tasks.rs       — CRUD: GET/POST /api/tasks, PATCH/DELETE /api/tasks/:id
  src/routes/graph.rs       — GET /api/graph
  tests/integration_test.rs — Axum integration tests

Running

# Backend (port 3001)
cd backend && cargo run

# Frontend (port 3003, proxies /api to backend)
cd frontend && npm run dev -- -p 3003

Port 3000 is used by Gitea on this machine — use 3003 for the frontend.

Testing

# Frontend tests
cd frontend && npx jest

# Backend tests
cd backend && cargo test

Key Design Decisions

  • Task IDs are UUIDs (TEXT in SQLite, string from backend). Frontend Task.id is typed as number but actually receives strings — selection uses string comparison throughout.
  • Graph tab and task list are switched via tabs in the center area. Left panel (user info) and right panel (task details) are independently foldable.
  • Selecting a task (from list or graph node click) animates the node to the center of the viewport (drag-style, not camera pan). The node stays pinned until a different task is selected.
  • ForceGraph2D canvas dimensions are driven by a ResizeObserver on a container div that always renders. The canvas is only mounted after the first measurement to avoid a 300x300 default.
  • Panel transitions are 300ms CSS; graph re-fit/re-center delays 350ms to wait for the transition.

API

All endpoints under /api:

Method Path Description
GET /tasks List all tasks
POST /tasks Create task {title, description?}
PATCH /tasks/:id Update task {title?, description?, completed?}
DELETE /tasks/:id Delete task
GET /graph Get nodes + weighted edges

Proxy

Do not use system proxy env vars when testing the app locally — curl --noproxy '*' or equivalent.