Coach-dashboard overview
const url = 'http://localhost:8000/api/dashboard/overview/?range=14d';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/overview/?range=14d' \ --header 'Authorization: Bearer <token>'Aggregated payload for the coach Overview page. One round-trip carries the roster pulse, score pulse, activity heatmap, top movers, quota strip, and recent sessions feed.
All counts are scoped to the caller’s active team. Range must be one of 7, 14, 30, 90; default 14. Cohort comparison (delta vs prior window) is best-effort: deltas are null when the prior window is empty.
Source-of-truth doc: project_context/product/COACH_DASHBOARD_PLAN.md §4 / §9.1.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”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.
Preset look-back window. Accepted: 7d, 14d, 30d, 90d, 365d. Default 14d. Numeric form (7, 14, …) also accepted. Mutually exclusive with from/to.
Examples
default
14dweek
7dquarter
90dyear
365dCustom-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/overview/.
object
The window the response was computed against. Echoed for the client to label its UI.
ISO date of the window’s first day, inclusive. Useful for labelling custom-range UI (e.g. ‘Apr 1 – Apr 30’).
ISO date of the window’s last day, inclusive.
Server timestamp at which the aggregation ran. Useful for ETag/cache debug.
Top-strip KPI tiles (zone B in the Overview mockup).
object
Total clients owned by the active team. Independent of session activity.
Clients that had at least one session (any status) in the requested range.
Sessions created since the start of the calling user’s now() day (UTC).
Sessions created in the last 7 calendar days.
Completed sessions without a coach_review SessionMetric. Not range-bound — coaches care about the absolute backlog, not the bucket.
Sessions with status=failed in the last 7 days. Quota refunded automatically per the ledger; this is a triage signal.
3-up score-ring strip (zone C).
object
Average composite score (0..100) across the latest completed session of every client. Null when no client has any scored session yet.
roster_avg minus the same calculation against sessions in the prior range_days window. Null when the prior window is empty.
Clients whose latest score is below the at-risk threshold (60). Single-session sample today; a longer rolling window may replace this in Phase D-future.
at_risk minus same metric over the prior window.
Clients with at least 3 completed sessions in the last 7 days.
streaks minus same metric over the previous 7d slice.
Activity × day cells over the requested range (zone D). Sparse: empty days are omitted, the client fills gaps with zeros.
object
Date bucket the cell represents (UTC), YYYY-MM-DD.
Activity enum (running, walking, jump, …).
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
Number of sessions in that activity for that day. Includes failed/pending — the heatmap is a load signal, not a success signal.
Per-activity completed-session totals over the window (roster-wide, group-scoped). The client lands the Dashboards view on the activity with the most completed sessions — the one that actually has data to show — instead of a hardcoded first chip (#899). Empty when there are no completed sessions.
object
Activity enum (running, walking, jump, …).
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
Completed (data-bearing) sessions for this activity in the window — the ones that produce cohort / leaderboard data. Unlike the heatmap this excludes failed/pending, so it’s the signal for which activity actually has something to show.
ISO datetime of the most-recent completed session for this activity. Tiebreak when two activities have equal completed counts (most-recent wins).
Up to 5 (client, activity) pairs sorted by largest positive delta (zone E left).
object
Client UUID; tap-target for navigating to /clients/:id.
Display name (display_name → email → empty). Empty allowed because legacy-imported clients can have neither.
Activity the delta is computed on. Each (client, activity) pair is one mover row.
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
Mean score over the last 7 days minus mean score over the prior 8..30 days. Sign matches the bucket: positive in movers_up, negative in movers_down.
Up to 5 (client, activity) pairs sorted by most negative delta (zone E right).
object
Client UUID; tap-target for navigating to /clients/:id.
Display name (display_name → email → empty). Empty allowed because legacy-imported clients can have neither.
Activity the delta is computed on. Each (client, activity) pair is one mover row.
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
Mean score over the last 7 days minus mean score over the prior 8..30 days. Sign matches the bucket: positive in movers_up, negative in movers_down.
Quota & subscription strip (zone F right).
object
Sum of positive ledger entries (plan_grant:*, manual top-ups). Lifetime, not period-bound.
Absolute value of negative ledger entries — sessions consumed.
granted - debited. Same number Me.session_quota reports.
Active plan display name (e.g. Pro). Null when the team has no Subscription row yet (free tier).
Subscription.current_period_end — when the next quota grant is expected. Null on free tier.
Floor of (period_end - now) in days. Null on free tier; clamped to 0 if past_due.
True when the user clicked Cancel — quota stops refilling at period_end.
5 most recent sessions, newest first (zone G).
object
Session UUID.
Stable per-team session number (#941); null on demo and pre-backfill rows.
Activity enum.
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
Exercise preset string from EXERCISES (e.g. Treadmill, Clean). Empty when unset on legacy rows.
pending / processing / completed / failed.
Server-side creation timestamp.
Client UUID, or null for legacy unattached sessions.
client.display_name → client.email → null.
Composite score SessionMetric value (0..100) when present. Null on failed/pending rows.
AI-coach insights derived from the same payload — see dashboard/recommendations.py.
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
Examples
Typical response for a small coaching team
{ "range_days": 14, "generated_at": "2026-04-29T15:08:00Z", "roster": { "total": 42, "active": 18, "sessions_today": 11, "sessions_week": 47, "pending_review": 3, "failed_7d": 0 }, "score_pulse": { "roster_avg": 78, "roster_avg_delta": 4, "at_risk": 8, "at_risk_delta": -2, "streaks": 9, "streaks_delta": 2 }, "heatmap": [ { "date": "2026-04-29", "activity": "running", "count": 4 }, { "date": "2026-04-29", "activity": "jump", "count": 2 } ], "activity_totals": [ { "activity": "running", "completed": 12, "last_completed_at": "2026-04-29T14:08:00Z" }, { "activity": "jump", "completed": 3, "last_completed_at": "2026-04-28T09:12:00Z" } ], "movers_up": [ { "client_id": "0d8b…", "client_name": "Anna Greco", "activity": "running", "delta": 12 } ], "movers_down": [], "quota": { "granted": 200, "debited": 13, "remaining": 187, "plan_name": "Pro", "period_end": "2026-05-08T00:00:00Z", "days_to_renew": 9, "cancel_at_period_end": false }, "recent": [ { "id": "ab12…", "seq_no": 42, "activity": "running", "exercise": "Treadmill", "status": "completed", "created_at": "2026-04-29T14:08:00Z", "client_id": "0d8b…", "client_name": "Anna Greco", "score": 84 } ]}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"}