Life Dashboard

From the Life-Dashboard wiki

Life Dashboard is a self-hosted wellness application that aggregates health metrics from Garmin, tracks nutrition intake, and surfaces AI-generated insights through a Monet-inspired interface designed to feel like a living pond with soft layers and pixel textures. It provides a unified view of daily health data, upcoming calendar events, and todo items through a homepage dashboard, and exposes specialized pages for nutrition tracking, news reading, journaling, and task management. The application deploys as a serverless stack on AWS Lambda, API Gateway, and Fargate with a React frontend, FastAPI backend, and PostgreSQL database, supporting both cloud and local development modes. Users can log food intake, view metrics trends, chat with an AI assistant, sync Google Calendar events, and ingest data from iMessage and Claude Code conversations.

flowchart LR
  n1[["AI digest"]]
  n2[["API server"]]
  n3[["Background jobs"]]
  n4[["Body page"]]
  n5[["Calendar integration"]]
  n6[["Claude code integration"]]
  n7[["Configuration"]]
  n8[["Dashboard and today page"]]
  n9[["Database migrations"]]
  n10[["Documentation"]]
  n11[["Garmin integration"]]
  n12[["iMessage integration"]]
  n13[["Infrastructure"]]
  n14[["Insights"]]
  n15[["Journal"]]
  n16[["Layout and navigation"]]
  n17[["Monet assistant"]]
  n18[["News feed"]]
  n19[["Nutrition tracking"]]
  n20[["Pixel assets"]]
  n21[["Read page"]]
  n22[["Screenshots and media"]]
  n23[["Todo management"]]
  n24[["Visual design system"]]
  n25[["Workspace management"]]
  n2 -->|"19 calls, 22 imports"| n23
  n16 -->|"19 calls, 22 imports"| n8
  n17 -->|"29 calls, 9 imports"| n19
  n19 -->|"21 calls, 17 imports"| n23
  n12 -->|"16 calls, 16 imports"| n23
  n4 -->|"13 calls, 17 imports"| n8
  n11 -->|"18 calls, 12 imports"| n23
  n2 -->|"7 calls, 19 imports"| n7
  n21 -->|"14 calls, 11 imports"| n18
  n17 -->|"10 calls, 12 imports"| n23
  n3 -->|"13 calls, 8 imports"| n23
  n15 -->|"11 calls, 9 imports"| n23
  n3 -->|"12 calls, 7 imports"| n7
  n5 -->|"6 calls, 10 imports"| n8
  n21 -->|"3 calls, 12 imports"| n8
  n14 -->|"8 calls, 6 imports"| n8
  n18 -->|"8 calls, 6 imports"| n8
  n12 -->|"12 imports"| n7
  n14 -->|"5 calls, 6 imports"| n4
  n15 -->|"6 calls, 5 imports"| n8
  n25 -->|"4 calls, 7 imports"| n23
  n14 -->|"4 calls, 6 imports"| n16
  n17 -->|"8 calls, 2 imports"| n12
  n23 -->|"6 calls, 4 imports"| n3
  n8 -->|"3 calls, 6 imports"| n4
  n12 -->|"4 calls, 5 imports"| n5
  n16 -->|"1 call, 8 imports"| n4
  n2 -->|"2 calls, 6 imports"| n19
  n3 -->|"3 calls, 5 imports"| n19
  n4 -->|"4 calls, 4 imports"| n16
  n8 -->|"2 calls, 6 imports"| n18
  n11 -->|"1 call, 7 imports"| n7
  n12 -->|"2 calls, 6 imports"| n19
  n16 -->|"3 calls, 5 imports"| n21
  n19 -->|"4 calls, 4 imports"| n12
  n23 -->|"5 calls, 3 imports"| n5
  n25 -->|"2 calls, 6 imports"| n7
  n14 -->|"1 call, 6 imports"| n24
  n16 -->|"2 calls, 5 imports"| n24
  n23 -->|"3 calls, 4 imports"| n12
  n25 -->|"5 calls, 2 imports"| n3
  n1 -->|"3 calls, 3 imports"| n23
  n5 -->|"4 calls, 2 imports"| n11
  n5 -->|"2 calls, 4 imports"| n23
  n6 -->|"2 calls, 4 imports"| n23
  n17 -->|"2 calls, 4 imports"| n5
  n18 -->|"5 calls, 1 import"| n12
  n19 -->|"1 call, 5 imports"| n7
  n23 -->|"6 imports"| n7
  n2 -->|"2 calls, 3 imports"| n3
  n7 -->|"5 imports"| n23
  n12 -->|"1 call, 4 imports"| n15
  n17 -->|"5 imports"| n7
  n17 -->|"2 calls, 3 imports"| n25
  n2 -->|"1 call, 3 imports"| n11
  n3 -->|"2 calls, 2 imports"| n1
  n3 -->|"1 call, 3 imports"| n11
  n5 -->|"4 imports"| n7
  n8 -->|"2 calls, 2 imports"| n14
  n11 -->|"2 calls, 2 imports"| n19
  n16 -->|"2 calls, 2 imports"| n14
  n1 -->|"2 calls, 1 import"| n3
  n1 -->|"2 calls, 1 import"| n12
  n2 -->|"2 calls, 1 import"| n12
  n3 -->|"1 call, 2 imports"| n15
  n7 -->|"3 imports"| n11
  n8 -->|"3 imports"| n16
  n11 -->|"1 call, 2 imports"| n2
  n12 -->|"3 imports"| n6
  n15 -->|"1 call, 2 imports"| n5
  n15 -->|"1 call, 2 imports"| n12
  n17 -->|"1 call, 2 imports"| n2
  n19 -->|"3 imports"| n6
  n21 -->|"3 imports"| n4
  n21 -->|"1 call, 2 imports"| n16
  n23 -->|"3 imports"| n2
  n23 -->|"3 imports"| n6
  n23 -->|"3 imports"| n11
  n25 -->|"2 calls, 1 import"| n5
  n2 -->|"2 imports"| n5
