398 lines
14 KiB
Markdown
398 lines
14 KiB
Markdown
# 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](https://docs.astral.sh/uv/)
|
|
- Node.js 22 LTS avec npm
|
|
- Git
|
|
|
|
### Backend
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
- Application : http://localhost:3000 (proxy automatique `/api` vers le backend)
|
|
|
|
### Docker / Podman
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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`)
|
|
|
|
```python
|
|
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
|
|
```python
|
|
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
|
|
|
|
```bash
|
|
# 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')"
|
|
```
|