Skip to content

ebelo/qfit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

442 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qfit

Explore fitness activity data spatially in QGIS.

qfit is a QGIS plugin that turns synced fitness activities into GeoPackage-backed layers, analysis views, and atlas-ready publish data for mapping and print workflows.

This README is split into two parts:

  1. Part 1, for human readers using qfit in QGIS
  2. Part 2, for contributors and AI coding agents changing the codebase

Part 1, for human readers

What qfit does today

qfit currently supports:

  • connecting to Strava with client_id, client_secret, and refresh_token
  • opening the Strava authorize page from the plugin and exchanging an auth code for a refresh token
  • fetching activities from Strava in the background
  • previewing fetched activities in the dock before writing anything to disk
  • storing a canonical local GeoPackage sync store
  • loading QGIS layers for tracks, start points, and optional sampled stream points
  • filtering by activity type, text search, date range, distance, and detailed-stream availability
  • applying visualization presets, optional temporal wiring, and an optional Mapbox basemap
  • running analysis workflows such as frequent starting points and activity heatmaps
  • generating atlas-ready publish layers and exporting a PDF atlas from the dock

Main outputs

qfit uses a GeoPackage as both local sync store and QGIS data source.

Internal tables

  • activity_registry
  • sync_state

Visible layers

  • activity_tracks
  • activity_starts
  • activity_points (optional, derived from detailed streams)
  • activity_atlas_pages

Atlas helper tables

  • atlas_document_summary
  • atlas_cover_highlights
  • atlas_page_detail_items
  • atlas_toc_entries
  • atlas_profile_samples

Typical workflow

  1. Configure Strava credentials.
  2. Fetch activities and preview the result in the dock.
  3. Choose an output .gpkg and store the data.
  4. Load the qfit layers into QGIS.
  5. Apply visualization or analysis workflows.
  6. Optionally generate atlas-ready publish data and export a PDF atlas.

Strava credentials

You need:

  • client_id
  • client_secret
  • refresh_token

qfit includes a built-in OAuth helper for the refresh-token step.

See:

  • docs/strava-setup.md

Background maps and styling

qfit can load an optional Mapbox basemap and keep it below the qfit layers in the QGIS layer tree.

The current visualization flow supports:

  • semantic activity styling by activity type
  • simpler line-based presets
  • track points / start points / heatmap-oriented views
  • temporal timestamp wiring when timestamp fields are available

See:

  • docs/map-style-guide.md

Publish and atlas support

qfit can generate atlas-ready layers and helper tables for print layouts, then export a PDF atlas from the plugin.

The current publish flow supports:

  • atlas page extent planning
  • cover and summary helper tables
  • TOC-ready helper rows
  • route-profile sample tables for layout charts
  • programmatic PDF export through the atlas/export subsystem

For validation notes and rendering-sensitive workflow details, see:

  • docs/atlas-validation-harness.md

More docs

  • docs/strava-setup.md
  • docs/schema.md
  • docs/map-style-guide.md
  • docs/qgis-testing.md

Part 2, for contributors and AI coding agents

Read these first

If you are changing internals, start here:

  • CONTRIBUTING.md
  • docs/architecture.md
  • docs/qgis-plugin-architecture-principles.md
  • docs/refactoring-roadmap.md
  • docs/qgis-testing.md
  • docs/atlas-validation-harness.md for rendering/export-sensitive work

Current architecture snapshot

qfit is being evolved as a modular monolith with pragmatic ports-and-adapters boundaries.

Preferred dependency direction:

UI -> application/workflow -> domain + ports -> infrastructure adapters

In practice, that means:

  • keep qfit_dockwidget.py focused on UI glue
  • move workflow orchestration into feature-owned application modules
  • keep provider-neutral logic easier to test than QGIS-heavy code
  • keep QGIS, Strava, GeoPackage, settings, and PDF assembly details in infrastructure/adapters when that improves clarity
  • add ports/gateways only when they earn their keep

Current repo shape

Plugin entrypoints and UI host

  • qfit_plugin.py
  • qfit_dockwidget.py
  • qfit_config_dialog.py
  • qfit_dockwidget_base.ui

