progression 50% pour evolution des joueurs
CI - Security, Lint & Tests / validate (push) Failing after 1m13s
CI - Security, Lint & Tests / validate (push) Failing after 1m13s
This commit is contained in:
+21
-1
@@ -21,6 +21,11 @@ from app.models._constants import (
|
||||
PLATFORM_CODES,
|
||||
TRN_URLS,
|
||||
EVALUATION_CRITERIA,
|
||||
OBJECTIVE_TYPES,
|
||||
OBJECTIVE_STATUSES,
|
||||
OBJECTIVE_PRIORITIES,
|
||||
OBJECTIVE_CHECK_FREQUENCIES,
|
||||
DEFAULT_OBJECTIVE_TEMPLATES,
|
||||
)
|
||||
|
||||
# =========================================================================
|
||||
@@ -96,4 +101,19 @@ from app.models.personal_note import PersonalNote
|
||||
from app.models.one_on_one_request import OneOnOneRequest
|
||||
from app.models.admin_settings import AppSettings
|
||||
from app.models.backup_record import BackupRecord
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.models.audit_log import AuditLog
|
||||
|
||||
# =========================================================================
|
||||
# Layer 12: player evolution objectives
|
||||
# =========================================================================
|
||||
from app.models.objective import Objective # noqa: F401 — new table for create_all()
|
||||
|
||||
# =========================================================================
|
||||
# Layer 13: player evolution entries (KPI measurements)
|
||||
# =========================================================================
|
||||
from app.models.objective_entry import ObjectiveEntry # noqa: F401
|
||||
|
||||
# =========================================================================
|
||||
# Layer 14: objective comments (coach feedback, no existing-schema change)
|
||||
# =========================================================================
|
||||
from app.models.objective_comment import ObjectiveComment # noqa: F401
|
||||
|
||||
@@ -69,6 +69,79 @@ PLATFORM_CODES = {
|
||||
|
||||
PLATFORM_DEFAULTS = {'Apex Legends': 'pc', 'Rainbow Six Siege': 'ubi', 'Rocket League': 'epic'}
|
||||
|
||||
# Objective-related constants for the Player Evolution planning feature.
|
||||
# Ordered lists of (value, human_label) pairs for form fields and display.
|
||||
OBJECTIVE_TYPES = [
|
||||
('individual', 'Individuel'),
|
||||
('team', 'Équipe'),
|
||||
]
|
||||
|
||||
OBJECTIVE_STATUSES = [
|
||||
('active', 'Actif'),
|
||||
('pending', 'En attente'),
|
||||
('completed', 'Terminé'),
|
||||
('overdue', 'En retard'),
|
||||
]
|
||||
|
||||
OBJECTIVE_PRIORITIES = [
|
||||
('low', 'Faible'),
|
||||
('medium', 'Moyenne'),
|
||||
('high', 'Élevée'),
|
||||
]
|
||||
|
||||
OBJECTIVE_CHECK_FREQUENCIES = [
|
||||
('weekly', 'Hebdomadaire'),
|
||||
('biweekly', 'Bi-hebdomadaire'),
|
||||
('monthly', 'Mensuelle'),
|
||||
]
|
||||
|
||||
# Default templates seeded on first run.
|
||||
# (priority, title, description, kpi_metric, kpi_target, kpi_unit, type, category)
|
||||
DEFAULT_OBJECTIVE_TEMPLATES = [
|
||||
# Quantitative
|
||||
('medium', 'Améliorer le taux de headshot (HS)',
|
||||
'Augmenter le pourcentage de têtes sur les kills totaux.',
|
||||
'Taux de headshot', 45.0, '%', 'individual', 'Mécaniques'),
|
||||
('medium', 'Augmenter le K/D ratio',
|
||||
'Améliorer le ratio kills/morts sur les matchs compétitifs.',
|
||||
'K/D Ratio', 1.2, '', 'individual', 'Performance'),
|
||||
('medium', 'Atteindre un KDA cible',
|
||||
'Maintenir un ratio kills/deaths/assists au-dessus du seuil.',
|
||||
'KDA', 3.0, '', 'individual', 'Performance'),
|
||||
('medium', 'Améliorer la précision',
|
||||
'Augmenter le pourcentage de tirs touchés par partie.',
|
||||
'Précision', 40.0, '%', 'individual', 'Mécaniques'),
|
||||
('medium', 'Augmenter les CS par minute',
|
||||
'Atteindre une moyenne de last-hits par minute en jeu.',
|
||||
'CS/min', 8.0, '', 'individual', 'Farm'),
|
||||
('medium', 'Réduire les morts par match',
|
||||
'Diminuer le nombre de décès moyens par partie compétitive.',
|
||||
'Morts/match', 5.0, '', 'individual', 'Survie'),
|
||||
('medium', 'Augmenter les dégâts par round',
|
||||
'Améliorer le damage output moyen par round joué.',
|
||||
'Dégâts/round', 150.0, '', 'individual', 'Performance'),
|
||||
('medium', 'Améliorer le taux de victoire',
|
||||
'Augmenter le pourcentage de parties gagnées sur la saison.',
|
||||
'Winrate', 55.0, '%', 'team', 'Compétitif'),
|
||||
|
||||
# Qualitative
|
||||
('medium', 'Améliorer le positionnement',
|
||||
'Travailler le placement sur la carte pour réduire les angles exposés.',
|
||||
None, None, None, 'individual', 'Positionnement'),
|
||||
('medium', 'Améliorer la communication',
|
||||
'Être plus vocal et clair dans les callouts en équipe.',
|
||||
None, None, None, 'individual', 'Communication'),
|
||||
('medium', 'Développer la conscience de carte',
|
||||
'Anticiper les rotations adverses et mieux lire la minimap.',
|
||||
None, None, None, 'individual', 'Game Sense'),
|
||||
('medium', 'Améliorer la prise de décision',
|
||||
'Réduire les décisions risquées et améliorer le choix des engagements.',
|
||||
None, None, None, 'individual', 'Decision'),
|
||||
('medium', 'Renforcer la cohésion d\'équipe',
|
||||
'Participer activement aux stratégies collectives et aux drills.',
|
||||
None, None, None, 'team', 'Équipe'),
|
||||
]
|
||||
|
||||
TRN_URLS = {
|
||||
'Valorant': 'https://tracker.gg/valorant/profile/riot/{username}',
|
||||
'League of Legends': 'https://tracker.gg/lol/riot/profile/{username}',
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
"""Player evolution objective — individual or team KPI-based goal."""
|
||||
|
||||
from app.extensions import db
|
||||
from app.time_utils import utc_now_naive
|
||||
|
||||
|
||||
class Objective(db.Model):
|
||||
"""Player evolution objective — a KPI-driven plan for individual players
|
||||
or teams, created and tracked by coaching staff.
|
||||
|
||||
Covers the full lifecycle: draft (pending), active, completed, overdue.
|
||||
Supports arbitrary KPI metrics, optional tags, and verifiable progress.
|
||||
"""
|
||||
|
||||
__tablename__ = 'objectives'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
title = db.Column(db.String(200), nullable=False)
|
||||
description = db.Column(db.Text, nullable=True)
|
||||
|
||||
# Category
|
||||
type = db.Column(
|
||||
db.String(20),
|
||||
nullable=False,
|
||||
default='individual',
|
||||
)
|
||||
status = db.Column(
|
||||
db.String(20),
|
||||
nullable=False,
|
||||
default='active',
|
||||
)
|
||||
priority = db.Column(
|
||||
db.String(20),
|
||||
nullable=False,
|
||||
default='medium',
|
||||
)
|
||||
category = db.Column(db.String(50), nullable=True)
|
||||
is_template = db.Column(db.Boolean, default=False, nullable=False)
|
||||
|
||||
# Assignment (individual player / org team)
|
||||
player_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
|
||||
team_id = db.Column(db.Integer, db.ForeignKey('org_teams.id'), nullable=True)
|
||||
|
||||
# KPI fields
|
||||
kpi_metric = db.Column(db.String(120), nullable=True)
|
||||
kpi_target = db.Column(db.Numeric(10, 2), nullable=True)
|
||||
kpi_unit = db.Column(db.String(20), nullable=True)
|
||||
kpi_precision = db.Column(db.Integer, nullable=True)
|
||||
|
||||
# Timeline
|
||||
start_date = db.Column(db.Date, nullable=True)
|
||||
due_date = db.Column(db.Date, nullable=False)
|
||||
check_frequency = db.Column(db.String(30), nullable=True)
|
||||
|
||||
# Progress tracking (0–100)
|
||||
progress = db.Column(db.Integer, default=0, nullable=False)
|
||||
|
||||
# Misc
|
||||
tags = db.Column(db.String(255), nullable=True)
|
||||
|
||||
# Who created it
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
|
||||
# Timestamps
|
||||
created_at = db.Column(db.DateTime, default=utc_now_naive)
|
||||
updated_at = db.Column(db.DateTime, default=utc_now_naive, onupdate=utc_now_naive)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Relationships
|
||||
# -----------------------------------------------------------------------
|
||||
player = db.relationship(
|
||||
'User',
|
||||
foreign_keys=[player_id],
|
||||
backref=db.backref('objectives', lazy='dynamic'),
|
||||
)
|
||||
team = db.relationship(
|
||||
'OrgTeam',
|
||||
foreign_keys=[team_id],
|
||||
backref=db.backref('objectives', lazy='dynamic'),
|
||||
)
|
||||
creator = db.relationship(
|
||||
'User',
|
||||
foreign_keys=[created_by],
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
"""Coach comments on a specific objective."""
|
||||
|
||||
from app.extensions import db
|
||||
from app.time_utils import utc_now_naive
|
||||
|
||||
|
||||
class ObjectiveComment(db.Model):
|
||||
"""A coach's comment on a player-evolution objective.
|
||||
|
||||
This is a separate table from PersonalNote — no existing schema
|
||||
is altered. The objective-form page also *reads* PersonalNote and
|
||||
TeamNote for context, but never writes to those tables.
|
||||
"""
|
||||
|
||||
__tablename__ = 'objective_comments'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
objective_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('objectives.id'),
|
||||
nullable=False,
|
||||
)
|
||||
coach_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
content = db.Column(db.Text, nullable=False)
|
||||
created_at = db.Column(db.DateTime, default=utc_now_naive)
|
||||
updated_at = db.Column(db.DateTime, default=utc_now_naive, onupdate=utc_now_naive)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Relationships
|
||||
# -----------------------------------------------------------------------
|
||||
objective = db.relationship(
|
||||
'Objective',
|
||||
backref=db.backref('comments', lazy='dynamic', order_by='ObjectiveComment.created_at'),
|
||||
)
|
||||
coach = db.relationship('User', foreign_keys=[coach_id])
|
||||
@@ -0,0 +1,39 @@
|
||||
"""Player evolution — KPI measurement entries for objectives."""
|
||||
|
||||
from app.extensions import db
|
||||
from app.time_utils import utc_now_naive
|
||||
|
||||
|
||||
class ObjectiveEntry(db.Model):
|
||||
"""A single KPI measurement recorded for an objective.
|
||||
|
||||
Each entry records a value at a point in time so the evolution
|
||||
graph can plot historical data and compute a trend line.
|
||||
"""
|
||||
|
||||
__tablename__ = 'objective_entries'
|
||||
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
objective_id = db.Column(
|
||||
db.Integer,
|
||||
db.ForeignKey('objectives.id'),
|
||||
nullable=False,
|
||||
)
|
||||
value = db.Column(db.Numeric(10, 2), nullable=True)
|
||||
recorded_at = db.Column(db.DateTime, nullable=False, default=utc_now_naive)
|
||||
note = db.Column(db.Text, nullable=True)
|
||||
|
||||
# Who recorded it
|
||||
recorded_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
|
||||
|
||||
# Timestamps
|
||||
created_at = db.Column(db.DateTime, default=utc_now_naive)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Relationships
|
||||
# -----------------------------------------------------------------------
|
||||
objective = db.relationship(
|
||||
'Objective',
|
||||
backref=db.backref('entries', lazy='dynamic', order_by='ObjectiveEntry.recorded_at'),
|
||||
)
|
||||
recorder = db.relationship('User', foreign_keys=[recorded_by])
|
||||
Reference in New Issue
Block a user