# 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