From 9fe0998436488537a8a2e8ffeefb0c4424b41c60 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Mon, 12 Jan 2026 09:27:16 -1000 Subject: Initial commit: Personal Consolidation Dashboard (Phase 1 Complete) Implemented a unified web dashboard aggregating tasks, notes, and meal planning: Core Features: - Trello integration (PRIMARY feature - boards, cards, lists) - Todoist integration (tasks and projects) - Obsidian integration (20 most recent notes) - PlanToEat integration (optional - 7-day meal planning) - Mobile-responsive web UI with auto-refresh (5 min) - SQLite caching with 5-minute TTL - AI agent endpoint with Bearer token authentication Technical Implementation: - Go 1.21+ backend with chi router - Interface-based API client design for testability - Parallel data fetching with goroutines - Graceful degradation (partial data on API failures) - .env file loading with godotenv - Comprehensive test coverage (9/9 tests passing) Bug Fixes: - Fixed .env file not being loaded at startup - Fixed nil pointer dereference with optional API clients (typed nil interface gotcha) Documentation: - START_HERE.md - Quick 5-minute setup guide - QUICKSTART.md - Fast track setup - SETUP_GUIDE.md - Detailed step-by-step instructions - PROJECT_SUMMARY.md - Complete project overview - CLAUDE.md - Guide for Claude Code instances - AI_AGENT_ACCESS.md - AI agent design document - AI_AGENT_SETUP.md - Claude.ai integration guide - TRELLO_AUTH_UPDATE.md - New Power-Up auth process Statistics: - Binary: 17MB - Code: 2,667 lines - Tests: 5 unit + 4 acceptance tests (all passing) - Dependencies: chi, sqlite3, godotenv Co-Authored-By: Claude Sonnet 4.5 --- spec.md | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 spec.md (limited to 'spec.md') diff --git a/spec.md b/spec.md new file mode 100644 index 0000000..a62909b --- /dev/null +++ b/spec.md @@ -0,0 +1,383 @@ +# Personal Consolidation Dashboard - Project Spec + +## Overview +Build a unified web dashboard that aggregates tasks, notes, and meal planning from multiple services into a single interface. Go backend + simple frontend with mobile-responsive design. + +## Core Requirements + +### Phase 1: Read-Only Aggregation (MVP) +Display data from: +1. **Todoist** - Tasks and projects +2. **Obsidian** - Recent notes (file system access) +3. **PlanToEat** - Upcoming meals/recipes +4. **Trello** (optional phase 1) - Boards and cards + +### Phase 2: Write Operations +- Create/update/complete tasks in Todoist +- Quick capture notes (save to Obsidian vault) +- Add meals to PlanToEat planner + +### Phase 3: Enhancements +- Search across all sources +- Unified quick capture +- Daily digest view +- Mobile PWA configuration + +## Technical Stack + +### Backend +- **Language:** Go 1.21+ +- **Framework:** Standard library + chi/gorilla for routing (your choice) +- **Storage:** SQLite for caching API responses, user preferences +- **APIs:** + - Todoist REST API v2: https://developer.todoist.com/rest/v2 + - PlanToEat API: https://www.plantoeat.com/developers + - Trello REST API: https://developer.atlassian.com/cloud/trello/rest + - Obsidian: Direct filesystem access to vault directory + +### Frontend +- **Framework:** HTMX + Tailwind CSS (or plain HTML/CSS/vanilla JS - your preference) +- **Mobile:** Responsive design, PWA manifest later + +### Deployment +- **Local first:** Run on localhost:8080 +- **Future:** Docker container, deploy to Fly.io/Railway +- **Data:** SQLite file in project directory, environment variables for API keys + +## Data Models + +### Task (from Todoist) +```go +type Task struct { + ID string + Content string + Description string + ProjectID string + ProjectName string + DueDate *time.Time + Priority int + Completed bool + Labels []string + URL string // Link back to Todoist +} +``` + +### Note (from Obsidian) +```go +type Note struct { + Filename string + Title string + Content string // First 200 chars or full content + Modified time.Time + Path string + Tags []string +} +``` + +### Meal (from PlanToEat) +```go +type Meal struct { + ID string + RecipeName string + Date time.Time + MealType string // breakfast, lunch, dinner + RecipeURL string +} +``` + +### Board/Card (from Trello) +```go +type Board struct { + ID string + Name string + Cards []Card +} + +type Card struct { + ID string + Name string + ListID string + ListName string + DueDate *time.Time + URL string +} +``` + +## API Integration Details + +### Todoist +- **Auth:** Bearer token in Authorization header +- **Endpoint:** https://api.todoist.com/rest/v2/tasks +- **Rate limit:** Not publicly documented, use reasonable polling (5min intervals) +- **Key operations:** + - GET /tasks - Fetch all active tasks + - GET /projects - Fetch project list + - POST /tasks - Create new task + - POST /tasks/{id}/close - Complete task + +### PlanToEat +- **Auth:** API key in query parameter or header (check docs) +- **Endpoint:** https://www.plantoeat.com/api/v2 +- **Key operations:** + - GET /planner_items - Fetch upcoming meals + - GET /recipes - Fetch recipe details + +### Trello +- **Auth:** API Key + Token in query parameters +- **Endpoint:** https://api.trello.com/1 +- **Key operations:** + - GET /members/me/boards - Fetch user's boards + - GET /boards/{id}/cards - Fetch cards on board + +### Obsidian +- **Access:** Direct filesystem reads from vault directory +- **Location:** Environment variable `OBSIDIAN_VAULT_PATH` +- **Parse:** Markdown files, extract YAML frontmatter for metadata +- **Watch:** Optional - use fsnotify for real-time updates + +## Architecture + +### Backend Structure +``` +cmd/ + dashboard/ + main.go # Entry point, server setup +internal/ + api/ + todoist.go # Todoist API client + plantoeat.go # PlanToEat API client + trello.go # Trello API client + obsidian.go # Filesystem reader + handlers/ + tasks.go # HTTP handlers for task views + notes.go # HTTP handlers for notes + meals.go # HTTP handlers for meals + models/ + types.go # Shared data structures + store/ + sqlite.go # Database operations +web/ + static/ + css/ + styles.css # Tailwind or custom styles + js/ + app.js # Optional vanilla JS + templates/ + index.html # Main dashboard + tasks.html # Task list partial + notes.html # Notes list partial +``` + +### Configuration +Environment variables (.env file): +```bash +TODOIST_API_KEY=your_token +PLANTOEAT_API_KEY=your_key +TRELLO_API_KEY=your_key +TRELLO_TOKEN=your_token +OBSIDIAN_VAULT_PATH=/path/to/vault +DATABASE_PATH=./dashboard.db +PORT=8080 +``` + +## UI Requirements + +### Dashboard Layout +``` ++----------------------------------+ +| [Quick Capture] | ++----------------------------------+ +| Today's Tasks | Meals | +| □ Task 1 | 🍳 Breakfast| +| □ Task 2 | 🍕 Lunch | +| ☑ Task 3 | 🍝 Dinner | ++----------------------------------+ +| Recent Notes | +| • Note 1 (2h ago) | +| • Note 2 (1d ago) | ++----------------------------------+ +| Trello Boards (optional) | ++----------------------------------+ +``` + +### Features +- **Mobile-responsive** - Stack vertically on small screens +- **Dark mode support** (optional but nice) +- **Refresh button** - Manual data sync +- **Auto-refresh** - Every 5 minutes +- **Loading states** - Spinners during API calls +- **Error handling** - Show API failures gracefully + +## Success Criteria + +### Phase 1 Complete When: +- [ ] Dashboard shows Todoist tasks for today/week +- [ ] Dashboard shows 5-10 most recent Obsidian notes +- [ ] Dashboard shows upcoming meals from PlanToEat +- [ ] Responsive design works on mobile browser +- [ ] Runs locally with `go run cmd/dashboard/main.go` + +### Phase 2 Complete When: +- [ ] Can create new Todoist task from dashboard +- [ ] Can mark Todoist task complete +- [ ] Can create quick note (saves to Obsidian vault) + +## Non-Requirements (Out of Scope) +- User authentication (single user only) +- Real-time sync (polling is fine) +- Offline support +- Data analytics/insights +- Calendar integration +- Migration tools from Google Keep +- Bi-directional Trello sync + +## Development Notes + +### API Key Setup +User must obtain: +1. Todoist: Settings → Integrations → API token +2. PlanToEat: Account settings → API access +3. Trello: https://trello.com/app-key → Generate token +4. Obsidian: Just need filesystem path + +### Testing Strategy +- Start with Todoist integration only (simplest API) +- Mock API responses for initial UI development +- Use real APIs once structure is solid +- Test on mobile browser early + +### Performance +- Cache API responses in SQLite (5min TTL) +- Obsidian: Only scan vault on startup + when requested +- Parallel API calls using goroutines +- Limit Obsidian file reads (e.g., last 20 modified files) + +## Questions to Resolve During Development +1. HTMX vs vanilla JS for interactivity? +2. Full Tailwind build or CDN version? +3. SQLite migrations approach (golang-migrate vs manual)? +4. Obsidian vault - recursive scan or flat directory? +5. Trello - all boards or filter to specific ones? + +## Getting Started Checklist +- [ ] Initialize Go module +- [ ] Set up project structure +- [ ] Create .env.example with required variables +- [ ] Implement Todoist API client first (test with real token) +- [ ] Build basic HTTP server with single endpoint +- [ ] Create simple HTML template +- [ ] Add SQLite caching layer +- [ ] Iterate on remaining integrations + +## Reference Documentation +- Todoist API: https://developer.todoist.com/rest/v2 +- PlanToEat API: https://www.plantoeat.com/developers +- Trello API: https://developer.atlassian.com/cloud/trello/rest/api-group-actions +- HTMX: https://htmx.org/docs/ + +Endpoint design guidance for Claude Code: +Security + +Token auth in header: Authorization: Bearer (not query param - avoids URL logging) +Single read-only token - Generate once, store in your env vars and tell me separately +Rate limiting: 100 req/hour per token (I rarely need more than 1-2 calls per conversation) +No CORS needed - Server-to-server only +HTTPS only when deployed (Let's Encrypt via Caddy/Traefik) + +Response format +json{ +"generated_at": "2026-01-09T15:30:00Z", +"tasks": { +"today": [ +{ +"id": "task_123", +"content": "Review PRs", +"priority": 4, +"due": "2026-01-09T17:00:00Z", +"project": "Work", +"completed": false +} +], +"overdue": [...], +"next_7_days": [...] +}, +"meals": { +"today": { +"breakfast": "Oatmeal with protein powder", +"lunch": "Chicken salad", +"dinner": "Salmon with veggies" +}, +"next_7_days": [...] +}, +"notes": { +"recent": [ +{ +"title": "Sprint planning notes", +"modified": "2026-01-09T10:15:00Z", +"preview": "First 150 chars...", +"path": "work/sprint-planning.md" +} +] +}, +"trello_boards": [...] // optional +} +Efficiency + +Cache responses: 5min TTL in-memory, return cached JSON if token valid +Limit data volume: + +Tasks: Today + overdue + next 7 days only +Notes: 10 most recent only +Meals: Today + next 7 days +Total response < 100KB + + +Selective fields: Don't include full note content, just previews +Single endpoint: /api/claude/snapshot (not multiple endpoints) + +Error responses +json{ +"error": "unauthorized", +"message": "Invalid or missing token" +} +``` + +Standard HTTP codes: +- 200: Success +- 401: Invalid/missing token +- 429: Rate limit exceeded +- 500: Server error (with safe message, no stack traces) + +### Implementation hints for Claude Code: +``` +Create GET /api/claude/snapshot endpoint: +- Require Authorization: Bearer header +- Return cached JSON (5min TTL) with current state +- Include: today's tasks, overdue tasks, next 7 days tasks, today's meals, + next 7 days meals, 10 most recent notes +- Limit each note preview to 150 chars +- Total response should be < 100KB +- Use 401 for auth failures, 429 for rate limits +- Cache API responses to avoid hammering upstream services +``` + +### What I'll do: +When you give me the URL + token: +``` +My dashboard: https://dashboard.yourdomain.com/api/claude/snapshot +Token: +``` + +I'll call: +``` +web_fetch( +url="https://dashboard.yourdomain.com/api/claude/snapshot", +headers={"Authorization": "Bearer "} +) +Then parse JSON and use context naturally in our conversations. +Optional: Webhook for updates +If you want proactive notifications (e.g., "Pete, you have 3 overdue tasks"), add: + +POST endpoint to receive webhook URL from me (not implemented yet on my side) +Your dashboard posts to that URL when important state changes +Skip this for now - manual fetch is simpler -- cgit v1.2.3