Commit graph

61 commits

Author SHA1 Message Date
Claude
ad3da57174 Fix: add backwards-compat CSS aliases for removed variable names
Theme overhaul removed --surface, --surface-2, --border, --r-md but
SettingsIntegrations.jsx and other pages still reference them. Cards
were rendering but invisible (transparent background/border).

Added aliases: --surface/--surface-2 → --card, --border → --card-border,
--r-md → --r
2026-07-13 22:20:08 +00:00
Claude
2411fc5b99 docs: add beta tester guide with Claude Desktop setup instructions 2026-07-05 01:13:18 +00:00
Claude
c37543b009 feat: timezone auto-detection, branding fix, frontend rebuild
Timezone:
- Add diligence/utils/dates.py with today_for_user(), now_for_user(), day_start_utc()
- Replace all 20 date.today() calls across 10 files with timezone-aware helpers
- Remove hardcoded Asia/Bangkok offset hack in nutrition router
- Change defaults from Asia/Bangkok to UTC in user model, nutrition model, config
- Add timezone field to RegisterRequest schema
- Set user.timezone from browser detection during registration
- Frontend sends Intl.DateTimeFormat().resolvedOptions().timeZone on register

Branding:
- Login page: Fitness Rewards -> Diligence, updated tagline and emoji
- index.html title: Fitness Rewards -> Diligence

Frontend rebuild:
- Fresh Vite build with all changes (index-CsKoBN0D.js)
- Nav bar, timezone detection, and branding all verified in built bundle
2026-07-04 07:16:23 +00:00
Claude
40c8485aa7 feat: MCP server for pip install path
- diligence/mcp/server.py: 14 MCP tools (adapted from mcp-connector/)
- diligence/mcp/__init__.py: background thread startup
- CLI starts MCP on port 3001 automatically (--no-mcp to disable)
- Graceful fallback if mcp package not installed
- Agent config endpoint returns correct port for pip path
2026-07-01 04:54:56 +00:00
Claude
df39a8dc08 feat: Agent Connect page + /api/agent/config endpoint
- New AgentConnect.jsx page with MCP URL, token, setup instructions
- Claude Desktop config snippet with copy button
- Claude Code CLI command with copy button
- Agent capabilities overview
- Added to bottom nav bar (6th item, plug icon)
- Backend /api/agent/config endpoint returns deployment-aware MCP details
- Nav padding adjusted for 6 items
- Frontend rebuilt with new page
2026-07-01 03:45:34 +00:00
Claude
a6e6e2f54f v2.0: dual deployment — pip install (SQLite) + Docker (PostgreSQL)
Architecture:
- Moved backend/app/ to diligence/ Python package
- Dialect-agnostic models (Uuid + JSON, no PostgreSQL imports)
- Auto-detect database: empty DATABASE_URL → SQLite at ~/.diligence/data.db
- Cross-dialect migrations (inspector-based, no raw PostgreSQL DDL)
- FastAPI serves pre-built React frontend for pip path
- CLI entry point: diligence [--port] [--no-browser] [--data-dir]
- pyproject.toml with optional deps: [postgres], [mcp], [dev]
- Docker path unchanged: docker compose up -d

pip install path: pip install . && diligence
Docker path: ./setup.sh && docker compose up -d
2026-07-01 03:30:12 +00:00
Claude
0ce1463de8 Fix setup.ps1: correct execution order and add API_TOKEN generation
Bug: API_TOKEN replacement ran before .env existed, and before the
existence check. On a clean clone the script errored immediately.

Fixed flow: banner → existence check → generate SECRET_KEY →
generate API_TOKEN → copy .env.example → replace both keys.

Also adds MCP connection info to output (matching setup.sh).
2026-06-26 23:37:11 +00:00
Claude
214e3e0111 Fix: AI chat router prefix /ai -> /api/ai (match other routers) 2026-06-22 00:29:52 +00:00
Claude
f2954af400 Fix: ai_provider reads actual DB schema (config_key/config_value rows)
Root cause: ai_provider.py assumed a single JSON blob in an
'encrypted_value' column, but IntegrationConfig stores each credential
as a separate row with config_key + config_value columns.

