openspec: propose profile-stats (profile roll-ups)

Lifetime totals (count · distance · ascent · elapsed time) + a last-4-weeks
count on the profile, viewer-scoped (public-only for visitors, full for the
owner).

Design records the cost decision: compute on the fly with a single aggregate
over stored columns on the owner_id-leading indexes (cheap even for power
users) — no cache table, no schema change — with a documented escape hatch to
a user_activity_stats cache if profiling ever shows it's hot.

Validates with `openspec validate --strict`. Specs only; no code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-06-13 06:56:06 +02:00
parent b7e55d09db
commit 977e0d8f5f
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
5 changed files with 173 additions and 0 deletions

View file

@ -0,0 +1,19 @@
## 1. Aggregate query
- [ ] 1.1 Add `getActivityStats(ownerId, { publicOnly })` to `activities.server.ts`: one aggregate (`count`, `sum(distance)`, `sum(elevationGain)`, `sum(duration)`) + a `last4Weeks` count (`started_at >= now() - 28d`, COALESCE with `created_at`), scoped by `publicOnly`.
- [ ] 1.2 Return zeros/empty when the owner has no visible activities.
## 2. Loader & view
- [ ] 2.1 Profile loader (`users.$username.server.ts`) calls `getActivityStats(ownerId, { publicOnly: !isOwn })`; expose the totals + last4Weeks.
- [ ] 2.2 Render a compact stats header on `users.$username.tsx` above the routes/activities lists (reuse `StatRow` + `stats.ts` formatters); hide it when there are no activities.
## 3. i18n
- [ ] 3.1 Add `journal.profileStats.*` keys (activities, distance, ascent, time, last4Weeks) to en + de.
## 4. Tests & checks
- [ ] 4.1 Unit/component: the stats header renders totals + last-4-weeks; hidden on empty (jsdom).
- [ ] 4.2 E2E: create activities, assert the profile shows the totals; a visitor sees public-only (a private activity is excluded from the count).
- [ ] 4.3 `pnpm typecheck && pnpm lint && pnpm test && pnpm test:e2e` green.