# SPEC: RTSport Parent Dashboard — Full Retool > Agent Collaboration Protocol v1.3.0 > Build Date: 2026-05-06 > Refs: `coach-retool-spec.md`, `product-brief.md`, `phase1-mvp-cut.md` ## Overview The Parent Dashboard exists as a skeleton with three bottom-nav tabs (Home, Timeline, Message) — same pattern as the Coach Dashboard. Home is partially wired with loading states. Timeline and Message are empty placeholders. This build fleshes out all three tabs with production-quality, demo-ready interfaces. ## 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) | | Parent Context | `currentAthleteId` variable, child selector for multi-kid families | | Design Accent | `--parent-accent: #8b5cf6` (violet — care/trust) | | Existing File | `/home/hoffmann_admin/.openclaw/shared/build-20260501/frontend/templates/parent/dashboard.html` (549 lines) | ## Shared Constants ### Status Enums | Constant | Values | Used By | |----------|--------|---------| | `AthleteStatus` | `out`, `restricted`, `cleared` | Backend + frontend status cards/badges | | `CasePhase` | `initial_assessment`, `active_rehab`, `return_to_play`, `full_clearance` | Backend + frontend progress bars | | `InjurySeverity` | `mild`, `moderate`, `severe` | Backend + frontend severity badges | | `TimelineEventType` | `assessment`, `restriction`, `milestone`, `clearance`, `message` | Backend + frontend timeline filtering | | `MessageStatus` | `sent`, `delivered`, `read` | Backend + frontend message bubbles | ### Feature Flags | Flag | Default | Description | |------|---------|-------------| | `ENABLE_PARENT_MESSAGING` | `true` | Controls Message tab visibility | | `ENABLE_FERPA_FILTER` | `true` | Strips clinical_notes from parent timeline | | `ENABLE_MULTI_CHILD` | `true` | Shows child selector for families with >1 athlete | ## Endpoints ### Home Tab #### `GET /api/v1/dashboard/parent?school_id=X&athlete_id=Y` **Response:** ```json { "athlete": { "id": "ath_001", "first_name": "Jake", "last_name": "Larson", "sport": "Football", "team": "Varsity", "grade": 11, "jersey_number": 12, "current_status": "out" }, "case": { "id": "case_001", "status": "active", "body_part": "Ankle", "side": "Right", "injury_type": "Sprain", "severity": "moderate", "opened_date": "2026-04-15", "phase": "active_rehab", "phase_number": 2, "total_phases": 4, "estimated_return": "2026-05-20", "next_appointment": "2026-05-08T15:30:00Z", "restrictions": [ "No running", "Non-contact only", "Must wear ankle brace" ], "milestones": [ {"label": "Initial Assessment", "status": "done", "completed_date": "2026-04-15"}, {"label": "Active Rehab", "status": "current", "target_date": "2026-05-10"}, {"label": "Return to Play", "status": "pending", "target_date": "2026-05-20"}, {"label": "Full Clearance", "status": "pending", "target_date": "2026-05-25"} ], "care_team": [ {"name": "Lisa Johnson, LAT", "role": "Athletic Trainer", "initials": "LJ", "email": "ljohnson@preble.k12.wi.us"}, {"name": "Coach Andrews", "role": "Head Coach — Football", "initials": "CA", "email": "andrews@preble.k12.wi.us"} ] }, "activity_feed": [ {"type": "milestone", "title": "Advanced to Active Rehab", "date": "2026-05-01", "note": "Range of motion restored. Starting strengthening exercises."}, {"type": "message", "title": "Message from Lisa Johnson, LAT", "date": "2026-04-28", "note": "Jake is progressing well. We'll re-evaluate next week."}, {"type": "restriction", "title": "Restrictions Updated", "date": "2026-04-22", "note": "Non-contact practice only. Must wear ankle brace."}, {"type": "assessment", "title": "Initial Assessment", "date": "2026-04-15", "note": "Right ankle sprain — Grade 2. Moderate swelling."} ] } ``` ### Timeline Tab #### `GET /api/v1/dashboard/parent/timeline?school_id=X&athlete_id=Y` **Response:** ```json { "athlete_name": "Jake Larson", "case": { "id": "case_001", "phase": "active_rehab", "phase_number": 2, "total_phases": 4 }, "events": [ {"type": "milestone", "title": "Advanced to Active Rehab", "date": "2026-05-01", "description": "Range of motion restored. Starting strengthening exercises — 3x/week.", "icon": "🏃"}, {"type": "message", "title": "AT Update", "date": "2026-04-28", "description": "Lisa Johnson shared: \"Jake is progressing well. We'll re-evaluate next week.\"", "icon": "💬"}, {"type": "restriction", "title": "Restrictions Updated", "date": "2026-04-22", "description": "Non-contact practice only. Must wear ankle brace during all activities.", "icon": "⚠️"}, {"type": "assessment", "title": "Initial Assessment", "date": "2026-04-15", "description": "Right ankle sprain — Grade 2. Moderate swelling. Immobilized, crutches for 3 days.", "icon": "🏥"}, {"type": "clearance", "title": "Case Opened", "date": "2026-04-15", "description": "Injury reported during football practice. AT notified immediately.", "icon": "📋"} ] } ``` ### Messages Tab #### `GET /api/v1/messages/parent?athlete_id=Y` **Response:** ```json { "athlete_name": "Jake Larson", "conversations": [ { "contact_name": "Lisa Johnson, LAT", "contact_role": "Athletic Trainer", "contact_initials": "LJ", "last_message": "Jake is progressing well. We'll re-evaluate next week.", "last_message_time": "2026-04-28T15:30:00Z", "unread_count": 1 } ] } ``` #### `GET /api/v1/messages/parent/{contact_id}?before=X` **Response:** ```json { "contact_name": "Lisa Johnson, LAT", "messages": [ {"id": "msg_001", "sender": "at", "text": "Hi, Jake's initial assessment is complete. Grade 2 right ankle sprain.", "timestamp": "2026-04-15T14:00:00Z", "status": "read"}, {"id": "msg_002", "sender": "parent", "text": "Thank you for letting me know. What's the recovery timeline?", "timestamp": "2026-04-15T14:30:00Z", "status": "read"}, {"id": "msg_003", "sender": "at", "text": "Jake is progressing well. We'll re-evaluate next week.", "timestamp": "2026-04-28T15:30:00Z", "status": "delivered"} ] } ``` #### `POST /api/v1/messages/parent/{contact_id}` **Request:** ```json { "text": "Thanks for the update! Is there anything we should do at home?" } ``` **Response:** `201 Created` with message object ### Child Selector #### `GET /api/v1/dashboard/parent/children?school_id=X` **Response:** ```json { "children": [ {"id": "ath_001", "first_name": "Jake", "last_name": "Larson", "sport": "Football", "team": "Varsity", "current_status": "out", "has_active_case": true}, {"id": "ath_005", "first_name": "Emma", "last_name": "Larson", "sport": "Soccer", "team": "JV", "current_status": "cleared", "has_active_case": false} ] } ``` ## UI Components ### Home Tab | Component | Purpose | Data Source | States | |-----------|---------|-------------|--------| | ChildSelector | Horizontal scrollable cards, one per child athlete | `GET /children` | Loading, 0 children (empty), 1 child (hidden), 2+ (scrollable) | | StatusHero | Large status card with athlete avatar, status, phase progress | `GET /parent` | Loading, healthy (no case), active case | | PhaseTracker | Progress bar showing recovery phase (e.g. "Phase 2 of 4") | `GET /parent` | Show only if active case | | RestrictionsCard | List of current restrictions with severity | `GET /parent` | Show only if restrictions exist | | NextAppointment | Highlighted card with next AT appointment | `GET /parent` | Show if appointment exists | | CareTeam | Contact cards for AT and coach | `GET /parent` | Always shown | | ActivityFeed | Recent events filtered for parent view | `GET /parent` | Loading, empty, populated | ### Timeline Tab | Component | Purpose | Data Source | States | |-----------|---------|-------------|--------| | PhaseHeader | Current phase indicator at top | `GET /timeline` | Active case, no case (healthy state) | | TimelineEvents | Vertical timeline with colored dots by event type | `GET /timeline` | Loading, empty, populated | | EventCard | Each event: icon, title, date, description | Embedded | All event types | | FERPAFilterNote | Small text: "Clinical notes are not shown in this view" | Static | Always shown (compliance) | ### Messages Tab | Component | Purpose | Data Source | States | |-----------|---------|-------------|--------| | ConversationList | List of care team members to message | `GET /messages/parent` | Loading, empty, populated | | ChatView | Message thread with bubbles | `GET /messages/parent/{id}`, `POST` | Loading, empty, populated | | MessageBubble | Sent (right, violet) vs received (left, muted) | Embedded | Timestamps, read receipts | | Composer | Text input + send button | Embedded | Empty validation, sending state | ## States to Handle Every component handles: - **Loading:** Skeleton/spinner while fetching - **Empty:** Friendly message with icon ("No active recovery plan" / "No messages yet") - **Error:** Actionable message with retry button ("Couldn't load. Tap to retry.") - **Populated:** Real data display ## Design Constraints - **Mobile-first:** 375-414px primary, scales to tablet - **Dark theme:** Match existing `--parent-accent: #8b5cf6`, `--bg-base: #0f0f17` - **44px minimum** tap targets on all interactive elements - **Pure CSS** — no chart libraries, no heavy animations - `touch-action: manipulation` on interactive elements - **FERPA compliance:** Parent sees only their athlete(s). No clinical notes in timeline. - Match existing CSS variables in `rtsport.css` — don't redefine them ## Success Criteria 1. **Home tab fully functional** — Status hero, phase tracker, restrictions, care team, activity feed all render from API data 2. **Child selector works** — Switching children reloads all dashboard data for that athlete 3. **Timeline tab shows complete recovery journey** — Chronological events with icons, dates, descriptions 4. **Messages tab supports full chat flow** — Conversation list → open thread → send message → see reply 5. **All states handled** — Loading, empty, error, populated for every component 6. **Mobile-first, matches design system** — Same violet accent, dark theme, typography, spacing 7. **FERPA-aware** — No clinical notes exposed, parent-only visibility badge present ## File Structure ### Backend (`/home/hoffmann_admin/.openclaw/shared/build-20260506-parent/backend/`) ``` rtsport_parent_api.py ← New endpoints for parent dashboard seed_parent_data.py ← Test parent data (at least 2 athletes, 1 with active case) ``` Mount into live codebase at `/home/hoffmann_admin/.openclaw/workspace-socrates/hoffdesk-api/` ### Frontend (`/home/hoffmann_admin/.openclaw/shared/build-20260506-parent/frontend/`) ``` parent-dashboard.html ← Full modified dashboard (read existing, replace placeholder sections) parent-tabs.css ← New CSS for parent-specific components parent-tabs.js ← JS for child switching, tab navigation, message sending ``` ## Integration Notes - The existing dashboard already has `loadDashboard()`, `loadChildren()`, `switchChild()`, `renderStatusCard()`, etc. — these functions should be enhanced, not thrown away - Backend mock data: at least 2 children (1 with active case, 1 healthy), 2 care team members, 4 milestone phases, 5 timeline events - Messages can be in-memory (shared dict between coach and parent message endpoints) - Child selector: horizontal scroll for 2-4 kids, stacked for 5+. Hide if only 1 child. - Timeline tab: use the `data.loaded` flag pattern already present (avoid re-fetching) ## Out of Scope - Real-time WebSocket/SSE - Push notifications / email alerts - File/image attachments in messages - Telehealth scheduling - Consent forms - Multi-school parent accounts