RTSport Backend
FastAPI-based REST API for athletic training case management in scholastic sports.
Architecture
- Framework: FastAPI 0.111.0
- Database: PostgreSQL with SQLAlchemy ORM
- Schemas: Pydantic v2
- Auth: JWT-based (FERPA-compliant role system)
Quick Start
Prerequisites
- Python 3.11+
- PostgreSQL 14+
Installation
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/Mac
# or: venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Set up environment variables
cp .env.example .env
# Edit .env with your database credentials
Database Setup
# Create database
createdb rtsport
# Initialize tables
python -c "from app.database import init_db; init_db()"
Running the Server
# Development (with auto-reload)
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Production
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
Project Structure
backend/
โโโ app/
โ โโโ __init__.py
โ โโโ main.py # FastAPI app factory
โ โโโ config.py # Settings management
โ โโโ database.py # SQLAlchemy engine/session
โ โโโ schemas.py # Pydantic v2 schemas (5 models)
โ โโโ models.py # SQLAlchemy ORM models
โ โโโ api/
โ โโโ __init__.py
โ โโโ roster.py # GET /api/v1/roster
โ โโโ cases.py # GET /api/v1/cases/*
โ โโโ events.py # POST /api/v1/events/sideline-entry
โโโ requirements.txt
โโโ README.md
API Endpoints
Read Operations
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/roster |
Get athlete roster (with filters) |
| GET | /api/v1/roster/{athlete_id} |
Get single athlete |
| GET | /api/v1/cases/{athlete_id} |
Get cases for athlete |
| GET | /api/v1/cases/{case_id}/timeline |
Get event timeline |
| GET | /api/v1/cases/{case_id}/milestones |
Get case milestones |
Write Operations
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/events/sideline-entry |
3-tap rapid entry |
Data Models
1. School (Tenant)
- Multi-tenant boundary - every model has
school_id - Config JSON for branding and sport name mappings
2. Athlete
- Central roster node
current_status: cached property (cleared|restricted|out)- Updated via DB trigger on event creation
3. Case
- Single injury lifecycle
severity(clinical, static) โattention_level(operational, daily)- Resolved via
clearance_grantedevent (reopenable within 30 days)
4. Milestone
- Forward-looking targets (Phase Bar UI)
- Separate from Events (backward-looking records)
5. Event
- Every sideline entry, note, or clearance
visibilitydefaults to["at"]- must explicitly expandclinical_notesstripped server-side for non-AT roles
FERPA Compliance
Role-based access matrix:
| Entity | AT | Coach | Parent |
|---|---|---|---|
| Roster | Full | Team Only | No Access |
| Cases | Full | Active Status Only | Own Child Only |
| Timeline | All | visibility: coach |
visibility: parent |
| Clinical Notes | Read/Write | HARD BLOCK | HARD BLOCK |
| Restrictions | Write | Read-Only | Read-Only |
Environment Variables
# Required
DATABASE_URL=postgresql://user:pass@localhost:5432/rtsport
SECRET_KEY=your-secret-key-here
# Optional
DEBUG=true
ACCESS_TOKEN_EXPIRE_MINUTES=10080 # 7 days
CORS_ORIGINS=["http://localhost:3000"]
Development Notes
Auto-Case Creation (Sideline Entry)
The POST /api/v1/events/sideline-entry endpoint:
1. Checks for existing active case for athlete + body_part
2. Creates new Case if none exists
3. Creates initial Event
4. Updates athlete.current_status via DB trigger
Status Synchronization
SQLAlchemy event listeners in models.py handle:
- restriction_added event โ athlete.status = "restricted"
- clearance_granted event โ athlete.status = "cleared" + case.resolved
Database Indexes
All tables indexed on:
- school_id (tenant isolation)
- Foreign keys (query performance)
- Array fields using GIN (JSONB/ARRAY queries)
Testing
# Run tests (when implemented)
pytest
# With coverage
pytest --cov=app --cov-report=html
Contract Alignment
Source of truth: ../docs/contract.md
- All 5 Pydantic schemas validate against contract ยง1
- All 4 GET + 1 POST endpoints match contract ยง2
- FERPA matrix implemented per contract ยง3
- Multi-tenant by
school_idper contract ยง4