# Taskpile A task manager with force-directed graph visualization and an MLOps-grade semantic feature store. ## Remote ``` http://localhost:3000/alvis/taskpile (Gitea, Agap server) ``` Push: `git push origin master` ## 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 - **ML**: Ollama (nomic-embed-text embeddings, qwen2.5:1.5b descriptions) — async worker, feature store in SQLite ## Project Structure ``` frontend/ src/app/page.tsx — Main page: tabs, panels, task state management; auth gate (LoginPage) src/app/layout.tsx — Root layout src/components/ GraphView.tsx — Force graph; node selection, drag-to-center, pending_count hint TaskList.tsx — Pending/completed task list with selection TaskItem.tsx — Individual task card (items-center, break-words) TaskDetailPanel.tsx — Right panel: full task info including AI context + ID LoginPage.tsx — Login form (auth gate) ProjectsPanel.tsx — Left panel: project filter ForceGraphClient.tsx — ForceGraph2D ref wrapper for dynamic import src/lib/ api.ts — API client (fetch wrappers, auth header, getMLStatus) types.ts — TypeScript interfaces (Task.created_at is number/Unix secs) src/__tests__/ unit/ — Jest unit tests (API, TaskItem) e2e/ — Jest integration tests (full user flows) backend/ src/main.rs — Axum server on port 3001; spawns ML worker on startup src/state.rs — AppState (pool + notify + cfg); FromRef for SqlitePool src/models.rs — Task, GraphNode, GraphEdge, GraphData structs src/db.rs — SQLite pool; migrations; seeds pending feature rows src/ml/ config.rs — MLConfig (model IDs, prompt_version, threshold); edge_model_key() ollama.rs — HTTP client; generate_description, get_embedding; render_prompt by version features.rs — content_hash, encode/decode embedding, mark_pending, compute, next_stale edges.rs — recompute_for_task (transactional, canonical source 0`. - `TaskItem` uses `items-center` (not `items-start`) so the checkbox aligns with the vertical center of the text block. Titles and descriptions use `break-words` to prevent overflow. - `TaskDetailPanel` shows all fields: title, description, project, tags, status, created_at (formatted), AI context (`latent_desc`) with a pending placeholder, and task ID. The AI context section previously used `text-gray-700` (invisible on dark bg) — now `text-gray-400`. ## API All endpoints under `/api`, Basic Auth required: | Method | Path | Description | |--------|------|-------------| | GET | /tasks | List all tasks | | POST | /tasks | Create task `{title, description?}` — seeds ML feature row | | PATCH | /tasks/:id | Update task `{title?, description?, completed?}` | | DELETE | /tasks/:id | Delete task (cascades to task_features + task_edges) | | GET | /graph | Nodes + edges + pending_count (pure read, no Ollama) | | GET | /ml/status | ML pipeline observability | ## Proxy Do not use system proxy env vars when testing the app locally — `curl --noproxy '*'` or equivalent.