Cross-roster view of one activity
const url = 'http://localhost:8000/api/dashboard/activity/example/';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url http://localhost:8000/api/dashboard/activity/example/ \ --header 'Authorization: Bearer <token>'Returns the cohort timeseries (median + IQR), per-client leaderboard with headline metric values, and an outlier strip of clients whose latest readings fall outside the MetricSpec target zone.
Range must be one of 7, 14, 30, 90. Bucketing switches from daily to weekly above 30 days. The metric must be one of the activity’s available_metrics; missing → 400 with the valid set listed. Unknown activity → 404.
Source-of-truth doc: project_context/product/COACH_DASHBOARD_PLAN.md §5 / §9.1.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”One of the closed Activity enum values: running, walking, jump, weightlifting, mobility, agility, fencing, workspace_wellness. Unknown → 404.
Query Parameters
Section titled “Query Parameters”Optional Client id — overlays that athlete’s per-bucket series for metric on the cohort distribution chart (athlete_series, aligned 1:1 with cohort). Omit for no overlay. A malformed id, or a client that isn’t the caller’s team, returns 404.
Exercise preset to narrow the cohort to — one of the activity’s available_exercises. Scopes the cohort, athlete overlay, leaderboard, and outliers to that exercise and narrows available_metrics + headline_metrics to the metrics it emits; when the current metric isn’t emitted by the exercise it falls back to the exercise’s first metric. Unknown exercise → 400. Omit for the all-exercises view. #795.
Custom-range start (ISO YYYY-MM-DD, inclusive). Takes precedence over range.
Optional ClientGroup id — narrows every roster / cohort / leaderboard / outlier figure to that group’s members. Omit for the whole-team view. A malformed id, or a group that isn’t the caller’s team, returns 404.
MetricSpec key driving the cohort timeseries. Defaults to the first entry of the activity’s HEADLINE_METRICS list. Must be a member of available_metrics.
Preset look-back — 7d / 14d / 30d / 90d / 365d. Mutually exclusive with from/to.
Custom-range end (ISO YYYY-MM-DD, inclusive). Defaults to today.
Viewer’s IANA timezone (e.g. America/Chicago). The look-back window AND the daily/weekly buckets are computed in it, so a session lands on the coach’s local day, not the server’s UTC day. Omit to fall back to UTC (legacy / partner-key callers).
Responses
Section titled “Responses”Shape of GET /api/dashboard/activity/{activity}/.
object
running- Runningwalking- Walkingjump- Vertical Jumpweightlifting- Weightliftingmobility- Mobility Assessmentworkspace_wellness- Workspace Wellnessagility- Agilityfencing- Fencingcycling- Cyclingtennis- Tennispadel- Padel Tennisbowling- Bowlingbaseball- Baseballfootball- Footballbadminton- Badmintoncricket- Cricketbasketball- Basketballscuba_diving- Scuba Divingice_hockey- Ice Hockeyamerican_football- American Footballfri- Falls Risk Indicator
ISO date of the window’s first day (inclusive).
ISO date of the window’s last day (inclusive).
Bucket granularity the cohort series is binned to. Picked from window length: ≤30d → day, ≤120d → week, otherwise month.
day- dayweek- weekmonth- month
MetricSpec key the cohort timeseries was computed against.
Clients with a latest score in scope — the denominator behind each leaderboard row’s standing rank (#3 of {cohort_size}). #609 Phase 2.
Median latest score across the standing cohort. Null when no client has a scored session. #609 Phase 2.
Closed list of cohort-switchable metrics. Narrowed to the chosen ?exercise=’s specs when it is set (#795); otherwise the activity-wide union, deduped by key across exercises.
object
One of the canonical Unit literal strings (see domain/metrics/base.py).
Metric has not cleared clinical / force-plate validation; the UI shows a ‘beta’ precision caveat.
Exercise presets of the activity (preset_exercises) for the cohort exercise sub-filter (#795). One entry for single-exercise activities; the frontend hides the control below 2. Filter via ?exercise=<name>.
Up to 4 keys the leaderboard surfaces as named columns. Driven by HEADLINE_METRICS in the dashboard service.
object
Bucket label. ISO date for range_days ≤ 30 (daily); ISO Monday-of-the-week for larger ranges (weekly).
Median value of the chosen metric across the cohort in the bucket. Null when the bucket is empty.
25th percentile (inclusive). Renders as the lower edge of the IQR band on the timeline chart.
75th percentile (inclusive). Upper edge of the IQR band.
Number of athletes contributing to this bucket — each athlete counts once regardless of how many sessions they posted. Zero for empty buckets.
The overlay athlete’s per-bucket values for metric, aligned 1:1 with cohort (one entry per bucket, null where that athlete has no session that bucket). Present only when ?athlete=<client_id> is supplied; null otherwise. #609.
object
Client UUID.
display_name → email → empty.
UUID of the most-recent completed session in the range.
created_at of that session.
score SessionMetric value (0..100) when present.
Headline metric values keyed by MetricSpec.key. Missing keys → null.
object
1-based overall standing within the in-scope cohort, by composite score (1 = best; ties share a rank). NOT the selected cohort metric — a per-metric rank misleads for band-optimal metrics + contradicts score. Null when the client has no scored session. #609 Phase 2.
0-100 — the share of other in-scope clients this client beats on composite score (best → 100). Null for a single-client cohort or a client with no scored session. #609 Phase 2.
Composite-score progress vs the client’s personal baseline (latest − the score at their earliest in-range session). The small per-row ‘vs baseline’ delta. Null when the client has a single in-range session or that earliest session carries no score. #609 Phase 2.
object
MetricSpec.key whose latest reading breaches the spec band.
The actual value that breached.
above = value > max_good; below = value < min_good.
above- abovebelow- below
MetricSpec.min_good for context — the POPULATION default, not this athlete’s resolved band, so the roster ranks every client against one yardstick. Deliberate and unchanged by #1317; note it can therefore flag an athlete whose own card reads in-zone.
MetricSpec.max_good — population, see target_min.
One AI-coach insight attached to a dashboard response.
Server returns the i18n keys + interpolation vars; the frontend renders the localised copy. This keeps server-side from owning user-facing English/Russian strings.
object
Semantic category — drives icon + i18n key on the client.
Drives the tone-bar colour: info → sleep, warning → form, critical → recovery-low.
info- infowarning- warningcritical- critical
I18n key for the headline. Frontend interpolates with title_vars.
Vars for title_key interpolation.
object
object
Example
{ "activity": "running", "granularity": "day", "outliers": [ { "direction": "above" } ], "recommendations": [ { "severity": "info" } ]}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Examplegenerated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Examplegenerated
{ "detail": "example"}object
Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).
Examples
404 — Unknown activity
{ "detail": "Unknown activity: 'curling'"}404 — No active team
{ "detail": "No active team — finish onboarding first."}