Back to Developer Logs

Build Log — January 23, 2026

Build Log — January 23, 2026

Context / Focus for Today

Major focus on enhancing Garmin activity metrics extraction and fixing training load calculations. Added comprehensive metrics from webhook data, fixed authentication issues across multiple API endpoints, and improved activity display for different sports.


Things I Got Done Today

Garmin Activity Metrics Enhancement

Comprehensive Metrics Extraction

  • Enhanced webhook activity extractor to capture all available Garmin metrics:
    • Max speed, elevation loss/gain
    • Cadence (running and cycling)
    • Power metrics (avg/max/normalized)
    • Device name
    • Starting location coordinates
  • Compute lap metrics from webhook samples when laps only have timestamps
  • Added "Imported from Garmin" branding with logo in activity stats modal header

Missing Metrics Fields

  • Fixed cadence field name: Garmin uses averageRunCadenceInStepsPerMinute
  • Added maxPaceInMinutesPerKilometer
  • Added maxRunCadenceInStepsPerMinute
  • Added startingLatitudeInDegree and startingLongitudeInDegree for location data

Sport-Specific Display

  • Bike activities now show "Avg Speed" in mph/km/h instead of pace
  • More intuitive display for cyclists vs runners

Training Load Fixes

Authentication Headers

  • Added auth headers to all training load API calls:
    • TrainingLoadChart.tsx
    • CalendarRecoveryBadge.tsx
    • TrainingCalendarApp.tsx (MobileDashboardContent)
  • Fixed auth waiting: ensure auth is ready before fetching training load

Database Field Mapping

  • Fixed field mapping in /api/training/load for CTL/ATL/TSB calculation:
    • Convert duration_minutes to seconds
    • Convert distance_km to meters
    • Map sport_type to sport
    • Add title/description/actual_metrics mapping
    • Use existing TSS if available before calculating
  • Same mapping fixes applied to /api/training/projection

Query Fixes

  • Removed non-existent columns from training load queries
  • Fixed Supabase import path

Garmin Sync Improvements

Sync Status Auth

  • SyncMenu now passes Authorization header to /api/sync/status
  • Added top-level try-catch in sync-stream route for better error reporting

Webhook Processing

  • Simplified sync logic to always extract from webhooks (let upsert dedupe)
  • Fixed metrics not being saved for new workout inserts
  • Fixed TypeScript error in webhook lap metrics computation

Housekeeping

  • Removed accidental nul file artifact from repo

Administrative

  • Responded to Garmin team for production API access application

In Progress

  • Garmin production access application (awaiting Garmin team response)
  • Training load visualization refinements
  • Activity metrics display improvements

Targets for Tomorrow

  1. Device name display — Show Garmin device name in activity stats
  2. Monitor training load — Verify CTL/ATL/TSB calculations are accurate
  3. Garmin production access — Follow up if needed
  4. Weekly summary toggle — Test and refine calendar totals feature

Notes / Observations

  • Garmin webhook data contains rich metrics but field names vary by activity type
  • Authentication headers were missing from several training load endpoints - caused silent failures
  • Field mapping between database and internal types is critical for accurate calculations
  • Running vs cycling need different metric displays (pace vs speed)
  • Lap-level metrics needed computation from samples when only timestamps provided
  • Production API access is required for broader user access to Garmin integration

Momentum Score: 8 / 10

Solid day focused on data quality and reliability. Significantly improved Garmin metrics extraction with comprehensive field coverage. Fixed critical authentication issues across training load endpoints that were causing silent failures. Added proper field mapping for accurate TSS/CTL/ATL calculations. Sport-specific display improvements make the app more intuitive. Good progress on administrative tasks with Garmin production access application.