Files
GarminSync/Design.md
2025-08-07 18:52:21 -07:00

4.4 KiB

GarminSync Application Design

Basic Info

App Name: GarminSync What it does: CLI application that downloads FIT files for every activity in Garmin Connect

Core Features

  1. List activities (garminsync list --all)
  2. List activities that have not been downloaded (garminsync list --missing)
  3. List activities that have been downloaded (garminsync list --downloaded)
  4. Download missing activities (garminsync download --missing)

Tech Stack

Frontend: CLI (Go) Backend: Go Database: SQLite (garmin.db) Hosting: Docker container Key Libraries: garminexport (Go), viper (env vars), cobra (CLI framework), go-sqlite3

Data Structure

Main data object:

Activity:
- activity_id: INTEGER (primary key, from Garmin)
- start_time: TEXT (ISO 8601 format)
- filename: TEXT (unique, e.g., activity_123_20240807.fit)
- downloaded: BOOLEAN (0 = pending, 1 = completed)

User Flow

  1. User launches container with credentials: sudo docker run -it --env-file .env garminsync
  2. User is presented with CLI menu of options
  3. User selects command (e.g., garminsync download --missing)
  4. Application executes task with progress indicators
  5. Application displays completion status and summary

File Structure

/garminsync
├── cmd/
│   └── root.go (CLI entrypoint)
│   └── list.go (activity listing commands)
│   └── download.go (download command)
├── internal/
│   ├── garmin/
│   │   ├── client.go (API integration)
│   │   └── activity.go (activity models)
│   └── db/
│       ├── database.go (embedded schema)
│       ├── sync.go (NEW: database synchronization)
│       └── migrations.go (versioned migrations)
├── Dockerfile
├── .env
└── README.md

Technical Implementation Notes

  • Architecture: Go-based implementation with Cobra CLI framework
  • Authentication: Credentials via GARMIN_EMAIL/GARMIN_PASSWORD env vars (never stored)
  • File naming: activity_{id}_{timestamp}.fit (e.g., activity_123456_20240807.fit)
  • Rate limiting: 2-second delays between API requests
  • Database: Embedded schema creation in Go code with versioned migrations
  • Docker:
    • All commands require sudo as specified
    • Fully containerized build process (no host Go dependencies)
  • Session management: Automatic cookie handling via garminexport with file-based persistence
  • Pagination: Implemented for activity listing
  • Package stability: Always use stable, released versions of packages to ensure reproducibility

Development Phases

Phase 1: Core Infrastructure - COMPLETE

  • Dockerfile creation
  • Environment variable handling (viper)
  • Cobra CLI framework setup
  • garminexport client initialization (with session persistence)

Phase 2: Activity Listing - COMPLETE

  • SQLite schema implementation
  • Activity listing commands
  • Database synchronization
  • List command UI implementation

Phase 3: Download Pipeline - COMPLETE

  • FIT file download implementation
  • Idempotent download logic (with exponential backoff)
  • Database update on success
  • Database sync integration

Phase 4: Polish

  • Progress indicators (download command)
  • Error handling (robust error recovery)
  • README documentation
  • Session timeout handling

Critical Roadblocks

  1. Rate limiting: Built-in 2-second request delays (implemented)
  2. Session management: Automatic cookie handling via garminexport (implemented)
  3. File conflicts: Atomic database updates during downloads (implemented)
  4. Docker permissions: Volume-mounted /data directory for downloads (implemented)
  5. Database sync: Efficient Garmin API ↔ local sync (implemented)

Current Status

Working on: Phase 4 - Final polish and error handling
Next steps:

  1. Fix command flag parsing issue
  2. Implement comprehensive error handling
  3. Complete README documentation
  4. Final testing and validation

Known issues:

  • Command flag parsing issue: The --all flag is not being recognized by the CLI. This appears to be related to how Cobra handles flags for subcommands. The root cause is being investigated.

Recent Fixes

  • Fixed package declaration conflicts in cmd/ directory (changed from package cmd to package main)
  • Removed unnecessary import in root.go that was causing build errors
  • Verified Docker build process now completes successfully