Each box is a feature; an arrow points from the feature whose code calls or imports to the one it uses.

Purpose and features

The dashboard displays a morning brief synthesized from Garmin readiness data, upcoming calendar events, open todos, and nutrition progress, with responsive layouts for mobile and desktop.[1] (see Dashboard and today page) Nutrition tracking lets users log food from meal suggestions, track macros and micronutrients against daily goals, and view 14-day rolling averages with ingredient and recipe management.[2] (see Nutrition tracking, Body page) Insights surfaces heart-rate variability, resting heart rate, sleep duration, and training load as 14-day trend charts with daily annotations derived from Garmin data.[3] (see Insights) Calendar integration syncs Google Calendar events, deduplicates them across calendars, and links them to todos through webhook-driven incremental sync.[4] (see Calendar integration)

Garmin integration fetches activity, readiness, wellness, and daily metrics from Garmin Connect and persists them via an encrypted database-backed token store.[5] (see Garmin integration) Monet assistant routes user messages to domain-specific tools for nutrition logging and todo creation, with context from the user's calendar, projects, and metrics.[6] (see Monet assistant) AI digest aggregates technical news from nine RSS feeds, classifies items by topic, and enriches them with LLM-generated summaries available through /ai-digest endpoints.[6] (see AI digest) iMessage integration copies messages from macOS, resolves contacts, extracts todos and journal entries from content, and matches completion messages to previously created tasks. (see iMessage integration)

Journal records daily entries with completed tasks and calendar events, surfaced through a book-style UI with weekly and daily views. (see Journal) News feed learns from user reads and dismissals to build an interest profile that decays across three temporal layers, allowing topic tuning to refine the feed. (see News feed)

Layers

Request paths

  • A user requests the dashboard homepage at / (frontend entry point Today.tsx), which calls backend routes /api/ai-digest/today, /api/nutrition/intake/daily, /api/todos, and /api/user/profile to populate brief, todo list, and nutrition cards, coordinating API server, AI digest, Nutrition tracking, Todo management, and Garmin integration.[11][12][13][14]
  • A food logging flow starts in FoodManager.tsx which calls POST /api/nutrition/intake/manual (routed through Nutrition tracking), which persists an intake entry and computes daily and rolling averages by summing nutrient contributions from ingredients or recipe components.[15][13]
  • A Garmin sync initiated via Background jobs calls app.aws.scheduled_handler.garmin_ingest(), which instantiates GarminClient to fetch activities from Garmin Connect, persists them via MetricsService, and stores readiness narratives in AI digest tables.[16][17]
  • A calendar sync webhook from Google triggers /calendar/google/webhook, routed through Calendar integration, which fetches events via the sync client, deduplicates them, updates the calendar_event table, and crosses to Todo management to link matching todos.[18]
  • A user message to the Monet assistant at POST /monet-message (Monet assistant) routes through MonetAssistant to tool agents (nutrition or todo), which call Nutrition tracking or Todo management services, and return composed replies enriched with context from Calendar integration and Insights.[19]
  • An AI digest refresh via POST /ai-digest/refresh calls AIDigestService to fetch and parse RSS feeds, classify items by topic, enrich with LLM summaries, and store them in the digest table, with processed items surfacing in the Read page UI.[20]

