# RTSport API — v0.3 # Frontend-driven contract from the AT dashboard mock. # These are the endpoints the frontend currently fetches or POSTs to. # Socrates: wire these. Auth, roles, and FERPA matrix in contract.md. openapi: "3.0.3" info: title: RTSport API version: "0.3" description: | Athletic training case management for high school sports. Current frontend targets: AT dashboard, sideline entry, athlete detail overlay. servers: - url: https://api.hoffdesk.com/rtsport/v1 description: Production - url: https://hoffdesk.com/api/v1 description: Current mock server path paths: # ── Dashboard ──────────────────────────────────────── /events/sideline-entry: post: summary: Submit a sideline injury/incident entry description: Called by the 3-tap sideline entry flow after all 3 selections requestBody: required: true content: application/json: schema: type: object required: - school_id - athlete_id - body_part - severity properties: school_id: type: string example: "schl_001" athlete_id: type: string example: "ath_001" body_part: type: string example: "Ankle" severity: type: string enum: [mild, moderate, severe] example: "moderate" removed_from_play: type: boolean default: false timestamp: type: string format: date-time description: ISO-8601 timestamp of when the injury occurred responses: "200": description: Entry created content: application/json: schema: type: object properties: case_id: type: string example: "cas_abc123" athlete: type: string example: "Jake Larson" body_part: type: string example: "Ankle" severity: type: string example: "moderate" athlete_status: type: string enum: [removed, evaluated] "400": description: Validation error — missing required fields # ── Athlete Detail ─────────────────────────────────── /athletes/{athlete_id}: get: summary: Get athlete profile parameters: - name: athlete_id in: path required: true schema: type: string responses: "200": description: Athlete profile content: application/json: schema: $ref: "#/components/schemas/Athlete" /cases/{athlete_id}: get: summary: Get active case for an athlete (latest if multiple) parameters: - name: athlete_id in: path required: true schema: type: string responses: "200": description: Full case data including milestones and timeline content: application/json: schema: $ref: "#/components/schemas/Case" "404": description: No active case found for this athlete /athletes/{athlete_id}/case: get: summary: Combined endpoint — returns athlete + active case in one call description: | Frontend currently makes TWO separate fetches (athletes.json + cases.json) and joins on athlete_id. This endpoint wraps both into one response for the athlete detail overlay. parameters: - name: athlete_id in: path required: true schema: type: string responses: "200": description: Athlete and case data merged content: application/json: schema: type: object properties: athlete: $ref: "#/components/schemas/Athlete" case: $ref: "#/components/schemas/Case" # ── Dashboard Data ─────────────────────────────────── /dashboard/at: get: summary: AT dashboard — quick stats and active cases responses: "200": content: application/json: schema: type: object properties: stats: type: object properties: full_count: type: integer example: 72 modified_count: type: integer example: 8 out_count: type: integer example: 3 active_cases: type: array items: $ref: "#/components/schemas/CaseSummary" recent_activity: type: array items: $ref: "#/components/schemas/ActivityItem" # ── Sideline ───────────────────────────────────────── /body-parts: get: summary: Body part categories and parts for the sideline entry picker responses: "200": description: Body part hierarchy (categories → parts) content: application/json: schema: type: array items: $ref: "#/components/schemas/BodyPartCategory" components: schemas: Athlete: type: object required: - id - first_name - last_name - sport - team - grade properties: id: type: string example: "ath_001" first_name: type: string example: "Jake" last_name: type: string example: "Larson" sport: type: string example: "Football" team: type: string example: "Varsity" grade: type: integer example: 11 initials: type: string example: "JL" description: Computed from first/last name, could also be server-generated active: type: boolean default: true Case: type: object required: - case_id - athlete_id - injury - status properties: case_id: type: string example: "cas_001" athlete_id: type: string example: "ath_001" injury: type: string example: "Ankle Sprain (Grade 2)" injury_date: type: string format: date example: "2026-04-28" body_part: type: string example: "Ankle" side: type: string enum: [Left, Right, null] nullable: true example: "Right" severity: type: string enum: [mild, moderate, severe] attention: type: string enum: [stable, urgent, warning] description: >- stable = on track. warning = behind schedule, need check-in. urgent = medical concern, review today. status: type: string enum: [active, cleared, referred] phase: type: integer example: 2 total_phases: type: integer example: 4 phase_label: type: string description: Human-readable current phase name example: "Active Rehab" projected_return: type: string format: date nullable: true example: "2026-05-12" last_updated: type: string example: "2026-05-01 14:00" last_updated_by: type: string example: "You" notified: type: array items: type: string example: ["Coach Andrews", "Parent"] milestones: type: array items: $ref: "#/components/schemas/Milestone" timeline: type: array items: $ref: "#/components/schemas/TimelineEvent" Milestone: type: object properties: num: type: integer description: Phase number (1-based) example: 2 label: type: string description: Phase name example: "Active Rehab" status: type: string enum: [done, current, pending] completed: type: string format: date nullable: true note: type: string example: "Walking without limp. ROM 75%. Strength work initiated." TimelineEvent: type: object properties: date: type: string example: "Apr 28 · 3:15 PM" description: Display-ready date string or ISO-8601 timestamp title: type: string example: "Initial Assessment" note: type: string example: "Grade 2 lateral ankle sprain. Swelling +2, unable to bear weight." by: type: string example: "You" type: type: string enum: [assessment, restriction, milestone, clearance, note] description: Drives the colored dot in the timeline UI CaseSummary: type: object properties: athlete_id: type: string athlete_name: type: string initials: type: string sport: type: string injury: type: string injury_short: type: string example: "Ankle sprain (Grade 2)" status: type: string enum: [active, cleared, referred] status_label: type: string example: "Phase 2/4" avatar_color: type: string description: CSS-compatible color string for avatar background example: "teal" ActivityItem: type: object properties: type: type: string enum: [cleared, out, modified] text: type: string example: "Marcus Johnson cleared for full practice" time_ago: type: string example: "2h ago" BodyPartCategory: type: object properties: name: type: string example: "Lower Body" parts: type: array items: type: object properties: id: type: string example: "ankle" label: type: string example: "Ankle" icon: type: string example: "🦶"