✨ Changements majeurs: - Suppression complète du code Flask legacy - Migration backend FastAPI vers racine /backend - Migration frontend Vue.js vers racine /frontend - Suppression de notytex-v2/ (code monté à la racine) ✅ Validations: - Backend démarre correctement (port 8000) - API /api/v2/health répond healthy - 99/99 tests unitaires passent - Frontend configuré avec proxy Vite 📝 Documentation: - README.md réécrit pour v2 - Instructions de démarrage mises à jour - .gitignore adapté pour backend/frontend/ 🎯 Architecture finale: notytex/ ├── backend/ # FastAPI + SQLAlchemy + Pydantic ├── frontend/ # Vue 3 + Vite + TailwindCSS ├── docs/ # Documentation └── school_management.db # Base de données (inchangée) Jalon 6 complété: Application v2 prête pour utilisation!
115 lines
2.9 KiB
Python
115 lines
2.9 KiB
Python
"""
|
|
Schemas Pydantic pour le conseil de classe.
|
|
"""
|
|
|
|
from datetime import date, datetime
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
from pydantic import Field
|
|
|
|
from schemas.common import BaseSchema
|
|
|
|
|
|
class AssessmentGradeInfo(BaseSchema):
|
|
"""Information sur les notes d'un élève pour une évaluation."""
|
|
|
|
id: int
|
|
title: str
|
|
date: Optional[date]
|
|
score: float
|
|
max_score: float = 20.0
|
|
coefficient: float = 1.0
|
|
|
|
|
|
class StudentTrimesterSummaryRead(BaseSchema):
|
|
"""Résumé d'un élève pour un trimestre."""
|
|
|
|
student_id: int
|
|
first_name: str
|
|
last_name: str
|
|
full_name: str
|
|
overall_average: Optional[float]
|
|
assessment_count: int
|
|
grades_by_assessment: Dict[int, AssessmentGradeInfo]
|
|
performance_status: str # 'excellent', 'good', 'average', 'struggling', 'no_data'
|
|
has_appreciation: bool
|
|
appreciation_status: Optional[str] = None # 'draft', 'finalized'
|
|
|
|
|
|
class PerformanceDistribution(BaseSchema):
|
|
"""Distribution des performances de la classe."""
|
|
|
|
excellent: int = 0
|
|
good: int = 0
|
|
average: int = 0
|
|
struggling: int = 0
|
|
no_data: int = 0
|
|
|
|
|
|
class ClassStatisticsRead(BaseSchema):
|
|
"""Statistiques de la classe pour un trimestre."""
|
|
|
|
mean: Optional[float]
|
|
median: Optional[float]
|
|
min: Optional[float]
|
|
max: Optional[float]
|
|
std_dev: Optional[float]
|
|
performance_distribution: PerformanceDistribution
|
|
student_count_with_data: int = 0
|
|
total_students: int = 0
|
|
|
|
|
|
class AppreciationStatsRead(BaseSchema):
|
|
"""Statistiques de completion des appréciations."""
|
|
|
|
total_students: int
|
|
completed_appreciations: int
|
|
draft_appreciations: int
|
|
finalized_appreciations: int
|
|
completion_percentage: float
|
|
|
|
|
|
class CouncilPreparationRead(BaseSchema):
|
|
"""Données complètes pour la préparation du conseil de classe."""
|
|
|
|
class_group_id: int
|
|
class_name: str
|
|
trimester: int
|
|
student_summaries: List[StudentTrimesterSummaryRead]
|
|
class_statistics: ClassStatisticsRead
|
|
appreciation_stats: AppreciationStatsRead
|
|
total_students: int
|
|
completed_appreciations: int
|
|
|
|
|
|
class AppreciationCreate(BaseSchema):
|
|
"""Données pour créer/mettre à jour une appréciation."""
|
|
|
|
general_appreciation: Optional[str] = None
|
|
strengths: Optional[str] = None
|
|
areas_for_improvement: Optional[str] = None
|
|
status: str = Field(default="draft", pattern="^(draft|finalized)$")
|
|
|
|
|
|
class AppreciationRead(BaseSchema):
|
|
"""Lecture d'une appréciation."""
|
|
|
|
id: int
|
|
student_id: int
|
|
class_group_id: int
|
|
trimester: int
|
|
general_appreciation: Optional[str]
|
|
strengths: Optional[str]
|
|
areas_for_improvement: Optional[str]
|
|
status: str
|
|
last_modified: datetime
|
|
created_at: datetime
|
|
|
|
|
|
class AppreciationResponse(BaseSchema):
|
|
"""Réponse après sauvegarde d'une appréciation."""
|
|
|
|
success: bool
|
|
message: str
|
|
appreciation: AppreciationRead
|