RTSport — Product Roadmap & State of the Build
2026-05-08 | Compiled by Wadsworth 📋
Current Architecture (what actually exists)
Layer 1: RTSport Standalone API (port 8001)
Status: ✅ Core backend built and running
Location: ~/.openclaw/shared/build-20260501/backend/
Framework: FastAPI + SQLAlchemy
Database: SQLite (rtsport_test.db) with PostgreSQL migration path
Auth: JWT with role-based access (at/coach/parent/admin)
| Component | File | Lines | State |
|---|---|---|---|
| Database models | app/models.py |
285 | ✅ Complete — User, School, Athlete, Case, Milestone, Event |
| Pydantic schemas | app/schemas.py |
316 | ✅ Complete |
| JWT Auth | app/auth.py |
191 | ✅ Complete — login, token creation/verification, role guards |
| Auth endpoints | app/api/auth.py |
168 | ✅ Complete — /login (OAuth2), /login/json, /me |
| Athletes API | app/api/athletes.py |
321 | ✅ Complete |
| Cases API | app/api/cases.py |
544 | ✅ Complete — CRUD, milestones |
| Roster API | app/api/roster.py |
328 | ✅ Complete — role-gated (at/coach only) |
| Events API | app/api/events.py |
409 | ✅ Complete — sideline entry, general events |
| Dashboard API | app/api/dashboard.py |
892 | ✅ Largest module — AT/Coach/Parent/AD dashboards |
| Admin API | app/api/admin.py |
320 | ✅ Complete — stats, roster management |
| Seed data | seed_data.py |
— | ⚠️ Only seeds parent@example.com |
| Tests | tests/ |
— | ✅ test_auth.py, generate_test_data.py |
25 live endpoints, role-based access control enforced.
Layer 2: HoffDesk Proxy Layer (port 8000)
Status: ✅ Partial proxy with mock fallbacks
Location: ~/.openclaw/workspace-socrates/hoffdesk-api/
| Component | File | What it does | State |
|---|---|---|---|
| Static mock router | rtsport_mock.py |
Serves static HTML/CSS/JS for all dashboards | ✅ Live via RTS_BASE → shared/current/frontend |
| API proxy | rtsport_api_proxy.py |
Forwards /api/v1/rtsport/* → port 8001 | ✅ Live |
| Coach API (mock) | rtsport_coach_api.py |
In-memory mock data, 8 endpoints, shares MESSAGES with parent API | ✅ Live, bypasses port 8001 |
| Parent API (mock) | rtsport_parent_api.py |
In-memory mock data, 6 endpoints, linked to coach API | ✅ Live, bypasses port 8001 |
| Login router | login_router.py |
Serves /rtsport/login page | ✅ Live |
| Unified auth | auth/router.py |
Session cookies for admin, Bearer for API | ✅ Live (HoffDesk family, not RTSport-specific) |
Layer 3: Frontend (served as static files)
Status: ✅ All role dashboards built
| Dashboard | File | Lines | Features |
|---|---|---|---|
| AT Dashboard | templates/at/dashboard.html |
— | Roster, case management, sideline entry |
| Coach Dashboard | templates/coach/dashboard.html |
~1550 | Roster cards, status filter, injury breakdown, timeline, messages |
| Parent Dashboard | templates/parent/dashboard.html |
~1200 | Child selector, case milestones, restrictions, care team, messages |
| AD Dashboard | templates/ad/dashboard.html |
— | Admin stats, school-wide overview |
| Login | templates/login.html |
67 | Dark theme, role-based redirect |
| Shared components | templates/components/ |
— | Athlete detail, notifications, timeline |
| CSS | 5 files | ~2936 lines | Dark theme, mobile-first, role-specific styles |
| JS | 5 files | ~2726 lines | Tab logic, API clients, auto-login, mock data |
The Two Systems Problem
Right now RTSport runs as two parallel systems:
User → https://hoffdesk.com/rtsport/coach
→ rtsport_mock.py serves coach/dashboard.html
→ dashboard.html JS calls /api/v1/dashboard/coach/status?school_id=schl_001
→ This routes to rtsport_coach_api.py (IN-MEMORY MOCK DATA)
→ NOT the real RTSport API at port 8001
Meanwhile:
RTSport API at port 8001 has full CRUD, real DB, role guards
→ But the frontend doesn't call it directly
→ The proxy at port 8000 → 8001 only handles /api/v1/rtsport/* paths
→ Coach/Parent dashboard endpoints are LOCAL_PATHS (not proxied)
Root cause: The coach and parent dashboard API endpoints are deliberately excluded from the proxy (LOCAL_PATHS in rtsport_api_proxy.py) because they have mock implementations in rtsport_coach_api.py and rtsport_parent_api.py. The real API at 8001 has its own /dashboard/coach and /dashboard/parent endpoints, but they're unreachable from the frontend.
Auth State — What Works, What Doesn't
| Flow | Status | Detail |
|---|---|---|
| Login page | ✅ | /rtsport/login serves dark theme login form |
| Login API call | ✅ | POST /api/v1/auth/login/json → returns JWT + role + school_id |
| Role-based redirect | ✅ | JS routes to correct dashboard based on role |
| Token storage | ✅ | localStorage: rtsport_token, rtsport_role, rtsport_school_id |
| Auto-login (dashboard direct access) | ⚠️ Works, but insecure | Hardcoded credentials in dashboard.html: email: 'parent@example.com', password: 'testpass123' |
| Auth guard on dashboard | ❌ Missing | No redirect to login if token invalid/missing — API calls fail silently |
| Auth guard on API | ⚠️ Partial | Port 8000 mock APIs accept any non-empty token (no real validation). Port 8001 has real JWT validation + role guards. |
| Role-based API access | ✅ Port 8001 | "Access denied. Required role: one of ['at', 'coach']" |
| Password hashing | ✅ | bcrypt via passlib in port 8001 auth.py |
| Session management | ✅ Admin only | Cookie-based for HoffDesk admin, not used for RTSport |
Database: Multi-Tenant Design (already built)
Schema: Single database, school_id on every table
Already implemented in models.py
| Table | Multi-tenant column | Indexed |
|---|---|---|
| schools | id (PK) | domain |
| users | school_id | ✅ school_id, email, role |
| athletes | school_id | ✅ school_id, current_status, sports, team |
| cases | school_id, athlete_id | ✅ school_id, athlete_id, status, opened_at |
| milestones | school_id, case_id | — |
| events | school_id, case_id | — |
Scale model:
- 1 database, ~10 tables, school_id column on every query
- SQLite for dev/small deployments (<100 schools), PostgreSQL for production
- Indexed by school_id on every table — fast multi-tenant queries
- JWT encodes school_id so a user can't query another school's data
Seed data gap: Only parent@example.com is seeded in the real database. Coach, AT, and admin accounts exist only in the mock Python dicts.
Blockers & Prioritized Work
🔴 Blocking Go-To-Market
| # | Blocker | Impact | Effort |
|---|---|---|---|
| 1 | Unify the two API systems — frontend calls real API at 8001, not mock dicts | Users see inconsistent/empty data. Mock data doesn't persist. | Medium (1-2 days) |
| 2 | Seed full test data — coach, AT, admin accounts + realistic athlete roster in the real DB | Can't demo multi-role flows end-to-end | Small (2-4 hours) |
| 3 | Auth guard on dashboards — redirect to login if no valid token | Direct dashboard access shows broken pages | Small (1-2 hours) |
| 4 | Remove hardcoded credentials from dashboard.html | Security risk, even for demo | Small (1 hour — just rely on login page) |
🟡 Needed Before Beta
| # | Item | Detail |
|---|---|---|
| 5 | AT Dashboard: case creation form → real API | Currently uses mock data |
| 6 | Sideline entry → real event creation API | Endpoint exists, frontend not wired |
| 7 | Message persistence — currently in-memory, lost on restart | Port 8001 needs message table + endpoints |
| 8 | Role-based UI — hide elements based on role | Coach shouldn't see AT-only actions |
🟢 Post-Beta / v1.1
| # | Item | Detail |
|---|---|---|
| 9 | PostgreSQL migration | SQLite works for beta, PG needed for concurrent users |
| 10 | Admin onboarding flow — create school, invite users | Currently manual DB inserts |
| 11 | Email notifications | Case updates, milestone completions |
| 12 | Mobile app shell | PWA wrapper around existing responsive HTML |
Go-To-Market Estimate
What's Done
- ✅ Full database schema with multi-tenant design
- ✅ JWT auth with role-based access (bcrypt, token refresh ready)
- ✅ 25 API endpoints with role guards
- ✅ All 5 role dashboards (AT, Coach, Parent, AD, Login)
- ✅ Mobile-first responsive CSS (~3000 lines)
- ✅ Coach dashboard: status cards, injury breakdown, recovery timeline, athlete messages
- ✅ Parent dashboard: child selector, milestones, restrictions, care team, activity feed
- ✅ AT dashboard: roster view, case management UI
- ✅ AD dashboard: admin stats (mock)
- ✅ Sideline entry form (frontend)
- ✅ Shared components (athlete detail, notifications, timeline)
- ✅ HTTPS via Cloudflare, secure in production posture
What Remains
- 🔴 Unify APIs (1-2 days)
- 🔴 Seed data + auth hardening (1 day)
- 🟡 Wire frontend to real API (2-3 days)
- 🟡 Message persistence (1 day)
- 🟡 Polish + bug fixes (1-2 days)
Timeline Estimate
| Milestone | Effort | Target |
|---|---|---|
| Demo-ready (all roles work, real data) | 1 week | May 15 |
| Beta-ready (persistent messages, polished UI) | 2-3 weeks | May 22-29 |
| Production MVP (PG migration, onboarding) | +2 weeks | June 12 |
Immediate Recommended Actions
- Unify APIs — Remove LOCAL_PATHS exclusion in proxy, have coach/parent dashboards call real port 8001 endpoints. Delete mock coach/parent API files.
- Seed database — Add coach@, at@, admin@ accounts + 10-15 athletes with real cases to rtsport_test.db.
- Auth guard — Add 10 lines of JS to each dashboard:
if (!getAuthToken()) window.location = '/rtsport/login' - Kill auto-login — Remove hardcoded credential block from dashboard HTML files.