UML avec la derniere version du projet
This commit is contained in:
@@ -0,0 +1,799 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Team Tryouts — Architecture v3 (Refactored)</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #1a1a2e;
|
||||
--surface: #16213e;
|
||||
--primary: #0f3460;
|
||||
--accent: #e94560;
|
||||
--text: #eee;
|
||||
--text-muted: #aaa;
|
||||
--border: #2a2a4a;
|
||||
--card-bg: #1e2a3a;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.6;
|
||||
}
|
||||
header {
|
||||
background: var(--surface);
|
||||
border-bottom: 2px solid var(--accent);
|
||||
padding: 1.5rem 2rem;
|
||||
text-align: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
box-shadow: 0 2px 20px rgba(0,0,0,0.5);
|
||||
}
|
||||
header h1 {
|
||||
font-size: 1.8rem;
|
||||
color: var(--accent);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
header p {
|
||||
color: var(--text-muted);
|
||||
margin-top: 0.25rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
nav a {
|
||||
background: var(--primary);
|
||||
color: var(--text);
|
||||
padding: 0.5rem 1.5rem;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
transition: background 0.2s, transform 0.2s;
|
||||
}
|
||||
nav a:hover {
|
||||
background: var(--accent);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
main {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
section {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
section h2 {
|
||||
color: var(--accent);
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
section h2 .icon { font-size: 1.4rem; }
|
||||
.mermaid-wrapper {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
overflow-x: auto;
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,0.3);
|
||||
}
|
||||
.legend {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 1rem 1.5rem;
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.legend-dot {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
.legend-dot.model { background: #4fc3f7; }
|
||||
.legend-dot.subpackage { background: #aed581; }
|
||||
.legend-dot.blueprint { background: #ffb74d; }
|
||||
.legend-dot.extension { background: #81c784; }
|
||||
.legend-dot.utility { background: #ba68c8; }
|
||||
.legend-dot.external { background: #e57373; }
|
||||
.legend-dot.middleware { background: #4dd0e1; }
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.8rem;
|
||||
border-top: 1px solid var(--border);
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.stat-card {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
.stat-card .stat-num {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
.stat-card .stat-label {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
main { padding: 1rem; }
|
||||
header h1 { font-size: 1.3rem; }
|
||||
.mermaid-wrapper { padding: 1rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>🏆 Team Tryouts — Architecture v3 (Refactored)</h1>
|
||||
<p>UML Class Diagram & Functional Graph — 7 Subpackages + 6 Standalone Models</p>
|
||||
<nav>
|
||||
<a href="#stats">Overview</a>
|
||||
<a href="#uml">UML Class Diagram</a>
|
||||
<a href="#packages">Package Structure</a>
|
||||
<a href="#functional">Functional Graph</a>
|
||||
<a href="#legend">Legend</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
|
||||
<!-- ============ STATS ============ -->
|
||||
<section id="stats">
|
||||
<h2><span class="icon">📊</span> Project Statistics</h2>
|
||||
<div class="stats">
|
||||
<div class="stat-card"><div class="stat-num">31</div><div class="stat-label">Python files in models/</div></div>
|
||||
<div class="stat-card"><div class="stat-num">7</div><div class="stat-label">Subpackages</div></div>
|
||||
<div class="stat-card"><div class="stat-num">24</div><div class="stat-label">Classes (incl. abstract)</div></div>
|
||||
<div class="stat-card"><div class="stat-num">8</div><div class="stat-label">Route Blueprints</div></div>
|
||||
<div class="stat-card"><div class="stat-num">4</div><div class="stat-label">Flask Extensions</div></div>
|
||||
<div class="stat-card"><div class="stat-num">8</div><div class="stat-label">Utility Modules</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ UML CLASS DIAGRAM ============ -->
|
||||
<section id="uml">
|
||||
<h2><span class="icon">📐</span> UML Class Diagram — All 24 Classes, Relationships & Inheritance</h2>
|
||||
<div class="mermaid-wrapper">
|
||||
|
||||
<div class="mermaid">
|
||||
classDiagram
|
||||
class BaseAvailability {
|
||||
+int day_of_week
|
||||
+time start_time
|
||||
+time end_time
|
||||
+datetime created_at
|
||||
+datetime updated_at
|
||||
}
|
||||
class PlayerDisponibility {
|
||||
+int id
|
||||
+int player_id
|
||||
}
|
||||
class CoachAvailability {
|
||||
+int id
|
||||
+int coach_id
|
||||
}
|
||||
BaseAvailability <|-- PlayerDisponibility : extends
|
||||
BaseAvailability <|-- CoachAvailability : extends
|
||||
|
||||
class BaseMatch {
|
||||
+str title
|
||||
+str description
|
||||
+date date
|
||||
+time start_time
|
||||
+time end_time
|
||||
+str location
|
||||
+str status
|
||||
+int created_by
|
||||
+datetime created_at
|
||||
}
|
||||
class Match {
|
||||
+int id
|
||||
+int tryout_id
|
||||
+str match_type
|
||||
+int team1_id
|
||||
+int team2_id
|
||||
+get_participating_players()
|
||||
}
|
||||
class TeamMatch {
|
||||
+int id
|
||||
+int org_team_id
|
||||
+str opponent
|
||||
+get_confirmed_count()
|
||||
}
|
||||
BaseMatch <|-- Match : extends
|
||||
BaseMatch <|-- TeamMatch : extends
|
||||
|
||||
class BaseParticipant {
|
||||
+int player_id
|
||||
+datetime added_at
|
||||
}
|
||||
class MatchParticipant {
|
||||
+int id
|
||||
+int match_id
|
||||
+int team_side
|
||||
+str position
|
||||
+bool attendance_confirmed
|
||||
}
|
||||
class TeamMatchParticipant {
|
||||
+int id
|
||||
+int team_match_id
|
||||
+bool is_confirmed
|
||||
}
|
||||
BaseParticipant <|-- MatchParticipant : extends
|
||||
BaseParticipant <|-- TeamMatchParticipant : extends
|
||||
|
||||
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()
|
||||
+get_gamertags()
|
||||
+get_org_teams()
|
||||
+can_evaluate()
|
||||
+can_manage_users()
|
||||
+can_manage_teams()
|
||||
+can_manage_tryouts()
|
||||
+can_schedule_matches()
|
||||
+can_manage_this_tryout()
|
||||
+can_manage_this_org_team()
|
||||
+get_visible_tryouts()
|
||||
}
|
||||
class Admin {
|
||||
+all permissions = True
|
||||
}
|
||||
class Manager {
|
||||
+can_manage_teams()
|
||||
+can_manage_tryouts()
|
||||
}
|
||||
class Coach {
|
||||
+can_evaluate()
|
||||
+can_schedule_matches()
|
||||
+can_manage_this_tryout()
|
||||
+can_manage_this_org_team()
|
||||
}
|
||||
class Player {
|
||||
+get_visible_tryouts()
|
||||
}
|
||||
class Scout {
|
||||
+can_evaluate()
|
||||
+get_visible_tryouts()
|
||||
}
|
||||
User <|-- Admin : polymorphic
|
||||
User <|-- Manager : polymorphic
|
||||
User <|-- Coach : polymorphic
|
||||
User <|-- Player : polymorphic
|
||||
User <|-- Scout : polymorphic
|
||||
|
||||
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 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 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 load_user {
|
||||
+load_user(user_id)
|
||||
}
|
||||
|
||||
User "1" --> "*" UserGamertag : gamertags
|
||||
User "1" --> "*" Tryout : created_tryouts
|
||||
User "1" --> "*" Tryout : managed_tryouts
|
||||
User "1" --> "*" Tryout : coached_tryouts
|
||||
User "1" --> "*" Evaluation : evaluations_given
|
||||
User "1" --> "*" Evaluation : evaluations_received
|
||||
User "1" --> "*" TryoutRegistration : 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 : 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 : as_team1
|
||||
Team "1" --> "*" Match : as_team2
|
||||
Match "1" --> "*" MatchParticipant : participants
|
||||
Match "1" --> "*" PersonalNote : notes
|
||||
|
||||
TeamMatch "1" --> "*" TeamMatchParticipant : participants
|
||||
|
||||
User .. load_user : loads
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ PACKAGE STRUCTURE ============ -->
|
||||
<section id="packages">
|
||||
<h2><span class="icon">📦</span> Model Package Structure — 7 Subpackages</h2>
|
||||
<div class="mermaid-wrapper">
|
||||
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
subgraph MODELS["app/models/ — 31 files"]
|
||||
direction TB
|
||||
INIT["__init__.py — master re-exporter"]
|
||||
CONST["_constants.py — USER_TYPES, ESPORT_GAMES, GAME_POSITIONS, etc."]
|
||||
LOADERS["_loaders.py — Flask-Login load_user()"]
|
||||
ASSOC["_associations.py — M2M association tables"]
|
||||
|
||||
subgraph USER_PKG["user_model/ (7 files)"]
|
||||
USER["user.py — User base (polymorphic)"]
|
||||
ADMIN["admin.py — Admin(User)"]
|
||||
MGR["manager.py — Manager(User)"]
|
||||
COACH["coach.py — Coach(User)"]
|
||||
PLAYER["player.py — Player(User)"]
|
||||
SCOUT["scout.py — Scout(User)"]
|
||||
end
|
||||
|
||||
subgraph AVAIL_PKG["availability/ (4 files)"]
|
||||
BASE_AVAIL["base.py — BaseAvailability (abstract)"]
|
||||
PD["player_disponibility.py — PlayerDisponibility"]
|
||||
CA["coach_availability.py — CoachAvailability"]
|
||||
end
|
||||
|
||||
subgraph MATCH_PKG["match_model/ (4 files)"]
|
||||
BASE_M["base.py — BaseMatch (abstract)"]
|
||||
MATCH["match.py — Match (tryout-scoped)"]
|
||||
TM["team_match.py — TeamMatch (regular season)"]
|
||||
end
|
||||
|
||||
subgraph PARTIC_PKG["participant/ (4 files)"]
|
||||
BASE_P["base.py — BaseParticipant (abstract)"]
|
||||
MP["match_participant.py — MatchParticipant"]
|
||||
TMP["team_match_participant.py — TeamMatchParticipant"]
|
||||
end
|
||||
|
||||
subgraph ORG_PKG["org_team/ (3 files)"]
|
||||
ORG["org_team.py — OrgTeam"]
|
||||
TP["team_player.py — TeamPlayer"]
|
||||
end
|
||||
|
||||
subgraph TRYOUT_PKG["tryout/ (3 files)"]
|
||||
TRY["tryout.py — Tryout"]
|
||||
TR["tryout_registration.py — TryoutRegistration"]
|
||||
end
|
||||
|
||||
subgraph TEAM_PKG["team/ (3 files)"]
|
||||
TEAM["team.py — Team (tryout-specific)"]
|
||||
TMEMBER["team_member.py — TeamMember"]
|
||||
end
|
||||
|
||||
subgraph STANDALONE["6 Standalone Files"]
|
||||
EVAL["evaluation.py"]
|
||||
CONTRACT["contract.py"]
|
||||
GT["user_gamertag.py"]
|
||||
TN["team_note.py"]
|
||||
PN["personal_note.py"]
|
||||
OOO["one_on_one_request.py"]
|
||||
end
|
||||
end
|
||||
|
||||
INIT --> USER_PKG
|
||||
INIT --> AVAIL_PKG
|
||||
INIT --> MATCH_PKG
|
||||
INIT --> PARTIC_PKG
|
||||
INIT --> ORG_PKG
|
||||
INIT --> TRYOUT_PKG
|
||||
INIT --> TEAM_PKG
|
||||
INIT --> STANDALONE
|
||||
INIT --> CONST
|
||||
INIT --> LOADERS
|
||||
INIT --> ASSOC
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ FUNCTIONAL ARCHITECTURE ============ -->
|
||||
<section id="functional">
|
||||
<h2><span class="icon">🔀</span> Functional Architecture — Request Flow & Component Graph</h2>
|
||||
<div class="mermaid-wrapper">
|
||||
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
subgraph CLIENT["Client Layer"]
|
||||
BROWSER["Browser / User"]
|
||||
DISCORD_APP["Discord App"]
|
||||
MONITOR["Monitoring / LB"]
|
||||
end
|
||||
|
||||
subgraph PROXY["Reverse Proxy"]
|
||||
NGINX["Nginx<br/>TLS termination<br/>Static files<br/>Rate limiting"]
|
||||
end
|
||||
|
||||
subgraph APP["Flask Application — create_app()"]
|
||||
subgraph INGRESS["Incoming Middleware"]
|
||||
BEFORE_REQ["before_request<br/>force_https()"]
|
||||
CSRF_CHECK["CSRF Validation"]
|
||||
LIMITER_CHECK["Rate Limiter<br/>200/day | 50/hr"]
|
||||
LOGIN_CHECK["login_required<br/>Permission checks"]
|
||||
end
|
||||
|
||||
subgraph BLUEPRINTS["Route Blueprints (8)"]
|
||||
AUTH_BP["auth_bp /auth<br/>login, register, logout"]
|
||||
MAIN_BP["main_bp /<br/>dashboard, privacy, terms"]
|
||||
TRYOUTS_BP["tryouts_bp /tryouts<br/>CRUD + register"]
|
||||
TEAMS_BP["teams_bp /teams<br/>OrgTeam CRUD"]
|
||||
MATCHES_BP["matches_bp /matches<br/>Tryout match CRUD"]
|
||||
TEAM_MATCHES_BP["team_matches_bp /team-matches<br/>Season match CRUD"]
|
||||
USERS_BP["users_bp /users<br/>User CRUD, contracts<br/>disponibilities, one-on-one"]
|
||||
EVALS_BP["evaluations_bp /evaluations<br/>9-score evaluations"]
|
||||
end
|
||||
|
||||
subgraph EGRESS["Outgoing Middleware"]
|
||||
AFTER_REQ["after_request<br/>Security headers"]
|
||||
ERRORS["Error Handlers<br/>400 401 403 404 429 500"]
|
||||
HEALTH["GET /health"]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph EXTENSIONS["Flask Extensions"]
|
||||
DB_EXT["SQLAlchemy db"]
|
||||
LOGIN_EXT["LoginManager"]
|
||||
CSRF_EXT["CSRFProtect"]
|
||||
LIMITER_EXT["Flask-Limiter"]
|
||||
end
|
||||
|
||||
subgraph MODELS["SQLAlchemy Models (7 subpackages)"]
|
||||
USER_M["user_model/ — User hierarchy<br/>User, Admin, Manager, Coach, Player, Scout"]
|
||||
AVAIL_M["availability/ — BaseAvailability<br/>PlayerDisponibility, CoachAvailability"]
|
||||
MATCH_M["match_model/ — BaseMatch<br/>Match, TeamMatch"]
|
||||
PARTIC_M["participant/ — BaseParticipant<br/>MatchParticipant, TeamMatchParticipant"]
|
||||
ORG_M["org_team/ — OrgTeam, TeamPlayer"]
|
||||
TRYOUT_M["tryout/ — Tryout, TryoutRegistration"]
|
||||
TEAM_M["team/ — Team, TeamMember"]
|
||||
STANDALONE_M["Standalone: Evaluation, Contract<br/>UserGamertag, TeamNote, PersonalNote<br/>OneOnOneRequest"]
|
||||
end
|
||||
|
||||
subgraph DB["Database"]
|
||||
SQLITE["SQLite / PostgreSQL<br/>DATABASE_URL"]
|
||||
end
|
||||
|
||||
subgraph UTILS["Utility Modules"]
|
||||
VALIDATORS["validators.py<br/>Input validation schemas"]
|
||||
LOGGING["logging_config.py<br/>Structured logging"]
|
||||
DISCORD_BOT["discord_bot.py<br/>Discord notifications<br/>Reaction handling"]
|
||||
SECURITY["security_scan.py<br/>Security audit"]
|
||||
SEED["seed.py<br/>Database seeding"]
|
||||
BACKUP["backup.py<br/>Database backup"]
|
||||
end
|
||||
|
||||
subgraph TEMPLATES["Jinja2 Templates"]
|
||||
PAGES["templates/pages/<br/>~30 HTML pages"]
|
||||
LAYOUTS["templates/layouts/<br/>base, nav"]
|
||||
ERRORS_TPL["templates/errors/<br/>400-500 errors"]
|
||||
end
|
||||
|
||||
subgraph STATIC["Static Assets"]
|
||||
CSS_F["static/css/"]
|
||||
JS_F["static/js/"]
|
||||
end
|
||||
|
||||
subgraph EXTERNAL["External APIs"]
|
||||
TRN_API["TRN / Tracker.gg<br/>Gamertag profiles"]
|
||||
DISCORD_API["Discord API<br/>Bot notifications"]
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
AUTH_BP -.-> USER_M
|
||||
TRYOUTS_BP -.-> TRYOUT_M
|
||||
EVALS_BP -.-> STANDALONE_M
|
||||
TEAMS_BP -.-> ORG_M
|
||||
MATCHES_BP -.-> MATCH_M
|
||||
TEAM_MATCHES_BP -.-> MATCH_M
|
||||
USERS_BP -.-> USER_M
|
||||
|
||||
MODELS --> DB
|
||||
|
||||
DB_EXT --> MODELS
|
||||
LOGIN_EXT --> USER_M
|
||||
CSRF_EXT --> BLUEPRINTS
|
||||
LIMITER_EXT --> BLUEPRINTS
|
||||
|
||||
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
|
||||
|
||||
BLUEPRINTS --> TEMPLATES
|
||||
TEMPLATES --> STATIC
|
||||
|
||||
USER_M -.-> TRN_API
|
||||
MONITOR --> HEALTH
|
||||
DISCORD_APP --> DISCORD_BOT
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ============ LEGEND ============ -->
|
||||
<section id="legend">
|
||||
<h2><span class="icon">🗺️</span> Legend</h2>
|
||||
<div class="legend">
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot model"></span>
|
||||
<span><strong>Models (abstract)</strong> — BaseAvailability, BaseMatch, BaseParticipant</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot subpackage"></span>
|
||||
<span><strong>Subpackages</strong> — user_model, availability, match_model, participant, org_team, tryout, team</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot blueprint"></span>
|
||||
<span><strong>Blueprints</strong> — Flask route groups</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot extension"></span>
|
||||
<span><strong>Extensions</strong> — SQLAlchemy, Login, CSRF, Limiter</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot utility"></span>
|
||||
<span><strong>Utilities</strong> — Logging, validators, seed, backup, bot</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot external"></span>
|
||||
<span><strong>External APIs</strong> — Discord API, TRN/Tracker.gg</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span class="legend-dot middleware"></span>
|
||||
<span><strong>Middleware</strong> — HTTPS redirect, security headers, errors</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span style="font-weight:bold;color:#ccc;">━━ Solid</span>
|
||||
<span>= HTTP / data flow</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<span style="font-weight:bold;color:#999;">┅┅ Dashed</span>
|
||||
<span>= Logical dependency</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>Team Tryouts © 2026 — Generated from refactored codebase (commit fc1bdc5)</p>
|
||||
<p>31 files · 7 subpackages · 24 classes · 8 blueprints · 4 extensions · 8 utilities</p>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'dark',
|
||||
themeVariables: {
|
||||
primaryColor: '#0f3460',
|
||||
primaryTextColor: '#eee',
|
||||
primaryBorderColor: '#4fc3f7',
|
||||
lineColor: '#4fc3f7',
|
||||
secondaryColor: '#1e2a3a',
|
||||
tertiaryColor: '#16213e',
|
||||
noteBkgColor: '#1a1a2e',
|
||||
noteTextColor: '#aaa',
|
||||
fontFamily: 'Segoe UI, system-ui, -apple-system, sans-serif',
|
||||
fontSize: '13px',
|
||||
},
|
||||
class: { useMaxWidth: false },
|
||||
flowchart: {
|
||||
useMaxWidth: false,
|
||||
htmlLabels: true,
|
||||
curve: 'basis',
|
||||
padding: 20,
|
||||
nodeSpacing: 30,
|
||||
rankSpacing: 60,
|
||||
},
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user