openapi: 3.1.0
info:
  title: Study-mate School Orchestrator API
  version: 1.0.0
  description: |
    API REST du tableau de bord pédagogique (Orchestrator) connecté à Ergo-Mate.

    **Identité élève** : UUID scolaire + e-mail scolaire.
    **Sécurité** : UrlEncoded (prioritaire) + JWT Bearer (optionnel) + HTTPS.
    **Multi-tenant** : Chaque requête doit inclure tenant_id (X-Orchestrator-Id header ou body).
    **RBAC** : Contrôle d'accès basé sur les rôles (admin, direction, teacher, inspector, intervenant).

    ## Isolation Multi-tenant (Sprint 3)

    Toutes les requêtes nécessitent un identifiant de tenant valide. L'isolation est garantie par:
    - Header `X-Orchestrator-Id` (recommandé pour JWT)
    - Paramètre `tenant_id` dans le body (pour URLENCODED)
    - Validation stricte: accès inter-tenant bloqué avec 403
    - Audit: tous les refus sont journalisés

    ## Rôles et Permissions (RBAC)

    ### Rôles disponibles:

    - **admin**: Accès complet au tenant
    - **direction**: Vue d'ensemble, rapports agrégés, gestion utilisateurs
    - **teacher**: CRUD sur propres assignments/themes, vue propres élèves
    - **inspector**: Lecture seule sur stats et assignments (audit)
    - **intervenant**: Accès limité aux classes assignées

    ### Matrice de permissions par ressource:

    | Resource | Action | Admin | Direction | Teacher | Inspector | Intervenant |
    |----------|--------|-------|-----------|---------|-----------|-------------|
    | assignments | create | ✅ | ✅ | ✅ | ❌ | ❌ |
    | assignments | read (own) | ✅ | ✅ | ✅ | ❌ | ❌ |
    | assignments | read (all) | ✅ | ✅ | ❌ | ✅ | ❌ |
    | assignments | update (own) | ✅ | ✅ | ✅ | ❌ | ❌ |
    | assignments | update (any) | ✅ | ✅ | ❌ | ❌ | ❌ |
    | assignments | delete | ✅ | ✅ | ✅ (own) | ❌ | ❌ |
    | students | read | ✅ | ✅ | ✅ | ✅ | ✅ |
    | students | create/update | ✅ | ✅ | ❌ | ❌ | ❌ |
    | stats | read | ✅ | ✅ | ✅ (own) | ✅ | ❌ |
    | stats | sync | ✅ | ✅ | ✅ | ❌ | ❌ |
    | dashboard | summary | ✅ | ✅ | ✅ | ✅ | ❌ |
    | dashboard | aggregated | ✅ | ✅ | ❌ | ✅ | ❌ |

    Inclut des webhooks Ergo-Mate → Orchestrator.

servers:
  - url: https://smso.mehdydriouech.fr
    description: Production
  - url: http://localhost:8080
    description: Local dev

tags:
  - name: Auth
    description: Authentification et gestion de session
  - name: Health
    description: État du service
  - name: Students
    description: Gestion et consultation des élèves
  - name: Classes
    description: Gestion des classes
  - name: Themes
    description: Contenus pédagogiques
  - name: Assignments
    description: Création et planification d'activités
  - name: Stats
    description: Statistiques consolidées côté Orchestrator
  - name: Sync
    description: Synchronisation avec Ergo-Mate
  - name: Dashboard
    description: Vues agrégées pour enseignants
  - name: Mistral
    description: Génération IA de contenus
  - name: Webhooks
    description: Réceptions d'événements Ergo-Mate
  - name: Partners
    description: Gestion des clés API et usage partenaires
  - name: Telemetry
    description: Télémétrie et observabilité API
  - name: Analytics
    description: 'Sprint 6: Learning Analytics - KPIs et heatmap pour enseignants'
  - name: Student
    description: 'Sprint 5: Learning Cycle - Endpoints côté élève (missions, progression, badges, révisions)'
  - name: Adaptive
    description: 'Sprint 7: Adaptive Learning - Recommandations IA, difficulté adaptative, mode focus, validation enseignant, détection fatigue'
  - name: Social
    description: 'Sprint 8: Social & Collaborative Learning - Classements, partages, commentaires, révision collective, modération'
  - name: Academic
    description: 'Sprint 9: Academic Data Hub - API lecture seule pour exports ENT/LMS avec rate limiting'
  - name: AI-Copilot
    description: 'Sprint 10: Teacher-AI Copilot - Génération quiz/fiches, insights classe, coach pédagogique, publication Ergo-Mate'
  - name: Ingest
    description: 'Sprint 10: Ingestion de contenu - Upload PDF/audio et extraction de texte'
  - name: Insights
    description: 'Sprint 10: Class Insights - Analytics et top difficultés par classe'
  - name: Coach
    description: 'Sprint 10: Coach Pédagogique - Assistant IA pour enseignants'
  - name: Publish
    description: 'Sprint 10: Publication Ergo-Mate - Publication de thèmes vers catalogue/affectations'
  - name: Catalog
    description: 'Sprint 12: Pedagogical Library - Catalogue interne de thèmes validés et versionnés, accessible aux enseignants du même établissement'
  - name: Quality
    description: 'Sprint 13: AI Quality & Linting - Analyse de confiance IA et détection d''incohérences dans les contenus générés'
  - name: System
    description: 'Sprint 13: System Management - Diagnostic système, backups automatiques, et monitoring de santé'
  - name: Export
    description: 'Sprint 13: Interoperability - Export de thèmes vers formats LMS (QTI 2.2, JSON) pour Moodle, Canvas, Blackboard'
  - name: User
    description: 'Sprint 13: User Management - Gestion de profil utilisateur et onboarding'
  - name: Admin
    description: 'Sprint 14: Admin & Tenant Management - Gestion utilisateurs, classes, rôles, licences, audit log (admin/direction only)'

