Files
notytex/docs/DOMAIN_COMPETENCE_PERSPECTIVE.md

11 KiB
Raw Blame History

Perspective Enseignant - Domaines et Compétences

Date: 3 décembre 2025
Type: Changement de perspective - Ce qui a été évalué vs Résultats des élèves

🎯 Objectif du Changement

Passer d'une perspective centrée sur les résultats des élèves à une perspective centrée sur ce qui a été évalué par l'enseignant.

Avant (Perspective Élèves)

Domaine Algèbre:
- 75 évaluations (25 élèves × 3 questions)
- 187.5 / 250 points

Difficile à interpréter : mélange le nombre d'élèves et les évaluations

Après (Perspective Enseignant)

Domaine Algèbre:
- 3 éléments de notation
- 10 points maximum

Clair et actionnable : l'enseignant voit ce qu'il a créé


📊 Cas d'Usage Concrets

Scénario 1: Vérifier l'équilibre d'un trimestre

Données affichées:

Domaines:
- Algèbre      : 8 éléments, 25 points
- Géométrie    : 3 éléments, 12 points  ← Sous-représenté
- Probabilités : 2 éléments, 8 points   ← Sous-représenté
- Calcul       : 6 éléments, 18 points

Action enseignant: Créer plus d'évaluations sur Géométrie et Probabilités pour le prochain contrôle.

Scénario 2: Analyser une évaluation

Données affichées:

Compétences:
- Calculer    : 5 éléments, 15 points
- Raisonner   : 3 éléments, 12 points
- Communiquer : 1 élément, 5 points   ← Sous-représenté

Action enseignant: Ajouter des questions de communication dans la prochaine évaluation.

Scénario 3: Comparer les trimestres

Domaine T1 T2 T3
Algèbre 8 éléments, 25pts 6 éléments, 18pts 10 éléments, 30pts
Géométrie 3 éléments, 12pts 7 éléments, 20pts 5 éléments, 15pts

Insight: L'enseignant voit qu'il a moins travaillé la géométrie au T3, peut ajuster pour l'année suivante.


🔧 Modifications Techniques

Backend

1. Nouveau Service (backend/domain/services/class_statistics_service.py)

Méthode ajoutée: calculate_domain_competence_from_elements()

Logique:

for assessment in assessments:
    for exercise in assessment.exercises:
        for element in exercise.grading_elements:
            # Compter par domaine
            if element.domain_id:
                domain_count[element.domain_id] += 1
                domain_points[element.domain_id] += element.max_points
            
            # Compter par compétence (via skill)
            if element.skill:
                competence = find_competence_by_name(element.skill)
                if competence:
                    competence_count[competence.id] += 1
                    competence_points[competence.id] += element.max_points

Retourne:

  • evaluation_count: Nombre de GradingElements utilisant ce domaine/compétence
  • total_points_possible: Somme des max_points de ces éléments
  • total_points_obtained: 0 (non pertinent dans cette perspective)

2. Endpoint modifié (backend/api/routes/classes.py)

Chargement des relations:

assessments_query = (
    select(Assessment)
    .options(
        selectinload(Assessment.exercises).selectinload(Exercise.grading_elements)
    )
    .where(...)
)

Utilisation du nouveau service:

# AVANT
domains_stats, competences_stats = stats_service.aggregate_domain_competence_stats(
    student_averages=student_averages,
    domains=domains,
    competences=competences,
)

# APRÈS
domains_stats, competences_stats = stats_service.calculate_domain_competence_from_elements(
    assessments=assessments,  # Avec exercises et grading_elements chargés
    domains=domains,
    competences=competences,
)

Frontend

1. Affichage modifié (frontend/src/views/ClassDashboardView.vue)

Template:

<!-- AVANT -->
<div>
  <span>{{ domain.name }}</span>
  <span>{{ domain.total_points_obtained }}/{{ domain.total_points_possible }}</span>
  <p>{{ domain.evaluation_count }} évaluations</p>
</div>

<!-- APRÈS -->
<div>
  <span>{{ domain.name }}</span>
  <span>{{ domain.total_points_possible }} points</span>
  <p>{{ domain.evaluation_count }} élément(s) de notation</p>
</div>

Titres modifiés:

  • "Statistiques par domaine" → "Évaluations par domaine"
  • "Statistiques par compétence" → "Évaluations par compétence"

Sous-titre ajouté:

  • "Perspective enseignant : ce qui a été évalué"

2. Barre de progression relative

Nouvelle logique:

function getRelativeWidth(item, allItems) {
  const maxPoints = Math.max(...allItems.map(d => d.total_points_possible || 0))
  if (maxPoints === 0) return 0
  return ((item.total_points_possible || 0) / maxPoints) * 100
}

Utilisation:

<div class="progress-bar">
  <div :style="{ width: `${getRelativeWidth(domain, stats.domains_stats)}%` }"></div>
</div>

La barre montre la proportion relative par rapport au domaine le plus évalué, pas un pourcentage absolu.


📈 Comparaison Avant/Après

Exemple avec une classe de 25 élèves, 2 contrôles

Contrôle 1 (Trimestre 1):

  • Q1: Algèbre, 5 points
  • Q2: Algèbre, 3 points
  • Q3: Géométrie, 4 points

Contrôle 2 (Trimestre 1):

  • Q1: Algèbre, 2 points
  • Q2: Probabilités, 5 points

Avant (Perspective Élèves)

Domaine Algèbre:

  • evaluation_count: 75 (3 questions × 25 élèves)
  • total_points_obtained: 187.5 (moyenne hypothétique)
  • total_points_possible: 250 ((5+3+2) × 25)

