trails/openspec/changes/archive/2026-06-14-profile-stats/proposal.md
Ullrich Schäfer 2ad9898f9c
openspec: archive profile-stats + profile-weekly-distance, sync specs
Both changes are implemented and merged (#539, #541). Promote their deltas into
openspec/specs/, move the changes to changes/archive/2026-06-14-*, and add the
two capabilities to the CAPABILITIES index.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:34:06 +02:00

1.9 KiB

Why

A profile (/users/:username) is a list of routes and activities with no sense of the person behind it — no "how far have they gone", no recent cadence. Komoot leads its profile with lifetime totals (tours · distance · time); Strava with a "last 4 weeks" activity count. A small stats header makes a profile feel like someone's outdoor life rather than a table, and every number is already in the activities table.

What Changes

  • Add a stats header to the profile page showing lifetime totals: activity count, total distance, total ascent, total time (elapsed).
  • Add a recent-activity summary: the count of activities in the last 4 weeks (rolling).
  • Scope the roll-up to what the viewer may see: a visitor sees public-only totals; the owner viewing their own profile sees totals over all their activities.
  • Compute on the fly with a single indexed aggregate query — no cache table, no schema change (see design for the cost analysis and the future-cache escape hatch).

Capabilities

New Capabilities

  • profile-stats: the profile stats header — which totals are shown, how they are scoped by viewer/visibility, and how they are computed.

Modified Capabilities

Impact

  • Journal app: a new aggregate query in activities.server.ts (getActivityStats(ownerId, { publicOnly })); the profile loader (users.$username.server.ts) calls it and the page renders a stats header (reusing the shared StatRow where it fits).
  • i18n: journal.profileStats.* labels (en + de).
  • No schema change, no migration, no GPX parsing — aggregates use the stored distance / elevation_gain / duration columns over the existing owner_id-leading indexes.