# SPEC: RTSport Coach Dashboard — Status & Messages Tabs > Agent Collaboration Protocol v1.3.0 > Build Date: 2026-05-06 ## Overview The Coach Dashboard has three bottom-nav tabs. Roster is fully built and polished. This build fleshes out the remaining two: **Status** (team-wide injury/recovery analytics) and **Messages** (secure coach-AT communication). ## Contract | Field | Value | |-------|-------| | API Base Path | `https://hoffdesk.com/api/v1` | | Auth Scheme | Bearer JWT (localStorage `rtsport_token`) | | Content Type | `application/json` | | Error Format | `{ "error": "...", "detail": { ... } }` | | Existing JS | Uses `apiRequest(endpoint, options)` wrapper in dashboard.html | | School ID | `schl_001` (test data) | | Coach Context | Current sport via `currentSport` variable, coach email from localStorage | ## Shared Constants ### Status Enums | Constant | Values | Used By | |----------|--------|---------| | `AthleteStatus` | `out`, `modified`, `cleared` | Backend enum + frontend labels/badges | | `CasePhase` | `initial_assessment`, `active_rehab`, `return_to_play`, `full_clearance` | Backend enum + frontend progress bar | | `MessageStatus` | `sent`, `delivered`, `read` | Backend + frontend message bubbles | ### Feature Flags | Flag | Default | Description | |------|---------|-------------| | `ENABLE_MESSAGING` | `true` | Controls Messages tab visibility | | `ENABLE_ANALYTICS` | `true` | Controls Status tab charts | ## Endpoints ### Status Tab #### `GET /api/v1/dashboard/coach/status?school_id=X&sport=Football` **Response:** ```json { "sport": "Football", "total_athletes": 50, "status_summary": { "out": 3, "modified": 2, "cleared": 45 }, "injury_breakdown": [ {"body_part": "Ankle", "count": 2}, {"body_part": "Knee", "count": 3}, {"body_part": "Shoulder", "count": 1} ], "recovery_timeline": [ {"athlete_name": "Jake Larson", "status": "out", "phase": "active_rehab", "days_remaining": 14}, {"athlete_name": "Marcus Johnson", "status": "out", "phase": "initial_assessment", "days_remaining": 21}, {"athlete_name": "Tyler Wilson", "status": "modified", "phase": "return_to_play", "days_remaining": 3} ], "recent_activity": [ {"type": "status_change", "athlete_name": "Jake Larson", "from": "modified", "to": "out", "timestamp": "2026-05-06T00:00:00Z"}, {"type": "new_case", "athlete_name": "Tyler Wilson", "body_part": "Knee", "timestamp": "2026-05-05T12:00:00Z"} ] } ``` #### `GET /api/v1/dashboard/coach/athlete/{athlete_id}/timeline` **Response:** ```json { "athlete_name": "Jake Larson", "cases": [ { "id": "case_001", "body_part": "Ankle - Right", "opened": "2026-04-15T00:00:00Z", "status": "active", "milestones": [ {"name": "Initial Assessment", "completed": true, "date": "2026-04-15"}, {"name": "Active Rehab", "completed": false, "date": null}, {"name": "Return to Play", "completed": false, "date": null}, {"name": "Full Clearance", "completed": false, "date": null} ] } ] } ``` ### Messages Tab #### `GET /api/v1/messages/coach?school_id=X&sport=Football` **Response:** ```json { "conversations": [ { "athlete_name": "Jake Larson", "athlete_id": "ath_001", "last_message": "Any update on the ankle?", "last_message_time": "2026-05-05T20:00:00Z", "unread_count": 2, "at_name": "Sarah (AT)" } ] } ``` #### `GET /api/v1/messages/coach/{athlete_id}?before=X` **Response:** ```json { "athlete_name": "Jake Larson", "messages": [ {"id": "msg_001", "sender": "coach", "text": "Any update on the ankle?", "timestamp": "2026-05-05T20:00:00Z", "status": "read"}, {"id": "msg_002", "sender": "at", "text": "He's progressing well. Should be back next week.", "timestamp": "2026-05-05T20:15:00Z", "status": "read"} ] } ``` #### `POST /api/v1/messages/coach/{athlete_id}` **Request:** ```json { "text": "Thanks for the update!" } ``` **Response:** `201 Created` with the message object ## Data Models ### StatusData | Field | Type | Required | Notes | |-------|------|----------|-------| | sport | string | yes | Current sport name | | total_athletes | int | yes | Total roster count for sport | | status_summary | object | yes | Out/Modified/Cleared counts | | injury_breakdown | array | yes | Body part → count | | recovery_timeline | array | yes | Active cases with ETA | | recent_activity | array | yes | Last 10 events | ### Message | Field | Type | Required | Notes | |-------|------|----------|-------| | id | string | yes | UUID | | sender | string | yes | "coach" or "at" | | text | string | yes | Message body | | timestamp | string | yes | ISO-8601 | | status | string | yes | sent/delivered/read | ## UI Components ### Status Tab | Component | Purpose | Data Source | |-----------|---------|-------------| | StatusPills | Three-stat cards (Out/Mod/Cleared) | `GET /status` | | InjuryBreakdown | Horizontal bar chart of body parts | `GET /status` | | RecoveryTracker | Active cases with progress bars | `GET /status` | | ActivityFeed | Chronological feed of recent changes | `GET /status` | ### Messages Tab | Component | Purpose | Data Source | |-----------|---------|-------------| | ConversationList | List of athlete message threads | `GET /messages/coach` | | ChatView | Message thread with athlete's AT | `GET /messages/coach/{id}`, `POST` | | MessageBubble | Single message (sent vs received styling) | Embedded in ChatView | ## States to Handle Every component must handle: - **Loading:** Skeleton/spinner while fetching - **Empty:** Friendly "no data yet" message with icon - **Error:** Actionable error message with retry button - **Populated:** Real data display ## File Structure ### Backend (`/home/hoffmann_admin/.openclaw/shared/build-20260506/backend/`) ``` rtsport_coach_api.py ← New endpoints for status + messages rtsport_messages.py ← Message model + storage (in-memory SQLite) seed_coach_data.py ← Test coach data (if needed) ``` Write to Socrates' existing codebase at `/home/hoffmann_admin/.openclaw/workspace-socrates/hoffdesk-api/` ### Frontend (`/home/hoffmann_admin/.openclaw/shared/build-20260506/frontend/`) ``` status-tab.html ← Status tab HTML/CSS (inline in dashboard or as partial) messages-tab.html ← Messages tab HTML/CSS (inline in dashboard or as partial) dashboard.js ← JS for tab switching, data fetching, chat interactions ``` The existing dashboard is at `/home/hoffmann_admin/.openclaw/shared/build-20260501/frontend/templates/coach/dashboard.html` — Daedalus should read that file and integrate the new tabs into it. ## Success Criteria 1. **Status tab loads and shows real data** — Coach sees Out/Modified/Cleared breakdown, injury chart, recovery tracker, activity feed 2. **Messages tab loads conversations** — Coach sees list of athlete threads with unread counts 3. **Coach can open a conversation and send a message** — Full chat flow works 4. **All states handled** — Loading, empty, error, populated for both tabs 5. **Mobile-first, matches existing design system** — Same color scheme, typography, spacing 6. **No regression on Roster tab** — Existing dashboard functionality preserved ## Integration Notes - Backend mock data is acceptable for this build — use the existing mock pattern in `rtsport_mock.py` - Messages can be in-memory (no persistence needed for demo) - Status tab charts should be pure CSS — no chart library dependency - The existing `apiRequest()` wrapper handles auth — use it - Coach context: `currentSport` variable already exists, use it to filter API calls ## Out of Scope - Real-time WebSocket/SSE for messages (polling is fine for MVP) - Push notifications - File/image attachments in messages - Multi-school support for AD view