Files
notytex/CLAUDE.md
2026-02-09 17:57:02 +01:00

14 KiB

Notytex v2 - Système de Gestion Scolaire

Notytex est une application web moderne pour la gestion complète des évaluations scolaires. Version 2.0 entièrement réécrite avec FastAPI (backend) et Vue.js 3 (frontend).

Objectif Principal

Simplifier et digitaliser le processus d'évaluation scolaire, de la création des contrôles à la saisie des notes, en offrant une interface moderne, réactive et une API REST documentée.


Architecture Technique

Couche Technologie
Backend FastAPI 0.115+ (Python 3.11-3.13)
ORM SQLAlchemy 2.0.36+ avec aiosqlite (async)
Validation Pydantic 2.10+ / pydantic-settings
Serveur Uvicorn 0.32+ (ASGI)
Frontend Vue.js 3.5+ (Composition API) + Vite 6.0+
State Pinia 2.2+
CSS TailwindCSS 3.4+
Graphiques Chart.js 4.4+ (vue-chartjs)
HTTP client Axios 1.7+
Base de données SQLite (dev/prod), PostgreSQL possible
Déploiement Docker / Podman avec Nginx
Tests pytest + pytest-asyncio (99/99 tests)
Qualité Black, Ruff, ESLint

Modèle de Données (12 tables)

Entités principales (7)

ClassGroup (6ème A, 5ème B...)
    ↓ StudentEnrollment (inscription temporelle : arrivée/départ)
Student (élèves)
    ↓
Assessment (évaluation, rattachée à un trimestre 1/2/3)
    ↓
Exercise (exercices ordonnés)
    ↓
GradingElement (question/compétence, type "notes" ou "score", domaine optionnel)
    ↓
Grade (note individuelle par élève : valeur string + commentaire)
  • CouncilAppreciation : appréciation de conseil de classe (élève + classe + trimestre, statut draft/finalized)

Tables de configuration (5)

  • AppConfig : clé-valeur (ex: context.school_year, grading.special_values)
  • CompetenceScaleValue : échelle de notation (0=Non acquis → 3=Expert, couleurs, ., d, a)
  • Competence : compétences pédagogiques (Calculer, Raisonner...) avec couleur et icône
  • Domain : domaines/tags pour les éléments de notation

Tous les modèles sont dans backend/infrastructure/database/models.py.


Fonctionnalités Clés

Gestion des Classes et Élèves

  • CRUD classes avec année scolaire
  • Inscription temporelle (bitemporal) : dates d'arrivée/départ, transferts, historique
  • Import CSV en masse (séparateur ;, format "NOM Prénoms", gestion doublons)
  • Statistiques par trimestre et par classe

Système d'Évaluation

  • Création unifiée (évaluation + exercices + barème en une fois)
  • Organisation par trimestre (1, 2, 3)
  • Filtrage avancé (trimestre, classe, statut de correction, tri)
  • Indicateurs de progression : rouge (0%), orange (en cours), vert (100%)

Notation Dual Configurable

2 types de notation (par GradingElement) :

  1. notes : valeurs numériques décimales (ex: 15.5/20) — calcul direct
  2. score : échelle fixe 0-3 — converti en points : (value / 3) * max_points

Valeurs spéciales (configurables via interface) :

  • . = pas de réponse (compte comme 0 dans le total)
  • d = dispensé (exclu des calculs)
  • a = absent (compte comme 0)

Analyse et Statistiques

  • Statistiques descriptives (moyenne, médiane, écart-type, min/max, quartiles)
  • Histogrammes de distribution (bins de 1 point, Chart.js)
  • Heatmaps par compétences et par domaines
  • Classement alphabétique avec scores par exercice

Conseil de Classe

  • Préparation automatique avec données consolidées par trimestre
  • Saisie et historique des appréciations (brouillon → finalisé)
  • Vue complète des performances par élève

Envoi de Bilans par Email

  • Génération automatique de bilans individualisés (HTML Jinja2)
  • SMTP configurable (Gmail, Outlook, serveur perso)
  • Envoi en lot avec rapport détaillé succès/erreurs
  • Prévisualisation avant envoi

Structure du Code