Fixes:
- Query groups rows by provider, decrypts each config_value separately
- Correct decrypt_value(secret_key, ciphertext) argument order
- Filter by user_id so providers are per-user
- Callers (ai_chat.py, chat()) now pass user_id through
2026-06-22 00:27:19 +00:00
Claude
5294745704 Fix: replace all settings.algorithm references with hardcoded ALGORITHM
SEC-11 removed algorithm from Settings but missed 3 call sites:
- auth.py line 68: jwt.decode in get_current_user
- integrations.py lines 58, 120: jwt.decode in OAuth callbacks

All now use ALGORITHM constant or inline 'HS256'.
2026-06-22 00:17:58 +00:00
Claude
4e8b321ef8 Fix: SyntaxError in main.py — comma after allow_credentials=False
The SEC-06 replacement swallowed the trailing comma into the comment:
  allow_credentials=False  # comment,  ← comma in comment
Fixed to:
  allow_credentials=False,  # comment  ← comma after value
2026-06-22 00:08:28 +00:00
Claude
d087e0a5a1 Fix: restore App.jsx and properly add ChatCoach import, route, nav
Previous commit wiped App.jsx due to emoji encoding error in the
patch script. Restored from Stream A commit (c075eb9), then applied
ChatCoach changes using a file-based Python script to handle unicode.

- import ChatCoach from './pages/ChatCoach' (line 21)
- NavLink /chat with brain emoji + 'Coach' label (line 95)
- Route /chat -> ProtectedRoute -> ChatCoach (line 125)
2026-06-22 00:03:43 +00:00
Claude
4eb70dc178 Deprioritize WHOOP: code against API docs, first user validates
WHOOP developer registration requires device ownership. Sync service
will be built against their documented API; first WHOOP-owning user
serves as the integration tester. Focus on Garmin and Oura first.
2026-06-21 23:51:30 +00:00
Claude
e9957c552a Add OUTSTANDING.md — remaining work for cofounder review 2026-06-21 23:36:14 +00:00
Claude
0670bca9b1 Stream C frontend: ChatCoach page, nav update, README with AI providers + agent configs
Frontend:
- ChatCoach.jsx: streaming chat UI with SSE, provider indicator, suggestion
  chips, 'no AI configured' state with setup link
- App.jsx: import + /chat route + nav bar (More → Coach with brain emoji)
- api.js: getAIStatus() method

Documentation:
- README.md: 'Built-in AI Coach' section with 8-provider table, external
  agent config snippets for Claude Desktop, Claude Code, Cursor, Windsurf,
  and COROS multi-MCP pattern
- AGENT_GUIDE.md: multi-device integration, Strava AI/ML warning,
  provider-agnostic statement

Nav bar: Home | Log | Keto | Programs | Coach
Settings still reachable at /settings (linked from Coach setup prompt)
2026-06-21 23:28:07 +00:00
Claude
3ab88a3d2a Stream B: Device sync base class + provider registry (already committed)
Abstract base class for device sync services (device_sync_base.py):
- Standard OAuth token management with automatic refresh
- Credential decryption from integration_configs table
- Activity import pipeline with deduplication by external_id
- Webhook validation and handling interface
- get_valid_token(), get_credentials(), import_activity() helpers

Garmin, WHOOP, and Oura sync service implementations follow when
API credentials are obtained (Scot action items):
- Apply for Garmin Developer Program (DiligenceWorks Pte. Ltd.)
- Register WHOOP developer app at developer.whoop.com
- Register Oura app at cloud.ouraring.com
2026-06-21 23:16:58 +00:00
Claude
9a8e6ce1eb Stream C: Multi-provider AI coaching backend + 20-provider registry
AI coaching service (backend/app/services/ai_provider.py):
- Two code paths: OpenAI-compatible (6 providers) + Anthropic (Claude)
- Streaming SSE responses via httpx async
- System prompt built from AGENT_GUIDE + live user context
- Graceful error handling for all provider failures
- Gemini adapter for Google's generateContent API

Chat endpoint (backend/app/routers/ai_chat.py):
- POST /api/ai/chat — SSE streaming response
- GET /api/ai/status — check configured provider
- History capped at 20 messages, content at 4K chars

