πŸ† Team Tryouts β€” Architecture Documentation

UML Class Diagram & Functional System Architecture

πŸ“Š Project Statistics

19
SQLAlchemy Model Classes
8
Route Blueprints
4
Flask Extensions
2
Association Tables (M2M)
50+
Route Endpoints
8
Utility Modules

πŸ“ UML Class Diagram β€” All 19 Model Classes

classDiagram class User { +int id +str username +str password_hash +str role +str full_name +str email +str phone +bool is_active_account +datetime created_at +int failed_login_attempts +datetime locked_until +str games +str discord_username +str discord_user_id +str league_os_profile +get_games_list() +has_role() +can_evaluate() +can_manage_users() +can_manage_tryouts() +can_manage_teams() +can_schedule_matches() +can_manage_this_tryout() +can_manage_this_org_team() +get_gamertags() +get_org_teams() } class UserGamertag { +int id +int user_id +str game +str gamertag +str platform +get_trn_url() } class OrgTeam { +int id +str name +int created_by +datetime created_at +int coach_id +int manager_id +get_coaches() +get_managers() +players() +get_players_with_status() } class TeamPlayer { +int id +int player_id +int org_team_id +str status +str position +datetime added_at } class Tryout { +int id +str title +str description +str game +date date +str location +str status +int max_players +int created_by +int target_org_team_id +int manager_id +int coach_id +datetime created_at } class TryoutRegistration { +int id +int tryout_id +int player_id +datetime registered_at +str status +str notes } class Evaluation { +int id +int tryout_id +int player_id +int evaluator_id +int mecanics_score +int cohesion_score +int communication_score +int gamesense_score +int versatility_score +int discipline_score +int analysis_score +int sport_ethics_score +int mental_score +float overall_score +str comments +str position_recommendation +datetime created_at +datetime updated_at } class Team { +int id +int tryout_id +str name +int created_by +datetime created_at } class TeamMember { +int id +int team_id +int player_id +str position +datetime added_at } class Match { +int id +int tryout_id +str title +str description +date date +time start_time +time end_time +str location +str status +str match_type +int created_by +datetime created_at +int team1_id +int team2_id +get_participating_players() } class PlayerDisponibility { +int id +int player_id +int day_of_week +time start_time +time end_time +datetime created_at +datetime updated_at } class MatchParticipant { +int id +int match_id +int player_id +int team_side +str position +bool attendance_confirmed +datetime added_at } class Contract { +int id +int player_id +int team_id +int uploaded_by_id +str original_filename +str stored_filename +str file_path +str signed_filename +str signed_file_path +str status +str notes +datetime uploaded_at +datetime signed_at +can_view() +can_upload_signed() } class CoachAvailability { +int id +int coach_id +int day_of_week +time start_time +time end_time +datetime created_at +datetime updated_at } class TeamNote { +int id +int org_team_id +int coach_id +str content +datetime created_at +datetime updated_at } class PersonalNote { +int id +int player_id +int coach_id +str content +datetime created_at +datetime updated_at +int match_id +int team_id +int tryout_id } class OneOnOneRequest { +int id +int player_id +int coach_id +int org_team_id +date date +time start_time +time end_time +str points +str status +datetime created_at +datetime responded_at +bigint discord_message_id +str coach_rejection_message } class TeamMatch { +int id +int org_team_id +str title +str description +str opponent +date date +time start_time +time end_time +str location +str status +int created_by +datetime created_at +get_confirmed_count() } class TeamMatchParticipant { +int id +int team_match_id +int player_id +bool is_confirmed +datetime added_at } class load_user { +load_user(user_id) } User "1" --> "*" UserGamertag : gamertags User "1" --> "*" Tryout : created_by User "1" --> "*" Tryout : managed_tryouts User "1" --> "*" Tryout : coached_tryouts User "1" --> "*" Evaluation : evaluations_given User "1" --> "*" Evaluation : evaluations_received User "1" --> "*" TryoutRegistration : tryout_registrations User "1" --> "*" TeamMember : team_assignments User "1" --> "*" TeamPlayer : team_placements User "1" --> "*" Match : created_matches User "1" --> "*" TeamMatch : created_team_matches User "1" --> "*" PlayerDisponibility : disponibilities User "1" --> "*" CoachAvailability : coach_availabilities User "1" --> "*" Team : created_teams User "1" --> "*" Contract : contracts User "1" --> "*" PersonalNote : personal_notes User "1" --> "*" OneOnOneRequest : one_on_one_requests OrgTeam "1" --> "*" TeamPlayer : team_players OrgTeam "1" --> "*" Tryout : tryouts OrgTeam "1" --> "*" TeamNote : team_notes OrgTeam "1" --> "*" TeamMatch : team_matches OrgTeam "1" --> "*" OneOnOneRequest : requests OrgTeam "1" --> "*" Contract : contracts Tryout "1" --> "*" TryoutRegistration : registrations Tryout "1" --> "*" Evaluation : evaluations Tryout "1" --> "*" Team : teams Tryout "1" --> "*" Match : matches Tryout "1" --> "*" PersonalNote : notes Team "1" --> "*" TeamMember : members Team "1" --> "*" Match : matches_as_team1 Team "1" --> "*" Match : matches_as_team2 Match "1" --> "*" MatchParticipant : participants Match "1" --> "*" PersonalNote : notes TeamMatch "1" --> "*" TeamMatchParticipant : participants User .. load_user : loads