notytex/
├── backend/                        # API FastAPI
│   ├── api/
│   │   ├── main.py                # App FastAPI + CORS + lifespan
│   │   ├── dependencies.py        # DI (AsyncSessionDep)
│   │   └── routes/
│   │       ├── assessments.py     # CRUD évaluations + notation + résultats + email
│   │       ├── classes.py         # CRUD classes + import CSV + stats dashboard
│   │       ├── students.py        # CRUD élèves + inscriptions
│   │       ├── config.py          # Configuration système + compétences + domaines
│   │       └── council.py         # Appréciations de conseil de classe
│   │
│   ├── schemas/                   # Modèles Pydantic (validation I/O)
│   │   ├── common.py             # BaseSchema, PaginationParams
│   │   ├── assessment.py         # AssessmentRead, AssessmentCreate...
│   │   ├── student.py            # StudentRead, StudentCreate...
│   │   ├── grading.py            # GradeRead, BulkGradeCreate
│   │   ├── class_group.py        # ClassGroupRead, ClassDashboardStats
│   │   ├── config.py             # ConfigRead, CompetenceCreate
│   │   ├── council.py            # CouncilAppreciationRead
│   │   └── csv_import.py         # CSVImportResponse
│   │
│   ├── domain/                    # Logique métier pure (aucune dépendance framework)
│   │   ├── services/
│   │   │   ├── grading_calculator.py       # Strategy Pattern (Notes/Score)
│   │   │   ├── statistics_service.py       # Statistiques descriptives
│   │   │   ├── score_calculator.py         # Calcul scores élèves
│   │   │   ├── config_service.py           # Valeurs spéciales, signification scores
│   │   │   ├── student_report_service.py   # Génération bilans email
│   │   │   └── class_statistics_service.py # Stats par classe
│   │   └── value_objects/
│   │       ├── progress.py        # ProgressResult, ProgressStatus
│   │       ├── score.py           # GradeValue, ExerciseScore, StudentScore
│   │       └── statistics.py      # StatisticsResult, HistogramBin
│   │
│   ├── infrastructure/
│   │   ├── database/
│   │   │   ├── models.py         # 12 modèles SQLAlchemy
│   │   │   └── session.py        # AsyncSession factory
│   │   └── external/
│   │       └── email_service.py  # Service SMTP
│   │
│   ├── core/
│   │   └── config.py             # pydantic-settings (Settings)
│   │
│   ├── tests/                     # 99 tests
│   │   ├── conftest.py           # Fixtures (SQLite in-memory, AsyncClient)
│   │   ├── unit/                 # Tests services domaine
│   │   ├── integration/          # Tests endpoints API
│   │   └── comparison/           # Tests parité v1 ↔ v2
│   │
│   ├── pyproject.toml            # Dépendances + config Black/Ruff/pytest
│   └── uv.lock
│
├── frontend/                      # SPA Vue.js 3
│   ├── src/
│   │   ├── main.js               # Initialisation app
│   │   ├── App.vue               # Composant racine
│   │   ├── router/index.js       # 14 routes Vue Router
│   │   ├── stores/               # Pinia (classes, assessments, config, notifications)
│   │   ├── services/api.js       # Instance Axios (/api/v2)
│   │   ├── views/                # 14 pages (Dashboard, Grading, Results...)
│   │   ├── components/           # 16+ composants réutilisables
│   │   └── assets/
│   ├── vite.config.js            # Proxy dev /api → localhost:8000
│   ├── tailwind.config.js
│   └── package.json
│
├── docker/
│   ├── docker-compose.yaml       # Production (ports 8080/8081)
│   ├── docker-compose.dev.yaml   # Développement avec hot reload
│   └── .env.example              # Template variables Docker
│
├── school_management.db           # Base SQLite partagée
├── CLAUDE.md                      # Ce fichier
└── README.md                      # Documentation utilisateur

Installation et Lancement

Prérequis

  • Python 3.11-3.13 avec uv
  • Node.js 22 LTS avec npm
  • Git

Backend

cd backend
uv sync --all-extras
uv run python -m uvicorn api.main:app --reload --port 8000

Frontend

cd frontend
npm install
npm run dev

Docker / Podman

cd docker
cp .env.example .env
# Modifier SECRET_KEY dans .env

docker compose up -d        # ou podman-compose up -d

Tests

cd backend

# Tous les tests
uv run pytest tests/ -v

# Tests unitaires
uv run pytest tests/unit/ -v

# Tests de parité v1 ↔ v2
uv run pytest tests/comparison/ -v

# Avec couverture
uv run pytest tests/ --cov=. --cov-report=html

Résultat actuel : 99/99 tests

Les tests utilisent une base SQLite in-memory avec AsyncClient + ASGITransport pour tester les endpoints sans serveur.


Configuration

