Redesign statistics pages with global timeframe, insights and privacy scoping
Build and Push Lunchtime Images (Kaniko) / build-and-push (push) Successful in 1m55s

- Shared ChartCard/StatRow/CardGrid primitives for a consistent layout; fix
  clipped axis labels, green 100% bars and uneven tiles
- One page-wide timeframe filter; period-over-period deltas on stat tiles;
  per-period activity bars replace cumulative charts
- My Orders: lunch profile (personality, records, adventurousness), calendar
  and weekday x hour heatmaps, anonymous community comparison. /api/stats/me
  no longer returns other users' emails (organizers are numbered per response)
- Order Management: order insights, participant loyalty, median fill time,
  regulars and drop-offs, submission heatmap, top item per weekday
- Site Overview: adoption funnel, weekly retention, order sizes, order value,
  submission heatmap; active users now based on real contributions

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
simandClaude Sonnet 5.5 committed 2026-11-05 22:21:43 +00:00
1 parent b7eb2bb6d0
commit 1df83afab1
16 files changed
+818 -302

No files matched your search

+8 -2
View File
@@ -15,9 +15,15 @@ Statistics pages live under `/stats/*` (`src/frontend/src/views/StatisticsView.t
| `GET /api/stats/managed` | any user (own orders only) | Order Management |
| `GET /api/admin/stats` | site admin | Site Overview |
## Time series
## Timeframe and insights
Every page has an "Over time" panel (`TimeSeriesPanel.tsx`): cumulative charts with a timeframe filter (1W, 1M, 3M, 1Y, YTD, All, custom range). Running totals start at 0 at the start of the timeframe. Site-wide daily counts come from `daily` in `/api/admin/stats`.
- One page-wide timeframe filter (`range.tsx`: 1W, 1M, 3M, 1Y, YTD, All, custom) drives every number and chart, except the all-time blocks labelled as such (lunch profile, calendar, payments, funnel).
- Stat tiles show the change vs. the previous period of equal length (`Delta`); "All" has no comparison.
- The "Activity" panel (`TimeSeriesPanel.tsx`) shows per-period totals (days / weeks / months depending on the range) instead of cumulative running totals. Site-wide daily counts come from `daily` in `/api/admin/stats`.
- Personal insights (lunch personality, records, adventurousness, calendar and weekday x hour heatmaps) are computed in `lib/stats.ts` from the fact rows. `community` in `/api/stats/me` (participant count, average, percentile) is the only extra aggregate, from `user_order_tokens`.
- Site "active users" now means users who created an order or submission in the window (was: last profile update). The funnel and weekly retention use the same data.
- **Privacy model:** My Orders only ever contains the viewer's own data plus anonymous aggregates (percentile, orders-per-participant histogram, organizer counts/shares). `/api/stats/me` returns no emails; organizers are numbered per response. Order Management is scoped to the viewer's own orders (their participants are visible, as in the order admin view). Only Site Overview (admin) sees site-wide data and names.
- Not possible without new tracking: fill rate per order (no invitee list), display names (only emails exist; the local part is shown).
## My Orders (orderees)