Commit graph

35 commits

Author SHA1 Message Date
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
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
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
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
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
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
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
ea1c4f4f52 Fix DB auth: use trust auth (no password) - Coolify strips POSTGRES_PASSWORD env var
Coolify does not pass environment variables to non-build services (image-only).
PostgreSQL initializes with trust authentication by default in this case.
Solution: connect without password, explicitly set POSTGRES_HOST_AUTH_METHOD=trust.
Also removed debug endpoint.
2026-03-15 12:16:58 +00:00
claude
df03ec24ee Temp: add debug env endpoint to diagnose Coolify env var issue 2026-03-15 12:15:23 +00:00
claude
d79129efc2 Fix: replace passlib with bcrypt directly - passlib incompatible with bcrypt 4.x 2026-03-15 01:35:46 +00:00
claude
2488dc4daf Debug: add traceback to register/login error responses to diagnose 500 2026-03-15 00:47:29 +00:00
claude
7846e3445d Fix: add future annotations to all files, fix date field name shadowing type in RewardRedeemRequest 2026-03-15 00:42:13 +00:00
claude
16d00fbd1b Fix backend startup: add retry logic for DB init, proper logging, ensure all models imported before create_all, increase healthcheck start_period 2026-03-15 00:34:39 +00:00
claude
00c58c6f62 Fix docker-compose for Coolify: remove manual Traefik labels, add healthchecks, add curl to containers 2026-03-15 00:23:35 +00:00
claude
4db2b0846b Initial commit: full fitness-rewards app
Backend: FastAPI + PostgreSQL + SQLAlchemy async
- Auth (JWT), onboarding (PAR-Q+, TTM, BREQ-2), activities, food log
- Points engine with daily gate + weekly targets
- Strava + Polar OAuth integration
- Open Food Facts barcode lookup
- Resource recommendation engine
- 10 seeded Darebee/StrongLifts/YouTube programs

Frontend: React + Vite, mobile-first dark theme
- Login/Register, 8-step onboarding flow
- Dashboard with daily gate status
- Activity logger, food logger (manual + barcode scan + search)
- Reward shop with redemption
- Weekly summary view
- Settings (point rules, targets, integrations)

Deployment: Docker Compose for Coolify (Traefik)
2026-03-14 23:53:00 +00:00