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) :
notes: valeurs numériques décimales (ex: 15.5/20) — calcul directscore: é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
- API : http://localhost:8000/api/v2/docs (Swagger)
- ReDoc : http://localhost:8000/api/v2/redoc
Frontend
cd frontend
npm install
npm run dev
- Application : http://localhost:3000 (proxy automatique
/apivers le backend)
Docker / Podman
cd docker
cp .env.example .env
# Modifier SECRET_KEY dans .env
docker compose up -d # ou podman-compose up -d
- Frontend : http://localhost:8081
- API : http://localhost:8080/api/v2/docs
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 coursgrading.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 :
mypyrecommandé pour les nouvelles fonctions - Async : toutes les routes et accès DB sont
async/await - Noms : snake_case, noms explicites (
calculate_student_scores, pascalc)
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.jspour 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
- Créer le schéma Pydantic dans
backend/schemas/ - Ajouter la route dans
backend/api/routes/ - Utiliser
AsyncSessionDeppour l'accès DB - Écrire les tests dans
backend/tests/
Ajouter une page frontend
- Créer le composant Vue dans
frontend/src/views/ - Ajouter la route dans
frontend/src/router/index.js - Créer un store Pinia si nécessaire dans
frontend/src/stores/ - Réutiliser les composants existants de
frontend/src/components/
Modifier la logique de notation
- Modifier
backend/domain/services/grading_calculator.py - Mettre à jour les tests dans
backend/tests/unit/test_grading_calculator.py - 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')"