Feature dependencies

  • API server depends on Todo management, Nutrition tracking, Calendar integration, Garmin integration, AI digest, Journal, Monet assistant, News feed, and Workspace management for route coordination.[21][22]
  • Monet assistant depends on Nutrition tracking, Todo management, Calendar integration, iMessage integration, and Workspace management to provide context and execute domain-specific actions.[23]
  • Nutrition tracking depends on Todo management for ingredient and recipe models, Calendar integration for context in insight service, iMessage integration for action extraction, and Monet assistant for LLM-assisted parsing.[24]
  • iMessage integration depends on Todo management, Calendar integration, Journal, Nutrition tracking, and Workspace management to create todos, calendar events, journal entries, and project notes from message content.[25]
  • Layout and navigation depends on Dashboard and today page, Body page, Calendar integration, Insights, Read page, and News feed through imports and route structure.[26]
  • Dashboard and today page depends on Body page, Insights, News feed, Calendar integration, and Journal to populate nutrition, chart, news, event, and daily summary widgets.[27]
  • Read page depends on News feed, Body page, and Dashboard and today page for article curation, topic tuning, and layout components.[28]
  • Garmin integration depends on Todo management, Nutrition tracking, and Configuration for token storage, metrics persistence, and credential management.[29]
  • Journal depends on Todo management, Calendar integration, iMessage integration, Nutrition tracking, and Background jobs to compile entries with completed tasks, events, and activity context.[30]
  • Todo management depends on Calendar integration to link todos with calendar events and Monet assistant for task suggestion and accomplishment generation.[31]

Infrastructure

  • The serverless stack defined in infra/app.py synthesizes four CDK stacks: Foundation (VPC, secrets, Postgres connection), Compute (API Lambda, job lambdas, SQS worker), CloudFront distribution, and local LocalStack simulation for development.[32][33]
  • Async job workers are scheduled via EventBridge cron rules (Garmin sync at 09:00 UTC daily, AI digest every 6 hours) and SQS queues (background tasks with batch size 10 and partial-batch-failure reporting) on separate Lambda functions sharing the same container image.[34]
  • All Lambdas connect to Neon PostgreSQL over TLS without VPC, cache key-value data and secrets in DynamoDB, and store blob assets in S3, with a shared async SQLAlchemy engine initialized once per cold start to reuse connection pools.[35]
  • Database schema changes are applied via ECS Fargate one-shot tasks running python -m app.aws.migrate against Alembic migrations in backend/migrations/versions/, enabling schema evolution across deployments.[36]
  • CI/CD pipelines in .github/workflows/ run tests on push, deploy via cdk deploy to AWS on manual trigger, and maintain a legacy EC2 docker-compose path as a rollback fallback with artifacts in docker/docker-compose.prod.yml and deploy/deploy_prod.sh.[37][38][39]

References

  1. ^ README.md:L7-10@e662257
  2. ^ README.md:L9@e662257
  3. ^ README.md:L8@e662257
  4. ^ README.md:L13-14@e662257
  5. ^ README.md:L14@e662257
  6. ^ a b README.md:L15@e662257
  7. ^ README.md:L33-34@e662257
  8. ^ README.md:L17@e662257
  9. ^ README.md:L23@e662257
  10. ^ README.md:L24@e662257
  11. ^ frontend/src/pages/Today.tsx:L106@e662257 (TodayPage)
  12. ^ backend/app/routers/ai_digest.py:L17-21@e662257 (get_today_digest)
  13. ^ a b backend/app/routers/nutrition.py:L45@e662257 (router)
  14. ^ backend/app/routers/todos_batch.py:L21@e662257 (router)
  15. ^ frontend/src/pages/FoodManagerPage.tsx:L19@e662257 (FoodManagerPage)
  16. ^ docs/deploy-serverless.md:L29-30@e662257
  17. ^ backend/app/aws/worker_handler.py:L21-22@e662257 (handler)
  18. ^ backend/app/routers/calendar.py:L40@e662257 (router)
  19. ^ backend/app/routers/assistant.py:L15-20@e662257 (monet_message)
  20. ^ backend/app/routers/ai_digest.py:L47-51@e662257 (refresh_digest)
  21. ^ backend/app/main.py:L25@e662257
  22. ^ backend/app/routers/__init__.py:L1@e662257
  23. ^ backend/app/services/monet_assistant.py:L16-26@e662257
  24. ^ backend/app/db/models/nutrition.py:L21-24@e662257
  25. ^ backend/app/services/imessage_processing_service.py:L29-30@e662257
  26. ^ frontend/src/components/common/Card.test.tsx:L6@e662257
  27. ^ frontend/src/components/dashboard/DashboardNutritionSnapshot.tsx:L5-6@e662257
  28. ^ frontend/src/components/news/CategoryStrip.tsx:L3@e662257
  29. ^ backend/app/db/models/base.py:L9@e662257
  30. ^ backend/app/db/models/journal.py:L10@e662257
  31. ^ backend/app/routers/todos.py:L24@e662257
  32. ^ infra/app.py:L9-12@e662257
  33. ^ docs/deploy-serverless.md:L8-36@e662257
  34. ^ docs/deploy-serverless.md:L29-32@e662257
  35. ^ docs/deploy-serverless.md:L45-46@e662257
  36. ^ docs/deploy-serverless.md:L33-35@e662257
  37. ^ .github/workflows/ci.yml:L1@e662257
  38. ^ .github/workflows/deploy-serverless.yml:L1@e662257
  39. ^ README.md:L50-57@e662257

This page was last edited on 8 June 2026, at commit e662257.