# 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 ```bash # 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 ```bash # Create database createdb rtsport # Initialize tables python -c "from app.database import init_db; init_db()" ``` ### Running the Server ```bash # 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_granted` event (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 - `visibility` defaults to `["at"]` - must explicitly expand - `clinical_notes` stripped 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 ```bash # 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 ```bash # 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_id` per contract §4