Provider registry expanded to 20 providers:
- 9 device integrations (strava, polar, garmin, whoop, oura, coros, fitbit, withings, suunto)
- 8 AI providers (openai, openrouter, huggingface, groq, ollama, claude, gemini, custom_ai)
- 3 other (usda, nutritionix, telegram)
- Categorized: device, ai_provider, nutrition, notifications
- COROS: MCP bridge approach (no API integration needed)
- Strava: AI/ML warning per their ToS

Frontend ChatCoach.jsx to follow in next commit.
2026-06-21 23:16:17 +00:00
Claude
6e082ce58f Stream D: Security hardening — 10 fixes from QA review
- SEC-05: Fail fast if SECRET_KEY is default 'change-me-in-production'
- SEC-06: CORS allow_credentials=False (Bearer tokens don't need it)
- SEC-08: Input validation on auth schemas (min/max length, username pattern)
- SEC-10: .dockerignore files (root, backend, mcp-connector)
- SEC-11: Hardcode ALGORITHM='HS256' as constant, remove from settings
- CQ-01: Gate crawl scheduler on CRAWL_ENABLED env var (default false)
- OS-02: CONTRIBUTING.md
- OS-03: CHANGELOG.md with v1.0.0 entry
- setup.ps1: Add API_TOKEN generation (Windows parity with setup.sh)
2026-06-21 23:13:53 +00:00
Claude
c075eb9257 Stream A: DW brand theme — Instrument Sans + IBM Plex Mono, light/dark mode, all hardcoded colors replaced
- Replace Solar Momentum palette with DiligenceWorks brand identity
- Typography: Outfit → Instrument Sans, Plus Jakarta Sans → IBM Plex Mono (data/stats)
- CSS variables: --orange* → --accent*, new DW blue #2952CC / #6B9BFF
- Dark mode: prefers-color-scheme media query + manual data-theme override
- Border radii: 14/10/20px → 8/6/12px (professional, less playful)
- Font weights: 800/900 → 600/700 (DW uses lighter weights)
- Fixed 30+ hardcoded hex values across 16 files (UI-06)
- Gate banners, progress bars, category chips all use CSS variables
2026-06-21 23:12:25 +00:00
Claude
83e715dbc4 README: platform-specific install guides for Windows 11 (WSL2/Hyper-V/BIOS), macOS (Apple Silicon/Intel/Homebrew), Linux 2026-06-16 03:36:06 +00:00
Claude
dfc5ab3c9d Add Windows setup (setup.ps1), expand README with cross-platform install, Claude Desktop example, backup/restore, architecture diagram, .dockerignore 2026-06-16 03:25:03 +00:00
Claude
e34ae36774 Add navigation links to Settings page for Meal Plans, Integrations, Rewards, Week View 2026-06-16 02:04:44 +00:00
Claude
69320e1e82 Fix all 7 launch blockers from security/QA review
SEC-16: Add frontend ports mapping (80:80) to docker-compose.yml
UI-01:  Add routes for Welcome, SettingsIntegrations, MealPlan in App.jsx
SEC-01: Remove traceback leak from auth error responses
SEC-02: Fix require_admin to use is_admin column (was undefined ADMIN_USERNAME)
SEC-03: Add API_TOKEN auth for MCP connector -> backend communication
SEC-04: OAuth state now uses signed JWT tokens (was raw user UUID)
OS-01:  First registered user gets admin immediately during registration

10 files changed, 97 insertions(+), 25 deletions(-)
2026-06-16 01:50:09 +00:00
Claude
50eae17c34 Fix: split CREATE INDEX migration into separate statements (asyncpg multi-statement restriction) 2026-06-15 14:45:43 +00:00
Claude
c133a463ec Deliver Step 9: agent-card.json, SKILL.md, USDA lookup, integrations dynamic config, Welcome/Integrations/MealPlan pages, API methods, README, routes 2026-06-15 14:40:34 +00:00
Claude
6fb5d759ef Deliver Steps 3-8: integration config, meal plans, provider registry, MCP connector (14 tools), B2A files, nginx proxy, AGENT_GUIDE, LICENSE 2026-06-15 14:34:09 +00:00
Claude
cb892564d9 Deliver Step 1: Backend cleanup — secrets scrubbed, is_admin column, Telegram optional, crypto service, v4-v7 migrations, .env.example, setup.sh 2026-06-15 14:29:53 +00:00
Claude
8e630233f6 Add 3-day fast operational protocol (hour-by-hour) 2026-04-16 15:16:24 +00:00
Claude
d4bac82644 Week 1: bilingual EN/Thai meal plan with full recipes inline
Meal plan now includes:
- Bilingual headers throughout (day names, meal labels, notes)
- Full recipes for all 11 meals inline with bilingual ingredient tables
- Thai translation of every cooking step
- Bilingual prep schedule and substitution rules

Shopping list already had bilingual item tables; added Thai to intro and cost sections.
2026-04-16 14:28:11 +00:00
Claude
bd5f82cf3c Correct Week 1 budget with verified Makro Thailand prices
Previous estimate of ~8,500 baht was USA-centric. Real Makro pricing:
- Chicken thighs boneless trimmed: 40 THB/kg (was estimated ~5x higher)
- Pork shoulder: 100 THB/kg
- Salmon frozen: 380 THB/kg
- Coconut cream UHT 250ml: 30 THB
- Aro macadamia 500g: 400 THB

New totals: ~5500-6000 THB week 1 (one-off pantry), ~3500-4500 THB ongoing.
2026-04-12 12:11:29 +00:00
Claude
3e5f38fe5a Week 1 meal plan + shopping list (expanded to 34 dairy-free recipes)
- Rebuild recipes/INDEX.md with all 83 recipes from 9 sources
- Update recipes.json + CSV with new Whole30/Paleo additions
- Add content/meal-plans/week-01/MEAL-PLAN.md (4 new recipes integrated)
- Add content/meal-plans/week-01/SHOPPING-LIST.md (bilingual EN/Thai, Makro-organized)
- Commit .recipe-candidates-dairy-free.json for future crawls
2026-04-12 12:05:04 +00:00
Claude
32ec2b744e Add recipes.json + CSV extract for fitness app ingestion (64 recipes) 2026-04-12 10:57:16 +00:00
Claude
6cb025ed97 Add 64 keto recipes (crawled from Diet Doctor via JSON-LD, filtered by macros) 2026-04-12 10:48:38 +00:00
claude
5dd5d39ca6 Feature: nutrition module (keto macros + intermittent fasting + electrolytes)
Backend:
- models/nutrition.py: NutritionGoal, Fast, ElectrolyteLog tables
- schemas/nutrition.py: Pydantic schemas for new endpoints
- routers/nutrition.py: /api/nutrition/{today,goals,fasts,electrolytes}
- main.py: register router + migration for new tables + seed keto point rules

Frontend:
- pages/Nutrition.jsx: macro bars, fast timer, eating window, electrolyte quick-add
- App.jsx: /nutrition route + Keto nav tab
- api.js: nutrition endpoints

Points schema for fasts (tier-based partial credit):
16:8=25, 18:6=40, 20:4=60, 24h=200, 36h=350, 48h=500, 72h=1000

Defaults tuned for Scot: 135kg M 44yo strict keto, 12:00-20:00 window,
Asia/Bangkok timezone, 2400/2600 cal rest/training, 20g net carb cap.
2026-04-12 05:13:52 +00:00
claude
9a306bc250 Fix: program workout shortcut now appears under Workout category
Two bugs fixed:

1. Backend: list_programs endpoint did not include catalog_id in its
   response, so the frontend filter (p.catalog_id) always matched zero
   programs. The previous LogActivity card never rendered because
   loadActiveProgram() found no active program with a catalog link.
   Now also exposes current_week.

2. UX restructure: instead of showing the program workout card at the
   top of /log unconditionally, the card now appears AFTER the user
   selects the 'Workout' category — matching the natural flow:
   Log -> Workout -> see today's program workout option.

   The Workout category now reveals:
   - Active program banner (clickable, shows program name + week,
     navigates to ProgramDetail on tap)
   - Today's workout card with exercise preview and one-tap 75 pts
   - Other uncompleted workouts in the current week (up to 3)
   - 'Or log freeform' divider before the existing form

   When all workouts in the current week are done, a green completion
   banner appears instead.

Refactored the workout card into a ProgramWorkoutCard component since
it's now used for both today's featured workout and weekly upcoming.
2026-04-09 16:13:47 +00:00
claude
42797b5462 Feature: clickable program bar on Dashboard + program workout shortcut on Log page
Dashboard:
- The program bar at the top of the home page is now clickable and
  navigates to the program detail page. Backend get_today_status now
  returns program_id alongside name/day/total_days.

LogActivity:
- On mount, fetches the user's active catalog program and its today's
  workout. If there's an uncompleted non-rest workout for today, a
  featured 'Today's Program Workout' card appears at the top with an
  exercise preview and a one-tap '✓ Complete — 75 pts' button.
- Tapping Complete fires the same /workout/{id}/complete endpoint as
  ProgramDetail, surfaces weekly/completion bonuses in the success
  message, and returns to the Dashboard.
- The standard category grid below is now relabeled 'Or log something
  else' when a program workout is available.
2026-04-09 16:06:38 +00:00
claude
087b91bc42 Fix: bottom nav bar overlapping content on detail pages
CatalogDetail, ProgramDetail, ProgramSearch and SupportAdmin all use
inline-styled root divs instead of the .page CSS class, so they were
missing the padding-bottom: 96px that clears the fixed bottom nav bar.
Last button/section was hidden behind the nav.

Adds paddingBottom: 96px to each page's root div. Support.jsx has its
own full-height chat layout and is intentionally left as-is.
2026-04-09 16:02:21 +00:00
claude
dddd308ff7 Fix: rotate template workouts across all program weeks (Bug 2)
Catalog stores only the template (typically week 1) but programs span
many weeks. The schedule endpoint was returning only the literal stored
rows, so after day 3 of StrongLifts a user would see no upcoming
workout despite being mid-program.

Changes:
- Add week_number column to workout_logs (migration in main.py) so the
  same template workout can be completed once per real week
- Synthetic workout IDs: '{template_uuid}::{real_week}' — frontend
  treats opaquely, backend parses on every endpoint
- get_program_schedule rotates the template across catalog.duration_weeks
  real weeks and returns synthetic IDs
- today_workout: first uncompleted non-rest entry in current real week
  (more flexible than literal day-of-week match)
- complete_workout / get_workout_detail parse synthetic IDs and track
  completion per (template_id, real_week) pair
- check_weekly_bonus filters by workout_logs.week_number for the real week
- check_completion_bonus and progress endpoint compute total as
  template_per_week * total_weeks, not just template count
2026-04-09 15:55:22 +00:00
claude
67b539f68a Fix: add CatalogDetail page and /catalog/:id route
The 'View Details' button on ProgramSearch navigated to /catalog/:id
but no route or page existed. Now creates a proper detail view that
fetches via getCatalogProgram, shows program metadata, weeks/workouts,
progression rules, and an Adopt button that redirects to the user's
new program tracking page on success.
2026-04-09 15:52:03 +00:00
claude
10f13a9f62 v2: In-app support chat with Telegram notifications (REVIEW — not deployed)
Backend:
- New models: SupportThread, SupportMessage (models/support.py)
- Support router: user thread/messages, admin threads/reply, Telegram outbound
- Context auto-attached: active program, points, gate status, last workout
- Rate limited: 10 messages/user/day
- Admin auth: username == 'scot' check
- Telegram: fire-and-forget sendMessage via @AureusGoldBot, never blocks
- config.py: added telegram_bot_token, telegram_chat_id

Frontend:
- Support.jsx: chat-style thread, send messages, confirmation, auto-scroll
- SupportAdmin.jsx: thread list with unread badges, thread detail with context sidebar, reply
- App.jsx: floating '?' help button with unread badge (polls every 60s), routes
- api.js: support endpoints (user + admin)

Config:
- docker-compose.yml: TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID env vars

NOT DEPLOYED — requires Telegram env vars in Coolify
2026-04-06 04:44:29 +00:00
claude
42632b1b50 Add PHUL and Darebee Foundation Light to known program sources 2026-04-03 16:53:23 +00:00
claude
ac075104da Fix: settings.groq_api_key lowercase (pydantic field naming) 2026-04-03 16:44:14 +00:00
claude
6ae6a640f3 Fix: register catalog router before programs router to prevent /catalog path being caught by /{program_id} 2026-04-03 16:32:26 +00:00
claude
93f24fff83 v2: Program research, Groq extraction, and workout tracking (REVIEW — not deployed)
Backend:
- New models: ProgramCatalog, CatalogWorkout, CrawlQueue, WorkoutLog
- Program.py: added catalog_id, current_week, current_day columns
- program_research.py: ttp-crawler integration, Groq Llama 3.3 70B extraction, known sources map, validation
- crawl_scheduler.py: priority queue with off-peak/weekend scheduling
- catalog.py router: research, catalog browse, adopt, schedule, complete, progress endpoints
- Points: 75pts/workout, 50pts weekly bonus, 200pts completion bonus
- config.py: added groq_api_key setting
- main.py: catalog router, background scheduler, v2 migration

Frontend:
- ProgramSearch.jsx: search, research submission, catalog browsing, adopt programs
- ProgramDetail.jsx: schedule view, today's workout, completion modal, progress tracking
- App.jsx: Programs nav tab, new routes
- api.js: catalog and tracking API functions

Config:
- docker-compose.yml: GROQ_API_KEY env var

NOT DEPLOYED — requires Groq API key and Scot review
2026-04-03 16:22:53 +00:00
claude
a81ca9c275 Add startup migration for equipment_list column on existing tables 2026-03-15 23:23:19 +00:00
claude
82c4533a96 Feature: expanded equipment, integration-aware sync, tooltips
1. Equipment (onboarding step 5):
   - Changed from 3 radio buttons to 14 multi-select chips
   - Bicycle, pool, free weights, squat rack, bench press, machines,
     resistance bands, pull-up bar, kettlebell, jump rope, yoga mat,
     treadmill, stationary bike, rowing machine
   - Backend: equipment_list JSONB field on profile model
   - Resource matcher updated to filter by specific equipment
   - Legacy equipment_access auto-derived for backward compat

2. Sync Strava/Polar (dashboard):
   - Fetches integration status on load
   - Shows 'Connect Strava/Polar' (dashed border) when not connected
   - Shows 'Sync Strava/Polar' only when connected
   - Connect button triggers OAuth flow
   - Sync shows loading state and result count

3. Tooltips:
   - Tip component: hover/click to show explanation bubble
   - Added to: goals, TTM stages, PAR-Q+, BREQ-2 items,
     equipment, rewards gate, daily points, activity checklist,
     weekly progress, integrations section
   - Science references: TTM, PAR-Q+, BREQ-2/RAI explained
2026-03-15 22:16:55 +00:00
claude
434db38f0d Fix: rename db -> fitness-db to avoid DNS collision with Coolify's postgres
ROOT CAUSE FOUND: 'db' resolved to multiple IPs on the Docker network.
Coolify's own PostgreSQL (or another stack's) also responds to 'db'
via the predefined network. Our backend was connecting to the WRONG
postgres — one that requires password auth.

Fix: rename service from 'db' to 'fitness-db' so the hostname is unique.
2026-03-15 21:54:51 +00:00
claude
25d15c38ce Bake all env vars into backend Dockerfile - bypass Coolify env handling entirely
Coolify's compose env var passing is unreliable. Moving all config
to Dockerfile ENV directives guarantees the values are present
regardless of how Coolify handles the compose file.
2026-03-15 21:20:00 +00:00
claude
c386befad2 Fix root cause: config.py default had password 'fitness', DB uses trust auth
The actual bug: config.py default database_url included ':fitness' password.
When Coolify doesn't pass DATABASE_URL env var to the container,
pydantic_settings falls back to this default, which PostgreSQL rejects
because the DB initialized with trust authentication (no password).

Fix: removed password from default database_url in config.py.
Also removed unnecessary custom db/Dockerfile.
2026-03-15 12:33:25 +00:00
claude
3684e50ac6 Fix DB auth: custom Dockerfile bakes trust auth into postgres image
Coolify strips environment variables from image-only services,
so POSTGRES_HOST_AUTH_METHOD=trust never reached the container.
Solution: build a custom DB image with trust auth baked in via
Dockerfile ENV + init script that rewrites pg_hba.conf.
2026-03-15 12:28:25 +00:00