pydantic-settings (backend/core/config.py)

class Settings(BaseSettings):
    # Base de données
    database_url: Optional[str]       # URL complète SQLAlchemy async
    database_path: Optional[str]      # Chemin simple vers le .db

    # API
    api_v2_prefix: str = "/api/v2"

    # CORS
    cors_origins: list[str] = ["http://localhost:3000", "http://localhost:5173"]

    # Logging
    log_level: str = "INFO"

    # Email (optionnel)
    smtp_server, smtp_port, smtp_username, smtp_password, email_from

    model_config = SettingsConfigDict(env_file=".env")

Toute la config est lue depuis backend/.env et validée par Pydantic au démarrage.

Configuration dynamique (table AppConfig)

Paramètres modifiables à chaud via l'interface web :

  • context.school_year — année scolaire en cours
  • grading.special_values — valeurs spéciales (., d, a)
  • grading.score_meanings — signification des scores 0-3
  • Configuration SMTP pour l'envoi d'emails

Patterns Architecturaux

Strategy Pattern — Calcul de notation

domain/services/grading_calculator.py : GradingStrategy (ABC) avec NotesStrategy et ScoreStrategy, sélectionnées par GradingStrategyFactory selon le grading_type du GradingElement.

Value Objects — Objets immuables du domaine

domain/value_objects/ : ProgressResult, GradeValue, StudentScore, StatisticsResult, HistogramBin. Représentent des résultats de calcul sans identité propre.

Dependency Injection — FastAPI natif

AsyncSessionDep = Annotated[AsyncSession, Depends(get_async_session)]

Injection de la session DB dans chaque route, facilitant le remplacement en tests.

Service Layer — Logique métier découplée

Les services dans domain/services/ n'ont aucune dépendance sur FastAPI ou SQLAlchemy. Ils reçoivent des données brutes et retournent des Value Objects.

Clean Architecture — Séparation en couches

api/ (routes) → schemas/ (validation) → domain/ (métier) → infrastructure/ (DB, email). Les dépendances pointent toujours vers l'intérieur.


Conventions de Code

Backend (Python)

  • Formatage : black (line-length 88, target py311)
  • Linting : ruff (pycodestyle, pyflakes, isort, bugbear, comprehensions)
  • Types : mypy recommandé pour les nouvelles fonctions
  • Async : toutes les routes et accès DB sont async/await
  • Noms : snake_case, noms explicites (calculate_student_scores, pas calc)

Frontend (JavaScript/Vue)

  • Composition API avec <script setup>
  • Pinia stores en style composition (pas Options API)
  • TailwindCSS pour le styling (pas de CSS custom sauf nécessité)
  • Axios via services/api.js pour tous les appels API

Base de données

  • Noms de tables : pluriel anglais (students, assessments)
  • Relations avec relationship() et cascade explicite
  • Modèles identiques à v1 pour compatibilité de la base partagée

Volumétrie (milieu d'année)

  • 5 classes de 25 à 35 élèves
  • 10 à 20 éléments de notation par évaluation
  • 4 évaluations corrigées par classe pour le 1er trimestre
  • 2 évaluations non corrigées ou partiellement corrigées par classe

Public Cible

  • Enseignants du secondaire (collège/lycée)
  • Établissements souhaitant digitaliser leurs évaluations
  • Contexte de coexistence notation classique et évaluation par compétences

Workflow Développeur

Ajouter un endpoint API

  1. Créer le schéma Pydantic dans backend/schemas/
  2. Ajouter la route dans backend/api/routes/
  3. Utiliser AsyncSessionDep pour l'accès DB
  4. Écrire les tests dans backend/tests/

Ajouter une page frontend

  1. Créer le composant Vue dans frontend/src/views/
  2. Ajouter la route dans frontend/src/router/index.js
  3. Créer un store Pinia si nécessaire dans frontend/src/stores/
  4. Réutiliser les composants existants de frontend/src/components/

Modifier la logique de notation

  1. Modifier backend/domain/services/grading_calculator.py
  2. Mettre à jour les tests dans backend/tests/unit/test_grading_calculator.py
  3. Lancer les tests de parité (tests/comparison/) pour vérifier la compatibilité v1

Débogage

# Backend avec rechargement auto
cd backend && uv run python -m uvicorn api.main:app --reload --port 8000

# Inspecter la base
sqlite3 school_management.db ".schema assessment"

# Console interactive
cd backend && uv run python -c "from infrastructure.database.models import *; print('OK')"