📄 SPEC.md 7,855 bytes Wednesday 01:25 📋 Raw

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:

{
  "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:

{
  "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:

{
  "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:

{
  "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:

{
  "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