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
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
- The job execution layer via Background jobs dispatches asynchronous work through a registry-based system, supporting both inline execution and SQS-backed task queues for Garmin ingestion, AI digest refresh, and todo suggestion generation.[7] (see Background jobs)
- The visual layer via Visual design system defines Monet-inspired light and dark themes with moment-specific palettes, semantic color tokens, and layered pixel sprites, complemented by Pixel assets sprite collections and texture files.[8] (see Visual design system, Pixel assets)
- The frontend layer comprises React components split across pages—Today, Body, Read, and Calendar—organized with Layout and navigation providing responsive navigation shells, settings, and theme control. (see Layout and navigation, Dashboard and today page, Body page)
- The API layer routes incoming requests through FastAPI in API server, which coordinates authentication, logging, middleware, and delegation to feature-specific routers for nutrition, todos, and Garmin endpoints.[9] (see API server, Nutrition tracking, Todo management)
- The application services layer includes Monet assistant for AI chat routing, iMessage integration for message sync and action extraction, and Claude code integration for session tracking. (see Monet assistant, iMessage integration, Claude code integration)
- The data layer comprises PostgreSQL tables created and evolved through Database migrations using Alembic, storing users, activities, metrics, nutrition data, todos, calendar events, and journal entries, with optional DynamoDB and S3 via Configuration for key-value caching and blob storage.[10] (see Database migrations, Configuration)
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/profileto 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 thecalendar_eventtable, 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/refreshcalls 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.migrateagainst Alembic migrations inbackend/migrations/versions/, enabling schema evolution across deployments.[36] - CI/CD pipelines in
.github/workflows/run tests on push, deploy viacdk deployto AWS on manual trigger, and maintain a legacy EC2 docker-compose path as a rollback fallback with artifacts indocker/docker-compose.prod.ymlanddeploy/deploy_prod.sh.[37][38][39]
References
-
^
README.md:L7-10@e662257 -
^
README.md:L9@e662257 -
^
README.md:L8@e662257 -
^
README.md:L13-14@e662257 -
^
README.md:L14@e662257 -
^ a b
README.md:L15@e662257 -
^
README.md:L33-34@e662257 -
^
README.md:L17@e662257 -
^
README.md:L23@e662257 -
^
README.md:L24@e662257 -
^
frontend/src/pages/Today.tsx:L106@e662257(TodayPage) -
^
backend/app/routers/ai_digest.py:L17-21@e662257(get_today_digest) -
^ a b
backend/app/routers/nutrition.py:L45@e662257(router) -
^
backend/app/routers/todos_batch.py:L21@e662257(router) -
^
frontend/src/pages/FoodManagerPage.tsx:L19@e662257(FoodManagerPage) -
^
docs/deploy-serverless.md:L29-30@e662257 -
^
backend/app/aws/worker_handler.py:L21-22@e662257(handler) -
^
backend/app/routers/calendar.py:L40@e662257(router) -
^
backend/app/routers/assistant.py:L15-20@e662257(monet_message) -
^
backend/app/routers/ai_digest.py:L47-51@e662257(refresh_digest) -
^
backend/app/main.py:L25@e662257 -
^
backend/app/routers/__init__.py:L1@e662257 -
^
backend/app/services/monet_assistant.py:L16-26@e662257 -
^
backend/app/db/models/nutrition.py:L21-24@e662257 -
^
backend/app/services/imessage_processing_service.py:L29-30@e662257 -
^
frontend/src/components/common/Card.test.tsx:L6@e662257 -
^
frontend/src/components/dashboard/DashboardNutritionSnapshot.tsx:L5-6@e662257 -
^
frontend/src/components/news/CategoryStrip.tsx:L3@e662257 -
^
backend/app/db/models/base.py:L9@e662257 -
^
backend/app/db/models/journal.py:L10@e662257 -
^
backend/app/routers/todos.py:L24@e662257 -
^
infra/app.py:L9-12@e662257 -
^
docs/deploy-serverless.md:L8-36@e662257 -
^
docs/deploy-serverless.md:L29-32@e662257 -
^
docs/deploy-serverless.md:L45-46@e662257 -
^
docs/deploy-serverless.md:L33-35@e662257 -
^
.github/workflows/ci.yml:L1@e662257 -
^
.github/workflows/deploy-serverless.yml:L1@e662257 -
^
README.md:L50-57@e662257
This page was last edited on 8 June 2026, at commit e662257.