paths:
  /api/health:
    get:
      tags: [Health]
      summary: État du service
      parameters:
        - name: check
          in: query
          schema:
            type: string
            enum: [db, full]
          description: "Type de vérification (db: test connexion DB)"
      responses:
        '200':
          description: Service opérationnel
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'
              examples:
                basic:
                  value:
                    status: ok
                    version: 1.0.0
                    timestamp: "2025-11-10T10:00:00Z"
                full:
                  value:
                    status: ok
                    version: 1.0.0
                    timestamp: "2025-11-10T10:00:00Z"
                    database:
                      status: ok
                      latency_ms: 12

  /api/auth/login:
    post:
      tags: [Auth]
      summary: Connexion et obtention du JWT
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
            examples:
              teacher:
                value:
                  email: claire.dubois@ife-paris.fr
                  password: Ergo2025!
      responses:
        '200':
          description: Authentification réussie
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/auth/me:
    get:
      tags: [Auth]
      summary: Informations utilisateur connecté
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Profil utilisateur
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/students:
    get:
      tags: [Students]
      summary: Lister les élèves d'une classe
      parameters:
        - name: classId
          in: query
          required: true
          schema:
            type: string
          example: CLASS_PARIS_L1_A
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des élèves
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Student'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
              examples:
                default:
                  value:
                    data:
                      - id: STU_PARIS_001
                        uuid_scolaire: uuid-ergo-paris-001
                        email_scolaire: alice.dupont@etudiant.ife-paris.fr
                        firstname: Alice
                        lastname: Dupont
                        classId: CLASS_PARIS_L1_A
                      - id: STU_PARIS_002
                        uuid_scolaire: uuid-ergo-paris-002
                        email_scolaire: lucas.moreau@etudiant.ife-paris.fr
                        firstname: Lucas
                        lastname: Moreau
                        classId: CLASS_PARIS_L1_A
                    pagination:
                      total: 25
                      limit: 50
                      offset: 0
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/classes:
    get:
      tags: [Classes]
      summary: Lister les classes du tenant
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: promoId
          in: query
          schema:
            type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des classes
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Class'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/classes/{id}:
    get:
      tags: [Classes]
      summary: Détails d'une classe
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Détails de la classe
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Class'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/themes:
    get:
      tags: [Themes]
      summary: Lister les thèmes disponibles
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, active, archived]
        - name: difficulty
          in: query
          schema:
            type: string
            enum: [beginner, intermediate, advanced]
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des thèmes
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Theme'

    post:
      tags: [Themes]
      summary: Créer un nouveau thème
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ThemeCreate'
      responses:
        '201':
          description: Thème créé
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Theme'

  /api/assignments:
    get:
      tags: [Assignments]
      summary: Lister les affectations
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, queued, pushed, ack, error]
        - name: teacherId
          in: query
          schema:
            type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des affectations
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Assignment'

    post:
      tags: [Assignments]
      summary: Créer une affectation (quiz/flashcards/fiche/annales)
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
          description: Clé pour éviter les doublons
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignmentCreate'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AssignmentCreate'
            examples:
              quiz:
                value:
                  api_key: "secret_key"
                  tenant_id: TENANT_INST_PARIS
                  scope: teacher
                  type: quiz
                  themeId: THEME_PARIS_001
                  title: "Quiz Anatomie MS - Révision S1"
                  dueAt: "2025-11-15T18:00:00Z"
                  targets: "CLASS_PARIS_L1_A"
      responses:
        '201':
          description: Affectation créée
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Assignment'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'

  /api/assignments/{id}:
    get:
      tags: [Assignments]
      summary: Détails d'une affectation
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Détails de l'affectation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Assignment'

  /api/sync/pull-stats:
    post:
      tags: [Sync]
      summary: Déclencher un pull des stats depuis Ergo-Mate
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PullStatsRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PullStatsRequest'
      responses:
        '202':
          description: Pull en cours
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SyncLog'
        '400':
          $ref: '#/components/responses/BadRequest'

  /api/stats:
    get:
      tags: [Stats]
      summary: Consulter les stats consolidées
      parameters:
        - name: studentId
          in: query
          schema:
            type: string
        - name: classId
          in: query
          schema:
            type: string
        - name: themeId
          in: query
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Statistiques consolidées
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Stats'

  /api/dashboard/summary:
    get:
      tags: [Dashboard]
      summary: Résumé dashboard enseignant
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: classId
          in: query
          schema:
            type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Résumé statistiques
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DashboardSummary'

  /api/mistral/queue:
    get:
      tags: [Mistral]
      summary: État de la file d'attente Mistral
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Jobs en attente/traitement
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/MistralJob'

    post:
      tags: [Mistral]
      summary: Soumettre un PDF pour génération IA
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                pdf:
                  type: string
                  format: binary
                jobType:
                  type: string
                  enum: [quiz, flashcards, fiche, full_theme]
                metadata:
                  type: string
                  description: JSON metadata
      responses:
        '202':
          description: Job soumis
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MistralJob'

  /api/webhooks/ergo/session-ended:
    post:
      tags: [Webhooks]
      summary: 'Webhook : fin de session côté Ergo-Mate'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SessionEnded'
      responses:
        '204':
          description: Reçu
      security: []

  /api/webhooks/ergo/assignment-ack:
    post:
      tags: [Webhooks]
      summary: "Webhook : accusé d'affectation côté Ergo-Mate"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssignmentAck'
      responses:
        '204':
          description: Reçu
      security: []

  /api/webhooks/ergo/error:
    post:
      tags: [Webhooks]
      summary: 'Webhook : erreur remontée par Ergo-Mate'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ErgoError'
      responses:
        '204':
          description: Reçu
      security: []

  /api/partners/usage:
    get:
      tags: [Partners]
      summary: Usage des clés API partenaires
      description: |
        Retourne les statistiques d'usage, rate limits et quotas des clés API.
        Nécessite le rôle admin ou direction.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: api_key_id
          in: query
          schema:
            type: string
          description: Filtrer par ID de clé API spécifique
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Date de début (YYYY-MM-DD)
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: Date de fin (YYYY-MM-DD)
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Statistiques d'usage des partenaires
          headers:
            X-Request-ID:
              schema:
                type: string
              description: ID unique de la requête pour corrélation
            X-Response-Time:
              schema:
                type: string
              description: Temps de réponse en millisecondes
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PartnersUsage'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/telemetry/stats:
    get:
      tags: [Telemetry]
      summary: Statistiques de télémétrie API
      description: |
        Retourne les métriques de performance, erreurs et observabilité.
        Nécessite le rôle admin ou direction.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: view
          in: query
          required: true
          schema:
            type: string
            enum: [overview, endpoints, errors, performance]
          description: Type de vue télémétrie
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Date de début (YYYY-MM-DD)
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: Date de fin (YYYY-MM-DD)
        - name: endpoint
          in: query
          schema:
            type: string
          description: Filtrer par endpoint spécifique (pour vue performance)
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
          description: Limite de résultats
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Statistiques de télémétrie
          headers:
            X-Request-ID:
              schema:
                type: string
              description: ID unique de la requête pour corrélation
            X-Response-Time:
              schema:
                type: string
              description: Temps de réponse en millisecondes
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TelemetryStats'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # ============================================================
  # Sprint 6: Learning Analytics - Measure & Analyze
  # ============================================================

  /api/analytics/kpis:
    get:
      tags: [Analytics]
      summary: 'E6-DASH: KPIs consolidés pour enseignants'
      description: |
        Retourne les indicateurs clés de performance agrégés:
        - Élèves total et actifs
        - Score moyen et taux de réussite
        - Maîtrise moyenne
        - Sessions totales et complétées
        - Temps total passé
        - Affectations actives et en attente

        **Cache**: 5 minutes (TTL 300s) pour optimisation performances (<1s sur 10k lignes).
        **Filtres**: classe, thème, période (avec persistance localStorage côté client).

        Nécessite le rôle teacher, direction, inspector ou admin.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
          description: Filtrer par classe spécifique
        - name: theme_id
          in: query
          schema:
            type: string
          description: Filtrer par thème spécifique
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Date de début (YYYY-MM-DD), défaut -30 jours
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: Date de fin (YYYY-MM-DD), défaut aujourd'hui
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: KPIs agrégés
          headers:
            X-Request-ID:
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenant_id:
                    type: string
                  filters:
                    type: object
                    properties:
                      class_id:
                        type: string
                        nullable: true
                      theme_id:
                        type: string
                        nullable: true
                      start_date:
                        type: string
                        format: date
                      end_date:
                        type: string
                        format: date
                  kpis:
                    type: object
                    properties:
                      students:
                        type: object
                        properties:
                          total:
                            type: integer
                          active:
                            type: integer
                          active_rate:
                            type: number
                      performance:
                        type: object
                        properties:
                          avg_score:
                            type: number
                          success_rate:
                            type: number
                          avg_mastery:
                            type: number
                      sessions:
                        type: object
                        properties:
                          total:
                            type: integer
                          completed:
                            type: integer
                          completion_rate:
                            type: number
                          avg_score:
                            type: number
                          total_time_hours:
                            type: number
                      assignments:
                        type: object
                        properties:
                          total:
                            type: integer
                          active:
                            type: integer
                          pending:
                            type: integer
                          avg_received:
                            type: number
                          avg_completed:
                            type: number
                  cached:
                    type: boolean
                    description: Indique si les données proviennent du cache
                  generated_at:
                    type: string
                    format: date-time
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/analytics/heatmap:
    get:
      tags: [Analytics]
      summary: 'E6-HEAT: Heatmap des difficultés par compétence/thème'
      description: |
        Retourne une visualisation des difficultés par thème pour cibler la remédiation.

        **Métriques par thème**:
        - Taux d'échec et de réussite
        - Score moyen et maîtrise
        - Nombre d'élèves et tentatives
        - Niveau de difficulté: low, medium, high, critical
        - Erreurs fréquentes

        **CTA**: Lien pour créer une révision sur les thèmes difficiles (échec ≥50%).
        **Cache**: 5 minutes (TTL 300s).

        Nécessite le rôle teacher, direction, inspector ou admin.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
          description: Filtrer par classe spécifique
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Date de début (YYYY-MM-DD), défaut -30 jours
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: Date de fin (YYYY-MM-DD), défaut aujourd'hui
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Heatmap des difficultés
          headers:
            X-Request-ID:
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenant_id:
                    type: string
                  filters:
                    type: object
                    properties:
                      class_id:
                        type: string
                        nullable: true
                      start_date:
                        type: string
                        format: date
                      end_date:
                        type: string
                        format: date
                  heatmap:
                    type: array
                    items:
                      type: object
                      properties:
                        theme_id:
                          type: string
                        theme_title:
                          type: string
                        theme_difficulty:
                          type: string
                          enum: [beginner, intermediate, advanced]
                        metrics:
                          type: object
                          properties:
                            student_count:
                              type: integer
                            total_attempts:
                              type: integer
                            avg_score:
                              type: number
                            avg_mastery:
                              type: number
                            failure_rate:
                              type: number
                            success_rate:
                              type: number
                            min_score:
                              type: number
                            max_score:
                              type: number
                            score_stddev:
                              type: number
                        difficulty_level:
                          type: string
                          enum: [low, medium, high, critical]
                          description: Niveau calculé basé sur le taux d'échec
                        needs_remediation:
                          type: boolean
                          description: True si taux d'échec ≥50%
                        color:
                          type: string
                          description: Code couleur hex pour visualisation
                        common_errors:
                          type: array
                          items:
                            type: object
                            properties:
                              errors:
                                type: array
                              count:
                                type: integer
                  cached:
                    type: boolean
                  generated_at:
                    type: string
                    format: date-time
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # ============================================================
  # Sprint 5: Learning Cycle - Student Endpoints
  # ============================================================

  /api/student/missions/pull:
    get:
      tags: [Student]
      summary: 'E5-MISSIONS: Pull student missions inbox'
      description: |
        Récupère la liste des missions (assignments) pour un élève.
        Inclut le statut local (a_faire, en_cours, terminee) et la progression.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: student_id
          in: query
          required: true
          schema:
            type: string
          description: ID de l'élève
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des missions de l'élève
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudentMissions'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/student/missions/{id}/status:
    patch:
      tags: [Student]
      summary: 'E5-MISSIONS: Update mission status locally'
      description: |
        Met à jour le statut local d'une mission (a_faire, en_cours, terminee).
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [student_id, status]
              properties:
                student_id:
                  type: string
                status:
                  type: string
                  enum: [a_faire, en_cours, terminee]
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Statut mis à jour
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                  status:
                    type: string
                  new_status:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/student/sync/push:
    post:
      tags: [Student]
      summary: 'E5-SYNC: Push student session results'
      description: |
        Pousse les résultats d'une session élève vers l'Orchestrator.
        Auto-sync après chaque session ErgoMate avec retry/backoff.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StudentSyncPush'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/StudentSyncPush'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '202':
          description: Résultats acceptés et synchronisés
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  session_id:
                    type: string
                  sync_log_id:
                    type: string
                  new_badges:
                    type: array
                    items:
                      type: object
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/ServerError'

  /api/student/{id}/progress:
    get:
      tags: [Student]
      summary: 'E5-PROGRESS: Get student progress dashboard'
      description: |
        Dashboard élève avec KPIs, graphiques (score trend, time by theme, mastery radar),
        analyse des forces/faiblesses, et activité récente.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Dashboard de progression élève
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudentProgress'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/student/{id}/review:
    get:
      tags: [Student]
      summary: 'E5-REVIEW: Get items to review (errors)'
      description: |
        Récupère les questions/concepts à réviser basés sur les erreurs passées.
        Permet de rejouer les erreurs avec les rationales.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: theme_id
          in: query
          schema:
            type: string
          description: Filtrer par thème
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des items à réviser
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudentReview'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/student/{id}/review/session:
    post:
      tags: [Student]
      summary: 'E5-REVIEW: Create review session'
      description: |
        Crée une session de révision pour un élève sur un thème spécifique.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [theme_id, items]
              properties:
                theme_id:
                  type: string
                items:
                  type: array
                  items:
                    type: object
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '201':
          description: Session de révision créée
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                  status:
                    type: string
                  items_count:
                    type: integer
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/student/{id}/badges:
    get:
      tags: [Student]
      summary: 'E5-BADGES: Get student badges'
      description: |
        Récupère les badges gagnés et disponibles pour un élève.
        Inclut la progression vers chaque badge disponible.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Badges de l'élève
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudentBadges'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # ============================================================
  # Sprint 7: Adaptive Learning - Personnalisation
  # ============================================================

  /api/reco:
    get:
      tags: [Adaptive]
      summary: 'E7-RECO: Get AI-powered recommendations'
      description: |
        Génère 3 recommandations personnalisées pour un élève basées sur:
        - Historique de performances
        - Zone Proximale de Développement (ZPD)
        - Patterns d'apprentissage
        - Courbe de l'oubli

        Inclut l'explicabilité (pourquoi cette recommandation).
      parameters:
        - name: studentId
          in: query
          required: true
          schema:
            type: string
          description: ID de l'élève
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Recommandations personnalisées
          content:
            application/json:
              schema:
                type: object
                properties:
                  student_id:
                    type: string
                  recommendations:
                    type: array
                    items:
                      type: object
                      properties:
                        theme_id:
                          type: string
                        theme_title:
                          type: string
                        theme_description:
                          type: string
                        theme_difficulty:
                          type: string
                        recommendation_score:
                          type: number
                        reasons:
                          type: array
                          items:
                            type: object
                            properties:
                              type:
                                type: string
                              label:
                                type: string
                              description:
                                type: string
                        explainability:
                          type: string
                  profile_summary:
                    type: object
                  generated_at:
                    type: string
                    format: date-time
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/reco/feedback:
    post:
      tags: [Adaptive]
      summary: 'E7-RECO: Record recommendation feedback'
      description: |
        Enregistre le feedback de l'élève sur une recommandation.
        Permet d'améliorer le système de recommandation.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [studentId, themeId, feedback]
              properties:
                studentId:
                  type: string
                themeId:
                  type: string
                feedback:
                  type: string
                  enum: [relevant, not_relevant, completed, too_hard, too_easy]
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Feedback enregistré
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/adaptive/difficulty:
    get:
      tags: [Adaptive]
      summary: 'E7-DIFF: Get adaptive difficulty level'
      description: |
        Calcule le niveau de difficulté adaptatif recommandé pour un élève.
        Niveaux: easy, normal, expert.
        Basé sur les performances et la ZPD.
      parameters:
        - name: studentId
          in: query
          required: true
          schema:
            type: string
        - name: themeId
          in: query
          schema:
            type: string
          description: Filtrer par thème spécifique
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Niveau de difficulté recommandé
          content:
            application/json:
              schema:
                type: object
                properties:
                  student_id:
                    type: string
                  current_level:
                    type: string
                    enum: [easy, normal, expert]
                  level_info:
                    type: object
                  recommendation:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/focus/create:
    post:
      tags: [Adaptive]
      summary: 'E7-FOCUS: Create focus session'
      description: |
        Crée une mini-session Focus ciblée (5-10 minutes).
        Types: quick_review, error_focus, mastery_boost, daily_challenge.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [studentId, focusMode]
              properties:
                studentId:
                  type: string
                focusMode:
                  type: string
                  enum: [quick_review, error_focus, mastery_boost, daily_challenge]
                themeId:
                  type: string
                  description: Optionnel pour mastery_boost
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '201':
          description: Session Focus créée
          content:
            application/json:
              schema:
                type: object
                properties:
                  session_id:
                    type: string
                  mode:
                    type: object
                  questions:
                    type: array
                  timeLimit:
                    type: integer
                  config:
                    type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/teacher/validations:
    get:
      tags: [Adaptive]
      summary: 'E7-HIL: Get pending validations'
      description: |
        Liste les items en attente de validation enseignant.
        Human-in-the-loop pour recommandations IA, ajustements de difficulté, etc.
      parameters:
        - name: type
          in: query
          schema:
            type: string
            enum: [recommendation, difficulty_adjustment, focus_session, ai_content]
        - name: my_items_only
          in: query
          schema:
            type: boolean
          description: Filtrer seulement mes items
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des validations
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags: [Adaptive]
      summary: 'E7-HIL: Submit item for validation'
      description: |
        Soumet un item pour validation enseignant.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [type, data]
              properties:
                type:
                  type: string
                  enum: [recommendation, difficulty_adjustment, focus_session, ai_content]
                data:
                  type: object
                metadata:
                  type: object
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '201':
          description: Item soumis
          content:
            application/json:
              schema:
                type: object
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/teacher/validations/{id}/approve:
    post:
      tags: [Adaptive]
      summary: 'E7-HIL: Approve validation'
      description: |
        Approuve un item en attente de validation.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                modifications:
                  type: object
                  description: Modifications optionnelles
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Item approuvé
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/teacher/validations/{id}/reject:
    post:
      tags: [Adaptive]
      summary: 'E7-HIL: Reject validation'
      description: |
        Rejette un item en attente de validation.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Item rejeté
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # ============================================================
  # Sprint 8: Social & Collaborative Learning
  # ============================================================

  /api/social/leaderboard:
    get:
      tags: [Social]
      summary: 'E8-LB: Get leaderboard rankings'
      description: |
        Récupère les classements par thème avec filtres.
        Supports hebdo, mensuel et all-time.
        Anonymisation optionnelle.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: theme_id
          in: query
          schema:
            type: string
          description: Filtrer par thème spécifique
        - name: class_id
          in: query
          schema:
            type: string
          description: Filtrer par classe spécifique
        - name: period
          in: query
          schema:
            type: string
            enum: [weekly, monthly, all_time]
            default: all_time
          description: Période du classement
        - name: anonymize
          in: query
          schema:
            type: boolean
            default: false
          description: Anonymiser les élèves
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
            maximum: 100
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Classement récupéré
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  period:
                    type: string
                  theme_id:
                    type: string
                    nullable: true
                  class_id:
                    type: string
                    nullable: true
                  anonymized:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        rank:
                          type: integer
                        student_id:
                          type: string
                        firstname:
                          type: string
                        lastname:
                          type: string
                        total_score:
                          type: number
                        total_sessions:
                          type: integer
                        avg_mastery:
                          type: number
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/content/share:
    post:
      tags: [Social]
      summary: 'E8-SHARE: Share student-created content'
      description: |
        Partage du contenu créé par un élève.
        Passe en modération automatiquement.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [student_id, content_type, title, content]
              properties:
                student_id:
                  type: string
                theme_id:
                  type: string
                content_type:
                  type: string
                  enum: [flashcard, note, summary, mnemo, quiz]
                title:
                  type: string
                content:
                  type: object
                description:
                  type: string
                is_public:
                  type: boolean
                target_class_id:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Contenu partagé
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  id:
                    type: string
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/content/shared:
    get:
      tags: [Social]
      summary: 'E8-SHARE: Get shared content'
      description: |
        Récupère les contenus partagés approuvés.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
        - name: theme_id
          in: query
          schema:
            type: string
        - name: content_type
          in: query
          schema:
            type: string
            enum: [flashcard, note, summary, mnemo, quiz]
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des contenus partagés
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/comments:
    post:
      tags: [Social]
      summary: 'E8-PEER: Post peer comment'
      description: |
        Poster un commentaire sur du contenu partagé.
        Supporte les threads (réponses).
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [student_id, comment_text]
              properties:
                student_id:
                  type: string
                shared_content_id:
                  type: string
                parent_comment_id:
                  type: string
                  description: Pour les réponses
                comment_text:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Commentaire publié
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  id:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/content/{id}/comments:
    get:
      tags: [Social]
      summary: 'E8-PEER: Get comments for content'
      description: |
        Récupère tous les commentaires pour un contenu partagé.
        Inclut les threads.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Liste des commentaires
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
                  threads:
                    type: object
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/sessions/collaborative:
    post:
      tags: [Social]
      summary: 'E8-COLLAB: Create collaborative session'
      description: |
        Créer une session de révision collective synchronisée.
        Génère un code unique pour rejoindre.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [creator_student_id, theme_id, title]
              properties:
                creator_student_id:
                  type: string
                theme_id:
                  type: string
                title:
                  type: string
                description:
                  type: string
                max_participants:
                  type: integer
                  default: 10
                session_type:
                  type: string
                  enum: [quiz_battle, flashcard_review, study_group]
                  default: study_group
                duration_minutes:
                  type: integer
                  default: 30
                questions:
                  type: array
                  items:
                    type: object
                settings:
                  type: object
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Session créée
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  session_id:
                    type: string
                  session_code:
                    type: string
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/sessions/collaborative/join:
    post:
      tags: [Social]
      summary: 'E8-COLLAB: Join collaborative session'
      description: |
        Rejoindre une session avec le code.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [session_code, student_id]
              properties:
                session_code:
                  type: string
                student_id:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Session rejointe
        '404':
          description: Session non trouvée
        '409':
          description: Session complète
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/sessions/collaborative/{id}:
    get:
      tags: [Social]
      summary: 'E8-COLLAB: Get session details'
      description: |
        Récupère les détails d'une session et la liste des participants.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Détails de la session
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/social/moderation/queue:
    get:
      tags: [Social]
      summary: 'E8-MOD: Get moderation queue'
      description: |
        File d'attente de modération (enseignants/admins).
        IA + validation humaine.
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, in_review, approved, rejected]
            default: pending
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: File de modération
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: array
                    items:
                      type: object
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/social/moderation/queue/{id}/approve:
    post:
      tags: [Social]
      summary: 'E8-MOD: Approve moderation item'
      description: |
        Approuver un contenu en attente de modération.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                notes:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Contenu approuvé
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/social/moderation/queue/{id}/reject:
    post:
      tags: [Social]
      summary: 'E8-MOD: Reject moderation item'
      description: |
        Rejeter un contenu en attente de modération.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                notes:
                  type: string
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: Contenu rejeté
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /realtime/collaborative/polling:
    get:
      tags: [Social]
      summary: 'E8-COLLAB: Real-time polling endpoint'
      description: |
        Polling endpoint pour sessions collaboratives.
        Fallback 15-30s si WebSocket indisponible.
        Long-polling supporté.
      parameters:
        - name: session_id
          in: query
          required: true
          schema:
            type: string
        - name: student_id
          in: query
          required: true
          schema:
            type: string
        - name: last_poll
          in: query
          schema:
            type: integer
          description: Timestamp du dernier poll
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      responses:
        '200':
          description: État de la session
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  timestamp:
                    type: integer
                  session:
                    type: object
                  participants:
                    type: array
                    items:
                      type: object
                  updates:
                    type: array
                    items:
                      type: object
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ============================================================
  # Sprint 9: Academic Data Hub - API Académique
  # ============================================================

  /api/academic/students:
    get:
      tags: [Academic]
      summary: 'E9-API: Export students data'
      description: |
        Read-only endpoint pour exporter les données étudiants vers ENT/LMS.

        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
        **Tenant isolation**: Accès strictement limité au tenant de la clé API.
        **Observabilité**: Tous les appels sont journalisés dans sync_logs.
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
          description: Clé API partenaire
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
          description: Filtrer par classe
        - name: promo_id
          in: query
          schema:
            type: string
          description: Filtrer par promotion
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Liste des étudiants
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
            X-RateLimit-Remaining:
              schema:
                type: integer
            X-RateLimit-Reset:
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicStudentsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/classes:
    get:
      tags: [Academic]
      summary: 'E9-API: Export classes data'
      description: |
        Read-only endpoint pour exporter les données classes vers ENT/LMS.

        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: promo_id
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum: [active, archived]
            default: active
      responses:
        '200':
          description: Liste des classes
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
            X-RateLimit-Remaining:
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicClassesResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/promotions:
    get:
      tags: [Academic]
      summary: 'E9-API: Export promotions data'
      description: |
        Read-only endpoint pour exporter les données promotions vers ENT/LMS.

        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: status
          in: query
          schema:
            type: string
            enum: [active, archived]
            default: active
      responses:
        '200':
          description: Liste des promotions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicPromotionsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/themes:
    get:
      tags: [Academic]
      summary: 'E9-API: Export themes data'
      description: |
        Read-only endpoint pour exporter les thèmes pédagogiques vers ENT/LMS.

        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, active, archived]
            default: active
        - name: difficulty
          in: query
          schema:
            type: string
            enum: [beginner, intermediate, advanced]
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Liste des thèmes
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicThemesResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/assignments:
    get:
      tags: [Academic]
      summary: 'E9-API: Export assignments data (read-only)'
      description: |
        Read-only endpoint pour exporter les affectations vers ENT/LMS.

        **Read-only**: Cet endpoint ne permet que la consultation, pas la création/modification.
        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
        - name: teacher_id
          in: query
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
            enum: [draft, queued, pushed, ack, error]
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            maximum: 500
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Liste des affectations
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicAssignmentsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/stats:
    get:
      tags: [Academic]
      summary: 'E9-API: Export aggregated statistics'
      description: |
        Read-only endpoint pour exporter les statistiques agrégées vers ENT/LMS.

        **Rate Limiting**: Requiert une clé API valide avec quotas.
        **Scope requis**: `academic:read`
        **Agrégation**: Calcule automatiquement avg_score, avg_mastery, total_time.
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: class_id
          in: query
          schema:
            type: string
        - name: student_id
          in: query
          schema:
            type: string
        - name: theme_id
          in: query
          schema:
            type: string
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: Date de début (défaut -30 jours)
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: Date de fin (défaut aujourd'hui)
      responses:
        '200':
          description: Statistiques agrégées
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicStatsResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /api/academic/export:
    get:
      tags: [Academic]
      summary: 'E9-API: Full data export for ENT/LMS'
      description: |
        Export complet de toutes les données académiques en une seule requête.

        **Rate Limiting**: Requiert une clé API valide avec quotas élevés.
        **Scope requis**: `academic:export` (scope spécial avec permissions étendues)
        **Format**: JSON (CSV à venir)
        **Inclusions**: Sélectionner les ressources à inclure via le paramètre `include`.
      parameters:
        - name: X-API-Key
          in: header
          required: true
          schema:
            type: string
        - $ref: '#/components/parameters/TenantHeader'
        - name: format
          in: query
          schema:
            type: string
            enum: [json, csv]
            default: json
          description: Format d'export
        - name: include
          in: query
          schema:
            type: string
          description: Ressources à inclure (CSV), ex "students,classes,themes,stats"
          example: "students,classes,themes,stats"
      responses:
        '200':
          description: Export complet
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AcademicExportResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '501':
          description: Format non encore implémenté

  # ========================================
  # Sprint 13: Stability, Automation & UX
  # ========================================

  /api/user/profile:
    get:
      tags: [User]
      summary: Récupérer le profil utilisateur
      description: Retourne les informations complètes du profil utilisateur incluant les préférences et le statut onboarding
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      responses:
        '200':
          description: Profil utilisateur récupéré avec succès
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  user:
                    $ref: '#/components/schemas/UserProfile'
        '401':
          $ref: '#/components/responses/Unauthorized'

    put:
      tags: [User]
      summary: Mettre à jour le profil utilisateur
      description: Met à jour les informations modifiables du profil (nom complet, préférences)
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                full_name:
                  type: string
                  example: "Claire Dubois"
                preferences:
                  type: object
                  properties:
                    theme:
                      type: string
                      enum: [light, dark]
                    notifications_enabled:
                      type: boolean
                    language:
                      type: string
                      example: "fr"
      responses:
        '200':
          description: Profil mis à jour avec succès
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/user/onboarding-complete:
    post:
      tags: [User]
      summary: Marquer l'onboarding comme terminé
      description: Indique que l'utilisateur a terminé le processus d'onboarding
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      responses:
        '200':
          description: Onboarding marqué comme complété
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /api/quality/analyze:
    post:
      tags: [Quality]
      summary: Analyser la qualité d'un thème (IA Confidence)
      description: |
        Évalue la fiabilité du contenu généré par IA et retourne un score de confiance par question.
        Inclut détection des zones à risque et recommandations de validation.
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - theme_id
              properties:
                theme_id:
                  type: integer
                  example: 42
      responses:
        '200':
          description: Analyse de qualité complétée
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  report:
                    $ref: '#/components/schemas/QualityConfidenceReport'
                  badge:
                    $ref: '#/components/schemas/QualityBadge'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/quality/lint:
    post:
      tags: [Quality]
      summary: Vérifier le contenu d'un thème (Linting)
      description: |
        Détecte les incohérences, erreurs factuelles, et problèmes structurels dans un thème.
        Retourne erreurs critiques, avertissements et recommandations.
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - theme_id
              properties:
                theme_id:
                  type: integer
                  example: 42
      responses:
        '200':
          description: Linting complété
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  report:
                    $ref: '#/components/schemas/LintingReport'
                  summary:
                    $ref: '#/components/schemas/LintingSummary'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/system/diagnostic:
    get:
      tags: [System]
      summary: Diagnostic système complet
      description: |
        Exécute une série de vérifications système :
        - État base de données et latence
        - Service IA (configuration et disponibilité)
        - Espace disque et permissions filesystem
        - Limites API et utilisation
        - État des sauvegardes
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      responses:
        '200':
          description: Diagnostic complété
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SystemDiagnostic'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Accès réservé aux admins et direction
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/system/backups:
    get:
      tags: [System]
      summary: Lister les sauvegardes disponibles
      description: Retourne la liste des sauvegardes avec taille, date, et âge
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      responses:
        '200':
          description: Liste des sauvegardes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  backups:
                    type: array
                    items:
                      $ref: '#/components/schemas/BackupInfo'
                  count:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  /api/system/backup:
    post:
      tags: [System]
      summary: Créer une sauvegarde manuelle
      description: |
        Déclenche une sauvegarde complète du système incluant :
        - Base de données (toutes tables)
        - Catalogue de thèmes
        - Configurations (.env, config/)
        - Génère un fichier ZIP téléchargeable
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                force:
                  type: boolean
                  description: Forcer même si sauvegarde récente existe
                  default: false
      responses:
        '200':
          description: Sauvegarde créée avec succès
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  backup_name:
                    type: string
                  backup_path:
                    type: string
                  size:
                    type: integer
                  size_human:
                    type: string
                  timestamp:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          description: Échec de la sauvegarde
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: string

  /api/system/backup/{backup_name}/download:
    get:
      tags: [System]
      summary: Télécharger une sauvegarde
      description: Télécharge un fichier ZIP de sauvegarde
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: backup_name
          in: path
          required: true
          schema:
            type: string
          example: "studymate_backup_2025-11-13_02-00-00.zip"
      responses:
        '200':
          description: Fichier ZIP de sauvegarde
          content:
            application/zip:
              schema:
                type: string
                format: binary
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/export/formats:
    get:
      tags: [Export]
      summary: Lister les formats d'export disponibles
      description: Retourne les formats supportés et les plateformes LMS compatibles
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
      responses:
        '200':
          description: Liste des formats d'export
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  formats:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        description:
                          type: string
                        file_extension:
                          type: string
                        mime_type:
                          type: string
                  lms_platforms:
                    type: object
                    additionalProperties:
                      type: string
              example:
                success: true
                formats:
                  - id: qti
                    name: "QTI 2.2"
                    description: "Format standard pour LMS"
                    file_extension: "zip"
                    mime_type: "application/zip"
                  - id: json
                    name: "JSON"
                    description: "Format natif StudyMate"
                    file_extension: "json"
                    mime_type: "application/json"
                lms_platforms:
                  generic: "QTI 2.2 Standard"
                  moodle: "Moodle"
                  canvas: "Canvas LMS"
                  blackboard: "Blackboard Learn"

  /api/export/qti/{theme_id}:
    get:
      tags: [Export]
      summary: Exporter un thème au format QTI 2.2
      description: |
        Génère un package QTI 2.2 compatible avec :
        - Moodle
        - Canvas
        - Blackboard
        - Autres LMS conformes IMS QTI

        Le package inclut :
        - assessment.xml (questions en QTI)
        - imsmanifest.xml (métadonnées)
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: theme_id
          in: path
          required: true
          schema:
            type: integer
          example: 42
        - name: explanations
          in: query
          schema:
            type: boolean
            default: true
          description: Inclure les explications des réponses
        - name: shuffle
          in: query
          schema:
            type: boolean
            default: true
          description: Mélanger l'ordre des réponses
        - name: lms
          in: query
          schema:
            type: string
            enum: [generic, moodle, canvas, blackboard]
            default: generic
          description: Optimiser pour une plateforme LMS spécifique
      responses:
        '200':
          description: Package QTI 2.2 (ZIP)
          content:
            application/zip:
              schema:
                type: string
                format: binary
          headers:
            Content-Disposition:
              schema:
                type: string
              description: "attachment; filename=theme_title_qti.zip"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Accès refusé (uniquement vos propres thèmes)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /api/export/json/{theme_id}:
    get:
      tags: [Export]
      summary: Exporter un thème au format JSON
      description: Export du thème dans le format natif StudyMate pour archivage ou transfert
      security:
        - bearerAuth: []
        - urlEncodedAuth: []
      parameters:
        - $ref: '#/components/parameters/TenantHeader'
        - name: theme_id
          in: path
          required: true
          schema:
            type: integer
          example: 42
      responses:
        '200':
          description: Thème au format JSON
          content:
            application/json:
              schema:
                type: object
                properties:
                  version:
                    type: string
                    example: "SPRINT_13"
                  exported_at:
                    type: string
                    format: date-time
                  theme:
                    type: object
                    properties:
                      id:
                        type: integer
                      title:
                        type: string
                      description:
                        type: string
                      difficulty:
                        type: string
                      status:
                        type: string
                      created_at:
                        type: string
                      content:
                        type: object
          headers:
            Content-Disposition:
              schema:
                type: string
              description: "attachment; filename=theme_title.json"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

components:
  securitySchemes:
    urlEncodedAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        Auth via form-urlencoded (prioritaire pour hébergement mutualisé).
        Champs requis dans le body: api_key, tenant_id, scope

        **Scopes disponibles**: admin, direction, teacher, inspector, intervenant

        Exemple:
        ```
        api_key=secret_teacher_key
        &tenant_id=TENANT_INST_PARIS
        &scope=teacher
        ```

        **Isolation tenant**: Le tenant_id dans le body doit correspondre au tenant de l'utilisateur.
        Tout accès inter-tenant sera bloqué avec HTTP 403.

    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Auth JWT (optionnel, mode MIXED).
        Token contient: sub, tenant_id, scope (role), exp

        **Header requis**: X-Orchestrator-Id avec le tenant_id

        **Validation RBAC**: Le scope/role dans le JWT détermine les permissions.
        Les rôles sont: admin, direction, teacher, inspector, intervenant.

        Exemple JWT payload:
        ```json
        {
          "sub": "USER_CLAIRE_DUBOIS",
          "tenant_id": "TENANT_INST_PARIS",
          "scope": "teacher",
          "exp": 1699999999
        }
        ```

        **Isolation tenant**: Le X-Orchestrator-Id header doit correspondre au tenant_id du JWT.
        Sinon, la requête sera rejetée avec HTTP 403.

  parameters:
    TenantHeader:
      name: X-Orchestrator-Id
      in: header
      required: true
      schema:
        type: string
      description: ID du tenant (école)
      example: TENANT_INST_PARIS

  responses:
    Unauthorized:
      description: JWT invalide, api_key manquante ou scope insuffisant
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    
    Forbidden:
      description: |
        Accès refusé - peut être causé par:
        - Tenant mismatch (accès inter-tenant)
        - Permissions insuffisantes (RBAC)
        - Tentative d'accès à ressource d'un autre utilisateur
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Error'
              - type: object
                properties:
                  required_permission:
                    type: string
                    example: "assignments:update"
                  your_role:
                    type: string
                    example: "teacher"
          examples:
            tenant_mismatch:
              value:
                code: TENANT_MISMATCH
                message: "Your authentication tenant does not match the requested tenant"
                timestamp: "2025-11-12T10:00:00Z"
            insufficient_permissions:
              value:
                code: FORBIDDEN
                message: "You do not have permission to update assignments"
                required_permission: "assignments:update"
                your_role: "inspector"
                timestamp: "2025-11-12T10:00:00Z"
            ownership_violation:
              value:
                code: FORBIDDEN
                message: "You can only access your own assignments"
                your_role: "teacher"
                timestamp: "2025-11-12T10:00:00Z"
    
    NotFound:
      description: Ressource introuvable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    
    BadRequest:
      description: Erreur de validation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    
    Conflict:
      description: Conflit (idempotence, doublon, etc.)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    
    TooManyRequests:
      description: Rate limit atteinte - quota dépassé
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Limite de requêtes (par minute)
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Requêtes restantes dans la fenêtre actuelle
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Timestamp Unix de réinitialisation du compteur
        X-RateLimit-Limit-Hour:
          schema:
            type: integer
          description: Limite horaire
        X-RateLimit-Remaining-Hour:
          schema:
            type: integer
          description: Requêtes restantes cette heure
        X-RateLimit-Limit-Day:
          schema:
            type: integer
          description: Limite quotidienne
        X-RateLimit-Remaining-Day:
          schema:
            type: integer
          description: Requêtes restantes aujourd'hui
        Retry-After:
          schema:
            type: integer
          description: Nombre de secondes avant de réessayer
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/Error'
              - type: object
                properties:
                  retry_after:
                    type: integer
                    description: Secondes avant de réessayer
                  reset_at:
                    type: string
                    format: date-time
                    description: Date/heure de réinitialisation
                  limits:
                    type: object
                    properties:
                      minute:
                        type: integer
                      hour:
                        type: integer
                      day:
                        type: integer
                  remaining:
                    type: object
                    properties:
                      minute:
                        type: integer
                      hour:
                        type: integer
                      day:
                        type: integer
          examples:
            rate_limit_exceeded:
              value:
                code: RATE_LIMIT_EXCEEDED
                message: "Rate limit exceeded. Please retry after the reset time."
                retry_after: 45
                reset_at: "2025-11-12T10:15:00Z"
                limits:
                  minute: 60
                  hour: 1000
                  day: 10000
                remaining:
                  minute: 0
                  hour: 234
                  day: 5678

  schemas:
    Error:
      type: object
      properties:
        code:
          type: string
          example: UNAUTHORIZED
        message:
          type: string
          example: "Invalid API key"
        timestamp:
          type: string
          format: date-time

    HealthResponse:
      type: object
      properties:
        status:
          type: string
          enum: [ok, degraded, error]
        version:
          type: string
        timestamp:
          type: string
          format: date-time
        database:
          type: object
          properties:
            status:
              type: string
            latency_ms:
              type: integer

    LoginRequest:
      type: object
      required: [email, password]
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          format: password

    LoginResponse:
      type: object
      properties:
        token:
          type: string
        user:
          $ref: '#/components/schemas/User'
        expiresAt:
          type: string
          format: date-time

    User:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        email:
          type: string
        firstname:
          type: string
        lastname:
          type: string
        role:
          type: string
          enum: [admin, direction, teacher, intervenant]

    Student:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        classId:
          type: string
        promoId:
          type: string
        uuid_scolaire:
          type: string
        email_scolaire:
          type: string
          format: email
        firstname:
          type: string
        lastname:
          type: string
        consent_sharing:
          type: boolean
        status:
          type: string
          enum: [active, graduated, withdrawn]

    Class:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        promoId:
          type: string
        name:
          type: string
        description:
          type: string
        teacherId:
          type: string
        status:
          type: string
          enum: [active, archived]
        studentCount:
          type: integer

    Theme:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        title:
          type: string
        description:
          type: string
        tags:
          type: array
          items:
            type: string
        difficulty:
          type: string
          enum: [beginner, intermediate, advanced]
        source:
          type: string
          enum: [manual, pdf_mistral, import]
        status:
          type: string
          enum: [draft, active, archived]

    ThemeCreate:
      type: object
      required: [title, content]
      properties:
        title:
          type: string
        description:
          type: string
        content:
          type: object
          description: Contenu JSON du thème
        tags:
          type: array
          items:
            type: string
        difficulty:
          type: string

    AssignmentCreate:
      type: object
      required: [type, themeId, title, targets]
      properties:
        type:
          type: string
          enum: [quiz, flashcards, fiche, annales]
        themeId:
          type: string
        title:
          type: string
        mode:
          type: string
          enum: [post-cours, pre-examen, revision-generale]
        dueAt:
          type: string
          format: date-time
        instructions:
          type: string
        targets:
          type: string
          description: "Cible: classId, promoId ou liste studentIds (CSV)"

    Assignment:
      allOf:
        - $ref: '#/components/schemas/AssignmentCreate'
        - type: object
          properties:
            id:
              type: string
            tenantId:
              type: string
            teacherId:
              type: string
            status:
              type: string
              enum: [draft, queued, pushed, ack, error]
            createdAt:
              type: string
              format: date-time

    PullStatsRequest:
      type: object
      properties:
        classId:
          type: string
        promoId:
          type: string
        themeId:
          type: string
        since:
          type: string
          format: date-time
          description: Date de début pour le pull

    Stats:
      type: object
      properties:
        id:
          type: string
        studentId:
          type: string
        themeId:
          type: string
        attempts:
          type: integer
        score:
          type: number
          format: float
        mastery:
          type: number
          format: float
        timeSpent:
          type: integer
          description: Temps en secondes
        lastActivityAt:
          type: string
          format: date-time

    SyncLog:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        direction:
          type: string
          enum: [pull, push]
        type:
          type: string
          enum: [stats, assignment, webhook]
        status:
          type: string
          enum: [queued, running, ok, error]
        startedAt:
          type: string
          format: date-time
        endedAt:
          type: string
          format: date-time

    DashboardSummary:
      type: object
      properties:
        kpis:
          type: object
          properties:
            totalStudents:
              type: integer
            activeStudents:
              type: integer
            avgScore:
              type: number
            avgMastery:
              type: number
        recentActivity:
          type: array
          items:
            type: object

    MistralJob:
      type: object
      properties:
        id:
          type: string
        tenantId:
          type: string
        userId:
          type: string
        jobType:
          type: string
          enum: [quiz, flashcards, fiche, full_theme]
        status:
          type: string
          enum: [pending, processing, completed, error]
        resultThemeId:
          type: string
        createdAt:
          type: string
          format: date-time

    SessionEnded:
      type: object
      required: [uuid, email, themeId, endedAt]
      properties:
        uuid:
          type: string
          description: UUID scolaire de l'élève
        email:
          type: string
          format: email
          description: Email scolaire de l'élève
        themeId:
          type: string
        score:
          type: number
        timeSpent:
          type: integer
        endedAt:
          type: string
          format: date-time
        attemptId:
          type: string

    AssignmentAck:
      type: object
      required: [assignmentId, ackAt]
      properties:
        assignmentId:
          type: string
        ackAt:
          type: string
          format: date-time
        status:
          type: string
          enum: [received, started, completed, error]

    ErgoError:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string
        correlationId:
          type: string
        context:
          type: object
          additionalProperties: true

    Pagination:
      type: object
      properties:
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer

    # Sprint 4: Partners & Telemetry schemas
    PartnersUsage:
      type: object
      description: Statistiques d'usage des clés API partenaires
      properties:
        tenant_id:
          type: string
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
        summary:
          type: object
          properties:
            total_api_keys:
              type: integer
            active_api_keys:
              type: integer
            total_requests:
              type: integer
            successful_requests:
              type: integer
            failed_requests:
              type: integer
            success_rate:
              type: number
              format: float
            avg_duration_ms:
              type: number
              format: float
        api_keys:
          type: array
          items:
            $ref: '#/components/schemas/ApiKeyUsage'

    ApiKeyUsage:
      type: object
      description: Usage détaillé d'une clé API
      properties:
        id:
          type: string
        owner:
          type: string
        scopes:
          type: array
          items:
            type: string
        status:
          type: string
          enum: [active, suspended, revoked]
        quotas:
          type: object
          properties:
            daily:
              type: integer
            per_hour:
              type: integer
            per_minute:
              type: integer
        rate_limit_status:
          type: object
          properties:
            limits:
              type: object
              additionalProperties:
                type: integer
            current:
              type: object
              additionalProperties:
                type: integer
            remaining:
              type: object
              additionalProperties:
                type: integer
            reset_at:
              type: object
              additionalProperties:
                type: integer
        usage:
          type: object
          properties:
            total_requests:
              type: integer
            successful_requests:
              type: integer
            failed_requests:
              type: integer
            success_rate:
              type: number
            avg_duration_ms:
              type: number
            max_duration_ms:
              type: number
            first_request:
              type: string
              format: date-time
            last_request:
              type: string
              format: date-time
        daily_usage:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              requests:
                type: integer
              successful:
                type: integer
              failed:
                type: integer
              avg_duration_ms:
                type: number
        top_endpoints:
          type: array
          items:
            type: object
            properties:
              endpoint:
                type: string
              requests:
                type: integer
              avg_duration_ms:
                type: number
              errors:
                type: integer
        recent_errors:
          type: array
          items:
            type: object
            properties:
              request_id:
                type: string
              method:
                type: string
              endpoint:
                type: string
              status_code:
                type: integer
              error_message:
                type: string
              error_code:
                type: string
              created_at:
                type: string
                format: date-time
        created_at:
          type: string
          format: date-time
        last_used_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time

    TelemetryStats:
      type: object
      description: Statistiques de télémétrie API
      properties:
        tenant_id:
          type: string
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
        view:
          type: string
          enum: [overview, endpoints, errors, performance]
        overview:
          type: object
          description: Vue d'ensemble (view=overview)
          properties:
            total_requests:
              type: integer
            active_days:
              type: integer
            successful_requests:
              type: integer
            client_errors:
              type: integer
            server_errors:
              type: integer
            avg_duration_ms:
              type: number
            max_duration_ms:
              type: number
            avg_db_queries:
              type: number
            avg_db_time_ms:
              type: number
        daily_stats:
          type: array
          description: Statistiques quotidiennes
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              requests:
                type: integer
              successful:
                type: integer
              errors:
                type: integer
              avg_duration_ms:
                type: number
              max_duration_ms:
                type: number
        hourly_stats:
          type: array
          description: Distribution horaire (24h)
          items:
            type: object
            properties:
              hour:
                type: integer
              requests:
                type: integer
              avg_duration_ms:
                type: number
        endpoints:
          type: array
          description: Statistiques par endpoint (view=endpoints)
          items:
            type: object
            properties:
              endpoint:
                type: string
              total_requests:
                type: integer
              successful_requests:
                type: integer
              failed_requests:
                type: integer
              avg_duration_ms:
                type: number
              max_duration_ms:
                type: number
              avg_db_queries:
                type: number
              avg_db_time_ms:
                type: number
              error_rate_pct:
                type: number
        error_groups:
          type: array
          description: Groupes d'erreurs (view=errors)
          items:
            type: object
            properties:
              status_code:
                type: integer
              error_code:
                type: string
              endpoint:
                type: string
              occurrences:
                type: integer
              error_message:
                type: string
        recent_errors:
          type: array
          description: Erreurs récentes (view=errors)
          items:
            type: object
            properties:
              request_id:
                type: string
              method:
                type: string
              endpoint:
                type: string
              status_code:
                type: integer
              error_code:
                type: string
              error_message:
                type: string
              duration_ms:
                type: number
              ip_address:
                type: string
              created_at:
                type: string
                format: date-time
        slow_queries:
          type: array
          description: Requêtes lentes (view=performance)
          items:
            type: object
            properties:
              request_id:
                type: string
              method:
                type: string
              endpoint:
                type: string
              status_code:
                type: integer
              duration_ms:
                type: number
              db_queries:
                type: integer
              db_time_ms:
                type: number
              created_at:
                type: string
                format: date-time
        endpoint_performance:
          type: array
          description: Performance par endpoint (view=performance)
          items:
            type: object
            properties:
              endpoint:
                type: string
              total_requests:
                type: integer
              avg_duration_ms:
                type: number
              max_duration_ms:
                type: number
              avg_db_queries:
                type: number
              avg_db_time_ms:
                type: number

    # ============================================================
    # Sprint 5: Student schemas
    # ============================================================

    StudentMissions:
      type: object
      description: 'E5-MISSIONS: Liste des missions d''un élève'
      properties:
        student:
          type: object
          properties:
            id:
              type: string
            firstname:
              type: string
            lastname:
              type: string
            uuid_scolaire:
              type: string
        missions:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              title:
                type: string
              type:
                type: string
                enum: [quiz, flashcards, fiche, annales]
              mode:
                type: string
              due_at:
                type: string
                format: date-time
              instructions:
                type: string
              theme_id:
                type: string
              theme_title:
                type: string
              theme_difficulty:
                type: string
              teacher_name:
                type: string
              local_status:
                type: string
                enum: [a_faire, en_cours, terminee]
              progress_percent:
                type: number
              is_overdue:
                type: boolean
              score:
                type: number
              time_spent:
                type: integer
        count:
          type: integer
        synced_at:
          type: string
          format: date-time

    StudentSyncPush:
      type: object
      description: 'E5-SYNC: Données de sync pour une session élève'
      required: [student_id, assignment_id, session_data]
      properties:
        student_id:
          type: string
        assignment_id:
          type: string
        session_data:
          type: object
          required: [score, time_spent, ended_at]
          properties:
            score:
              type: number
              description: Score en pourcentage (0-100)
            time_spent:
              type: integer
              description: Temps en secondes
            started_at:
              type: string
              format: date-time
            ended_at:
              type: string
              format: date-time
            errors:
              type: array
              description: Liste des erreurs commises
              items:
                type: object
            correct_answers:
              type: integer
            mastery:
              type: number
              description: Niveau de maîtrise (0-1)

    StudentProgress:
      type: object
      description: 'E5-PROGRESS: Dashboard de progression élève'
      properties:
        student:
          type: object
          properties:
            id:
              type: string
            firstname:
              type: string
            lastname:
              type: string
            email_scolaire:
              type: string
            class_name:
              type: string
        kpis:
          type: object
          properties:
            total_sessions:
              type: integer
            completed_assignments:
              type: integer
            avg_score:
              type: number
            total_time_spent:
              type: integer
            sessions_last_7_days:
              type: integer
            overall_mastery:
              type: number
        charts:
          type: object
          properties:
            score_trend:
              type: object
              properties:
                labels:
                  type: array
                  items:
                    type: string
                values:
                  type: array
                  items:
                    type: number
            time_by_theme:
              type: object
              properties:
                labels:
                  type: array
                  items:
                    type: string
                values:
                  type: array
                  items:
                    type: integer
            mastery_radar:
              type: object
              properties:
                labels:
                  type: array
                  items:
                    type: string
                values:
                  type: array
                  items:
                    type: number
        recent_activity:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              score:
                type: number
              time_spent:
                type: integer
              completed_at:
                type: string
                format: date-time
              assignment_title:
                type: string
              assignment_type:
                type: string
              theme_title:
                type: string
        analysis:
          type: object
          properties:
            strengths:
              type: array
              items:
                type: object
                properties:
                  theme_title:
                    type: string
                  mastery:
                    type: number
                  score:
                    type: number
                  attempts:
                    type: integer
            weaknesses:
              type: array
              items:
                type: object
                properties:
                  theme_title:
                    type: string
                  mastery:
                    type: number
                  score:
                    type: number
                  attempts:
                    type: integer
        generated_at:
          type: string
          format: date-time

    StudentReview:
      type: object
      description: 'E5-REVIEW: Items à réviser pour un élève'
      properties:
        student:
          type: object
          properties:
            id:
              type: string
            firstname:
              type: string
            lastname:
              type: string
        review_items:
          type: array
          items:
            type: object
            properties:
              session_id:
                type: string
              assignment_id:
                type: string
              assignment_title:
                type: string
              assignment_type:
                type: string
              theme_id:
                type: string
              theme_title:
                type: string
              error:
                type: object
              completed_at:
                type: string
                format: date-time
        count:
          type: integer
        errors_by_theme:
          type: array
          items:
            type: object
            properties:
              theme_id:
                type: string
              theme_title:
                type: string
              error_count:
                type: integer
        recommendations:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum: [low_mastery, frequent_errors]
              theme_id:
                type: string
              theme_title:
                type: string
              reason:
                type: string
              priority:
                type: string
                enum: [low, medium, high]
        generated_at:
          type: string
          format: date-time

    StudentBadges:
      type: object
      description: 'E5-BADGES: Badges d''un élève'
      properties:
        student:
          type: object
          properties:
            id:
              type: string
            firstname:
              type: string
            lastname:
              type: string
        earned_badges:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              badge_id:
                type: string
              badge_name:
                type: string
              badge_description:
                type: string
              badge_icon:
                type: string
              badge_category:
                type: string
              badge_tier:
                type: string
                enum: [bronze, silver, gold, platinum]
              earned_at:
                type: string
                format: date-time
              metadata:
                type: object
        available_badges:
          type: array
          items:
            type: object
            properties:
              badge_id:
                type: string
              badge_name:
                type: string
              badge_description:
                type: string
              badge_icon:
                type: string
              badge_category:
                type: string
              badge_tier:
                type: string
              criteria:
                type: object
              progress:
                type: object
                properties:
                  percent:
                    type: number
                  met_criteria:
                    type: integer
                  total_criteria:
                    type: integer
                  details:
                    type: array
                    items:
                      type: object
        recent_badges:
          type: array
          items:
            type: object
        statistics:
          type: object
          properties:
            total_earned:
              type: integer
            total_available:
              type: integer
            by_category:
              type: object
            by_tier:
              type: object
        generated_at:
          type: string
          format: date-time

    ServerError:
      type: object
      description: Erreur serveur
      properties:
        code:
          type: string
        message:
          type: string
        timestamp:
          type: string
          format: date-time

    # ============================================================
    # Sprint 9: Academic API Schemas
    # ============================================================

    AcademicStudentsResponse:
      type: object
      description: 'E9-API: Response for /api/academic/students'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              uuid_scolaire:
                type: string
              email_scolaire:
                type: string
                format: email
              firstname:
                type: string
              lastname:
                type: string
              class_id:
                type: string
              promo_id:
                type: string
              class_name:
                type: string
              promo_name:
                type: string
              consent_sharing:
                type: boolean
              status:
                type: string
                enum: [active, graduated, withdrawn]
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
        pagination:
          type: object
          properties:
            total:
              type: integer
            limit:
              type: integer
            offset:
              type: integer
            has_more:
              type: boolean
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            generated_at:
              type: string
              format: date-time

    AcademicClassesResponse:
      type: object
      description: 'E9-API: Response for /api/academic/classes'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              name:
                type: string
              description:
                type: string
              promo_id:
                type: string
              promo_name:
                type: string
              teacher_id:
                type: string
              teacher_firstname:
                type: string
              teacher_lastname:
                type: string
              student_count:
                type: integer
              status:
                type: string
                enum: [active, archived]
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            count:
              type: integer
            generated_at:
              type: string
              format: date-time

    AcademicPromotionsResponse:
      type: object
      description: 'E9-API: Response for /api/academic/promotions'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              name:
                type: string
              description:
                type: string
              year_start:
                type: integer
              year_end:
                type: integer
              class_count:
                type: integer
              student_count:
                type: integer
              status:
                type: string
                enum: [active, archived]
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            count:
              type: integer
            generated_at:
              type: string
              format: date-time

    AcademicThemesResponse:
      type: object
      description: 'E9-API: Response for /api/academic/themes'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              title:
                type: string
              description:
                type: string
              tags:
                type: array
                items:
                  type: string
              difficulty:
                type: string
                enum: [beginner, intermediate, advanced]
              source:
                type: string
                enum: [manual, pdf_mistral, import]
              status:
                type: string
                enum: [draft, active, archived]
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
        pagination:
          type: object
          properties:
            total:
              type: integer
            limit:
              type: integer
            offset:
              type: integer
            has_more:
              type: boolean
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            generated_at:
              type: string
              format: date-time

    AcademicAssignmentsResponse:
      type: object
      description: 'E9-API: Response for /api/academic/assignments'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              type:
                type: string
                enum: [quiz, flashcards, fiche, annales]
              title:
                type: string
              mode:
                type: string
                enum: [post-cours, pre-examen, revision-generale]
              theme_id:
                type: string
              theme_title:
                type: string
              theme_difficulty:
                type: string
              teacher_id:
                type: string
              teacher_firstname:
                type: string
              teacher_lastname:
                type: string
              status:
                type: string
                enum: [draft, queued, pushed, ack, error]
              due_at:
                type: string
                format: date-time
              instructions:
                type: string
              targets:
                type: string
              created_at:
                type: string
                format: date-time
              updated_at:
                type: string
                format: date-time
        pagination:
          type: object
          properties:
            total:
              type: integer
            limit:
              type: integer
            offset:
              type: integer
            has_more:
              type: boolean
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            generated_at:
              type: string
              format: date-time

    AcademicStatsResponse:
      type: object
      description: 'E9-API: Response for /api/academic/stats'
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              student_id:
                type: string
              firstname:
                type: string
              lastname:
                type: string
              email_scolaire:
                type: string
              theme_id:
                type: string
              theme_title:
                type: string
              theme_difficulty:
                type: string
              attempts:
                type: integer
              score:
                type: number
              mastery:
                type: number
              time_spent:
                type: integer
                description: Temps en secondes
              last_activity_at:
                type: string
                format: date-time
        aggregates:
          type: object
          properties:
            total_sessions:
              type: integer
            avg_score:
              type: number
            avg_mastery:
              type: number
            total_time_hours:
              type: number
        filters:
          type: object
          properties:
            class_id:
              type: string
              nullable: true
            student_id:
              type: string
              nullable: true
            theme_id:
              type: string
              nullable: true
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
        meta:
          type: object
          properties:
            tenant_id:
              type: string
            generated_at:
              type: string
              format: date-time

    AcademicExportResponse:
      type: object
      description: 'E9-API: Response for /api/academic/export'
      properties:
        tenant_id:
          type: string
        exported_at:
          type: string
          format: date-time
        format_version:
          type: string
        students:
          type: array
          items:
            type: object
        classes:
          type: array
          items:
            type: object
        themes:
          type: array
          items:
            type: object
        stats:
          type: array
          items:
            type: object

    # ========================================
    # Sprint 13: Schemas
    # ========================================

    UserProfile:
      type: object
      description: 'Sprint 13: User profile with onboarding status'
      properties:
        id:
          type: integer
        tenant_id:
          type: integer
        email:
          type: string
        full_name:
          type: string
        role:
          type: string
          enum: [admin, direction, teacher, intervenant, inspector]
        first_login:
          type: boolean
          description: True if user has never logged in before
        onboarding_completed:
          type: boolean
          description: True if user completed onboarding walkthrough
        preferences:
          type: object
          properties:
            theme:
              type: string
              enum: [light, dark]
            notifications_enabled:
              type: boolean
            language:
              type: string
        created_at:
          type: string
          format: date-time
        last_login_at:
          type: string
          format: date-time

    QualityConfidenceReport:
      type: object
      description: 'Sprint 13: AI confidence analysis report'
      properties:
        overall_confidence:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: Overall confidence score (0-1)
        questions:
          type: array
          items:
            type: object
            properties:
              question_id:
                type: integer
              confidence_score:
                type: number
                format: float
              risk_level:
                type: string
                enum: [low, medium, high]
              issues:
                type: array
                items:
                  type: string
              text_preview:
                type: string
        risk_areas:
          type: array
          items:
            type: object
            properties:
              question_index:
                type: integer
              reason:
                type: string
              severity:
                type: string
        recommendations:
          type: array
          items:
            type: object
            properties:
              priority:
                type: string
                enum: [low, medium, high]
              message:
                type: string
              action:
                type: string
        requires_validation:
          type: boolean
          description: True if human validation is recommended

    QualityBadge:
      type: object
      description: 'Sprint 13: Quality badge for theme'
      properties:
        label:
          type: string
          enum: [Excellente, Bonne, Acceptable, À revoir]
        color:
          type: string
          description: Hex color code
        icon:
          type: string
          description: Unicode emoji icon

    LintingReport:
      type: object
      description: 'Sprint 13: Content linting report'
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/LintIssue'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/LintIssue'
        info:
          type: array
          items:
            $ref: '#/components/schemas/LintIssue'
        stats:
          type: object
          properties:
            total_questions:
              type: integer
            total_words:
              type: integer
            avg_question_length:
              type: integer
            avg_answer_length:
              type: integer

    LintIssue:
      type: object
      description: 'Sprint 13: Individual linting issue'
      properties:
        code:
          type: string
          example: "DUPLICATE_QUESTION"
        message:
          type: string
        severity:
          type: string
          enum: [low, medium, high, critical]
        location:
          type: string
          example: "Question 3"

    LintingSummary:
      type: object
      description: 'Sprint 13: Linting summary'
      properties:
        status:
          type: string
          enum: [success, warning, error]
        message:
          type: string
        color:
          type: string

    SystemDiagnostic:
      type: object
      description: 'Sprint 13: System health diagnostic'
      properties:
        timestamp:
          type: string
          format: date-time
        status:
          type: string
          enum: [healthy, degraded, unhealthy]
        checks:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/DiagnosticCheck'
      example:
        timestamp: "2025-11-13T10:00:00Z"
        status: "healthy"
        checks:
          database:
            status: "ok"
            latency_ms: 12
            message: "Database connection healthy"
          ai_service:
            status: "ok"
            provider: "Mistral AI"
            message: "AI service configured"
          disk_space:
            status: "ok"
            used_percent: 45.2
            free_gb: 150.5
            total_gb: 250.0

    DiagnosticCheck:
      type: object
      description: 'Sprint 13: Individual diagnostic check'
      properties:
        status:
          type: string
          enum: [ok, warning, error, critical, info]
        message:
          type: string
        latency_ms:
          type: number
          format: float
        provider:
          type: string
        table_count:
          type: integer
        used_percent:
          type: number
          format: float
        free_gb:
          type: number
          format: float
        total_gb:
          type: number
          format: float
        version:
          type: string
        memory_limit:
          type: string
        backup_count:
          type: integer

    BackupInfo:
      type: object
      description: 'Sprint 13: Backup metadata'
      properties:
        name:
          type: string
          example: "studymate_backup_2025-11-13_02-00-00.zip"
        path:
          type: string
        size:
          type: integer
          description: Size in bytes
        size_human:
          type: string
          example: "45.2 MB"
        created_at:
          type: string
          format: date-time
        age_days:
          type: integer
          description: Age in days