Affichage: "75 évaluations - 187.5/250" → Illisible pour l'enseignant

Après (Perspective Enseignant)

Domaine Algèbre:

  • evaluation_count: 3 (nombre de questions posées)
  • total_points_possible: 10 (5+3+2)

Affichage: "3 éléments de notation - 10 points" → Très lisible et actionnable


🎓 Avantages Pédagogiques

1. Clarté

  • Indépendant du nombre d'élèves: 3 éléments restent 3 éléments
  • Unité cohérente: Points = barème défini par l'enseignant

2. Planification

  • Voir rapidement quels domaines ont été peu évalués
  • Équilibrer les évaluations entre domaines
  • Comparer les trimestres facilement

3. Réflexivité

  • Analyse de pratique: "Ai-je trop évalué l'algèbre ?"
  • Diversification: "Dois-je ajouter plus de géométrie ?"
  • Cohérence: "Mon programme est-il équilibré ?"

4. Communication

  • Conseil de classe: "J'ai évalué 8 fois l'algèbre ce trimestre"
  • Parents: "Voici la répartition de mes évaluations"
  • Équipe pédagogique: "Comparons nos pratiques d'évaluation"

🔍 Détails d'Implémentation

Gestion des Compétences

Mapping via element.skill:

if element.skill:
    matching_competence = next(
        (c for c in competences if c.name == element.skill),
        None
    )

Logique:

  • Les compétences sont stockées dans GradingElement.skill (champ texte libre)
  • Le matching se fait par nom de compétence
  • Si aucune correspondance: la compétence n'est pas comptée

Amélioration future: Ajouter competence_id dans GradingElement pour éviter le matching par nom.

Performance

Requête optimisée:

# Un seul trip à la base de données
assessments = session.execute(
    select(Assessment)
    .options(selectinload(Assessment.exercises).selectinload(Exercise.grading_elements))
    .where(...)
).scalars().all()

Complexité: O(n) où n = nombre total de GradingElements du trimestre

Charge typique:

  • 5 évaluations × 15 éléments/évaluation = 75 éléments à parcourir
  • Temps: < 10ms

Données Retournées

Structure JSON:

{
  "domains_stats": [
    {
      "id": 1,
      "name": "Algèbre",
      "color": "#3B82F6",
      "evaluation_count": 3,
      "total_points_obtained": 0.0,
      "total_points_possible": 10.0
    }
  ],
  "competences_stats": [
    {
      "id": 1,
      "name": "Calculer",
      "color": "#10B981",
      "evaluation_count": 5,
      "total_points_obtained": 0.0,
      "total_points_possible": 15.0
    }
  ]
}

Note: total_points_obtained est à 0 car non pertinent dans cette perspective.


📁 Fichiers Modifiés

Backend (2 fichiers)

  1. backend/domain/services/class_statistics_service.py

    • Ajout: calculate_domain_competence_from_elements()
    • Logique: Parcours des GradingElements
    • Retour: DomainStats et CompetenceStats
  2. backend/api/routes/classes.py

    • Modification: Chargement des assessments avec relations
    • Modification: Appel de la nouvelle méthode de calcul

Frontend (1 fichier)

  1. frontend/src/views/ClassDashboardView.vue
    • Modification: Titres ("Évaluations par..." au lieu de "Statistiques par...")
    • Modification: Affichage (points seuls au lieu de obtained/possible)
    • Modification: Texte ("élément(s) de notation" au lieu de "évaluations")
    • Ajout: Fonction getRelativeWidth() pour barre proportionnelle
    • Ajout: Sous-titre explicatif "Perspective enseignant : ce qui a été évalué"

Tests Suggérés

1. Vérifier le comptage

  • Créer 3 évaluations avec 2, 3, 4 éléments respectivement
  • Vérifier: evaluation_count = 9

2. Vérifier les points

  • Élément 1: 5 points
  • Élément 2: 3 points
  • Élément 3: 2 points
  • Vérifier: total_points_possible = 10

3. Vérifier le filtrage par domaine

  • 3 éléments Algèbre, 2 éléments Géométrie
  • Vérifier: Algèbre montre 3, Géométrie montre 2

4. Vérifier les compétences

  • Créer des éléments avec skill = "Calculer"
  • Vérifier: Compétence "Calculer" affiche le bon nombre

5. Vérifier l'absence de données

  • Domaine sans éléments: evaluation_count = 0, total_points_possible = 0
  • Affichage: "0 élément(s) de notation - 0 points"

🚀 Utilisation

Accéder au Dashboard

http://localhost:5173/classes/{id}

Vérifier l'affichage

  1. Sélectionner un trimestre
  2. Scroller jusqu'aux sections "Évaluations par domaine/compétence"
  3. Vérifier:
    • Titre: "Évaluations par domaine/compétence"
    • Sous-titre: "Perspective enseignant : ce qui a été évalué"
    • Affichage: "X points" (pas de fraction)
    • Texte: "X élément(s) de notation"
    • Barre proportionnelle au domaine le plus évalué

🎯 Conclusion

Cette modification transforme le dashboard d'une vue résultats (complexe, orientée élèves) en une vue enseignant (simple, orientée pratique pédagogique).

Impact pédagogique:

  • Meilleure visibilité sur la répartition des évaluations
  • Aide à l'équilibrage du programme
  • Facilite la réflexion sur les pratiques d'évaluation
  • Indépendant du nombre d'élèves (plus cohérent)

Impact technique:

  • Code plus simple (pas de double comptage élèves × éléments)
  • Requêtes optimisées avec selectinload
  • Données plus claires et exploitables