Skip to content

Architecture

The Player Wellness App is a single-page Streamlit application backed by a PostgreSQL database. It is intentionally simple — the registration app captures data, and all analysis and reporting happens in a separate reporting application.


File structure

player_wellness_registration/
├── main.py                        # Streamlit app — UI only, no DB logic
├── database.py                    # All database interaction
├── models.py                      # SQLAlchemy ORM table definitions
├── requirements.txt               # Python dependencies
├── images/
│   └── BORG_RPE_scale.png         # Static reference image
├── .streamlit/
│   └── secrets.toml               # Database connection string (not in git)
└── docs/                          # MkDocs documentation source
    ├── mkdocs.yml
    └── docs/
        ├── index.md
        ├── user-guide/
        └── developer/

Layer responsibilities

File Responsibility
main.py Page config, tab layout, all Streamlit UI widgets
database.py Engine creation, player queries, wellness and RPE inserts
models.py SQLAlchemy ORM class definitions, table constraints

main.py only imports from database.py. It never touches SQLAlchemy directly. This keeps the UI layer clean and makes the database layer independently testable.


Request flow

Player opens app
    → get_engine() creates SQLAlchemy engine (cached for session)
    → Base.metadata.create_all() verifies / creates tables
    → get_player_ids() populates the player ID selectbox

Player submits Pre-Training form
    → insert_wellness() writes a row to player_wellness
    → duplicate submission (same player_id + session_id) is silently ignored

Player submits Post-Training form
    → insert_rpe() calculates session_load = rpe_score × training_minutes
    → writes a row to player_rpe
    → duplicate submission is silently ignored

Session ID

The session_id is a string key derived in the UI from the selected date and the first two digits of the player ID:

session_id = f"{date.strftime('%Y%m%d')}U{str(player_id)[:2]}"
# Example: player 7, date 3 Sep 2024 → "20240903U07"

This key links player registrations to sessions in the reporting app. Session records in the sessions table are created separately by coaching staff. Player registrations are never blocked by a missing session — the link is resolved at reporting time.


Idempotent inserts

Both insert_wellness and insert_rpe are idempotent. If a player submits the same form twice for the same session, the second submission is silently ignored via a UNIQUE constraint on (player_id, session_id). The player sees a success message either way.