πŸ”€ Functional Architecture β€” Request Flow & Component Graph

graph TD subgraph CLIENT["🌐 Client Layer"] BROWSER["Browser / User"] DISCORD_APP["Discord App"] MONITOR["Monitoring / LB"] end subgraph PROXY["πŸ”„ Reverse Proxy"] NGINX["Nginx
(TLS termination,
static files,
rate limiting)"] end subgraph APP["🐍 Flask Application (create_app)"] direction TB subgraph INGRESS["Incoming"] BEFORE_REQ["@before_request
force_https()"] CSRF_CHECK["CSRF Validate"] LIMITER_CHECK["Rate Limiter
200/day Β· 50/hr"] LOGIN_CHECK["@login_required"] end subgraph BLUEPRINTS["πŸ“¦ Route Blueprints (8 total)"] AUTH_BP["auth_bp
━━━━━━━
⁕ /auth/login
⁕ /auth/register
⁕ /auth/logout
⁕ /auth/profile
⁕ /auth/change-password
⁕ /auth/delete-account"] MAIN_BP["main_bp
━━━━━━━
⁕ /
⁕ /dashboard
⁕ /privacy
⁕ /terms"] TRYOUTS_BP["tryouts_bp
━━━━━━━
⁕ /tryouts/
⁕ /tryouts/create
⁕ /tryouts/{id}
⁕ /tryouts/{id}/register
⁕ /tryouts/{id}/edit
⁕ /tryouts/{id}/delete"] TEAMS_BP["teams_bp
━━━━━━━
⁕ /teams/
⁕ /teams/create
⁕ /teams/{id}
⁕ /teams/{id}/edit
⁕ /teams/{id}/delete
⁕ /teams/{id}/add-player"] MATCHES_BP["matches_bp
━━━━━━━
⁕ /matches/
⁕ /matches/create
⁕ /matches/{id}
⁕ /matches/{id}/edit"] TEAM_MATCHES_BP["team_matches_bp
━━━━━━━
⁕ /team-matches/
⁕ /team-matches/create
⁕ /team-matches/{id}
⁕ /team-matches/{id}/edit
⁕ /team-matches/{id}/delete"] USERS_BP["users_bp
━━━━━━━
⁕ /users/
⁕ /users/create
⁕ /users/{id}
⁕ /users/{id}/delete
⁕ /users/disponibilities/
⁕ /users/coach-availability/
⁕ /users/api/gamertags"] EVALS_BP["evaluations_bp
━━━━━━━
⁕ /evaluations/
⁕ /evaluations/create
⁕ /evaluations/{id}
⁕ /evaluations/{id}/edit
⁕ /evaluations/{id}/delete"] end subgraph EGRESS["Outgoing"] AFTER_REQ["@after_request
add_security_headers()"] ERROR_HANDLERS["Error Handlers
400 Β· 401 Β· 403 Β· 404
429 Β· 500 Β· HTTPException"] HEALTH["GET /health"] end end subgraph EXTENSIONS["πŸ”Œ Flask Extensions"] DB_EXT["SQLAlchemy
(db)"] LOGIN_EXT["Flask-Login
(login_manager)"] CSRF_EXT["CSRFProtect
(csrf)"] LIMITER_EXT["Flask-Limiter
(limiter)"] end subgraph MODELS["πŸ—„οΈ SQLAlchemy Models (models.py)"] direction LR USER_M["User"] TRYOUT_M["Tryout"] EVAL_M["Evaluation"] ORGTEAM_M["OrgTeam"] TEAM_M["Team"] MATCH_M["Match"] TEAMMATCH_M["TeamMatch"] OTHERS_M["...15 more classes"] end subgraph DB["πŸ’Ύ Database"] SQLITE["SQLite / PostgreSQL
(SQLALCHEMY_DATABASE_URI)"] end subgraph UTILS["πŸ› οΈ Utility Modules"] VALIDATORS["validators.py
Password/username validation"] LOGGING["logging_config.py
Structured logging"] DISCORD_BOT["discord_bot.py
Discord notifications
+ reaction handling"] SECURITY["security_scan.py
Security audit tool"] SEED["seed.py
Database seeding"] BACKUP["backup.py
Database backup"] MIGRATE["migrate_usernames.py
Username migration"] end subgraph TEMPLATES["πŸ–ΌοΈ Jinja2 Templates"] PAGES["templates/pages/
(~30 HTML pages)"] LAYOUTS["templates/layouts/
(base, nav)"] ERRORS_TPL["templates/errors/
(400, 401, 403, 404, 429, 500)"] end subgraph STATIC["πŸ“ Static Assets"] CSS_F["static/css/"] JS_F["static/js/"] end subgraph EXTERNAL["🌍 External APIs"] TRN_API["TRN / Tracker.gg
(gamertag profiles)"] DISCORD_API["Discord API
(bot notifications)"] end %% ========== FLOW ========== BROWSER --> NGINX NGINX --> BEFORE_REQ BEFORE_REQ --> CSRF_CHECK CSRF_CHECK --> LIMITER_CHECK LIMITER_CHECK --> LOGIN_CHECK LOGIN_CHECK --> BLUEPRINTS BLUEPRINTS --> AFTER_REQ AFTER_REQ --> BROWSER %% Blueprint to models AUTH_BP -.-> USER_M TRYOUTS_BP -.-> TRYOUT_M EVALS_BP -.-> EVAL_M TEAMS_BP -.-> ORGTEAM_M MATCHES_BP -.-> MATCH_M TEAM_MATCHES_BP -.-> TEAMMATCH_M USERS_BP -.-> USER_M %% Models to DB MODELS --> DB %% Extensions DB_EXT --> MODELS LOGIN_EXT --> USER_M CSRF_EXT --> BLUEPRINTS LIMITER_EXT --> BLUEPRINTS %% Utilities VALIDATORS -.-> AUTH_BP VALIDATORS -.-> USERS_BP LOGGING -.-> APP DISCORD_BOT --> DISCORD_API DISCORD_BOT -.-> MATCHES_BP DISCORD_BOT -.-> TEAM_MATCHES_BP DISCORD_BOT -.-> USERS_BP SEED -.-> DB BACKUP -.-> DB %% Templates & Static BLUEPRINTS --> TEMPLATES TEMPLATES --> STATIC %% External USER_M -.-> TRN_API MONITOR --> HEALTH %% Discord DISCORD_APP --> DISCORD_BOT

πŸ—ΊοΈ Legend

SQLAlchemy Models β€” Database entity classes
Route Blueprints β€” Flask route groups
Flask Extensions β€” SQLAlchemy, Login, CSRF, Limiter
Utility Modules β€” Logging, validators, seeding, backups
External APIs β€” Discord, TRN/Tracker.gg
Middleware β€” Security headers, HTTPS redirect, error handlers
─── Solid arrow = HTTP request flow
- - - Dashed arrow = Data access / logical dependency