Feature-owned packages

  • activities/ for fetch/sync/load workflows and provider-neutral activity logic
  • analysis/ for analysis workflows, request/result shaping, and QGIS-backed analysis adapters
  • atlas/ for publish/export workflows, runtime preparation, and PDF assembly
  • configuration/ for settings, connection status, and dock-settings binding helpers
  • providers/ for provider contracts and Strava-backed adapters
  • ui/ for dock-widget dependency assembly and UI-only coordination helpers
  • visualization/ for render planning, basemap workflows, temporal wiring, and QGIS layer adapters

Root-level modules

The top-level Python module layer is now mostly limited to:

  • plugin/bootstrap entrypoints
  • a few small shared helpers such as polyline_utils.py, time_utils.py, mapbox_config.py, and qfit_cache.py
  • transitional compatibility shims such as activity_query.py, activity_classification.py, models.py, and other grandfathered modules that still exist only to cushion package migration

Rule of thumb:

Do not add new feature-specific top-level modules.

If new code belongs to one feature, it should usually live under that feature package.

Current architectural priorities

  1. Keep thinning QfitDockWidget.
  2. Preserve strict feature ownership.
  3. Move policy into application/domain while leaving mechanics in adapters.
  4. Keep request/result seams explicit where they reduce UI or framework coupling.
  5. Delete compatibility shims once in-repo callers are migrated.

Practical coding rules

  • Prefer small, reviewable PR-sized slices.
  • Every behavior change needs tests.
  • New workflow logic should not accumulate in QfitDockWidget.
  • Prefer feature-owned modules over generic root-level helpers.
  • Prefer explicit request/result dataclasses when they replace long parameter lists or messy widget-state handoff.
  • Keep provider-neutral logic free of PyQGIS when practical.
  • Rendering/export-sensitive changes need artifact proof, not only green CI.

Working conventions by area

activities/

  • activities/domain/ holds provider-neutral activity logic.
  • activities/application/ owns fetch/sync/load workflows, preview helpers, and task wrappers.
  • GeoPackage-backed activity persistence belongs under infrastructure-oriented paths.

analysis/

  • dock-facing analysis entrypoints are intentionally being thinned behind workflow-oriented application seams
  • request building, dispatch, result shaping, and status policy belong in application modules, not in the dock
  • QGIS-backed layer creation stays in analysis infrastructure

visualization/

  • render planning, temporal intent, and user-facing visualization policy belong in visualization/application/
  • layer mutation, renderer construction, basemap loading, and QGIS project wiring belong in visualization/infrastructure/

atlas/

  • atlas/ owns publish/export workflows
  • keep naming and ownership crisp across request building, runtime preparation, task execution, and PDF assembly
  • avoid adding abstraction layers that do not clarify responsibility

ui/

  • ui/ is for dock-widget support code, dependency assembly, UI-only coordination, and similar glue
  • UI modules should call workflows and render results, not absorb more business logic

Testing

Run the main test suite with:

python3 -m pytest tests/ -x -q --tb=short

Run unittest discovery with:

python3 -m unittest discover -s tests -v

Run the PyQGIS smoke test with:

python3 -m unittest tests.test_qgis_smoke -v

On machines without PyQGIS installed, the smoke test skips automatically.

Local install and packaging

Install qfit into a local QGIS profile for testing with:

python3 scripts/install_plugin.py --plugins-dir <QGIS plugins dir> --mode copy

Build a release-style plugin archive with:

python -m pip install pypdf
python3 scripts/package_plugin.py

The release ZIP is written to dist/.

CI and review expectations

Before treating a change as done:

  • run the relevant tests
  • keep SonarCloud green
  • keep CodeQL/CI green
  • address meaningful review feedback
  • for export/rendering work, verify the final artifact, not just object construction

Short version for agents

If you only remember a few rules, remember these:

  • make QfitDockWidget thinner, not heavier
  • keep real feature logic inside feature-owned packages
  • keep QGIS-heavy mechanics out of provider-neutral workflow code
  • prefer small, behavior-preserving slices
  • delete migration shims once callers are gone

License

GPL-2.0-or-later. See LICENSE.

About

QFIT - Explore fitness data spatially in QGIS

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages