Aller au contenu

Alert-Parent Frontend

Description

Interface utilisateur de la plateforme Alert-Parent, permettant aux administrateurs et à l'équipe pédagogique de gérer les campus, promos, étudiants, templates d'alertes et campagnes d'envoi aux parents.

Informations techniques

Élément Valeur
Framework React 18 (Vite 5)
Langage JavaScript (JSX, pas de TypeScript)
UI TailwindCSS 3 + shadcn/ui
Data fetching TanStack React Query
HTTP Client Axios (instance partagée avec intercepteurs)
Routing React Router v6 (lazy-loaded)
Port 127.0.0.1:3004 (hôte) → 3000 (conteneur nginx)
Registry ghcr.io/epitechafrik/alert-parent-frontend
Déploiement Automatique via GitHub Actions sur push main

Utilisateurs cibles

  • Administrateurs : gestion des promos, étudiants, utilisateurs, envoi d'alertes
  • Équipe pédagogique (Users) : envoi et consultation des alertes

Pages principales

Page Route Description
Login /auth/login Connexion JWT ou Microsoft SSO
Alerts /alertes Historique des mails envoyés (lecture seule) avec filtres
New Alert (déprécié) /alertes/new Redirige vers /alert-campaigns/new (ancien formulaire retiré)
Alert Campaigns /alert-campaigns Historique des campagnes envoyées et brouillons
New Campaign /alert-campaigns/new Composer de campagne (mode template ou mail libre) avec preview et envoi
Edit Campaign /alert-campaigns/:campaignId/edit Reprise/modification d'un brouillon
Alert Templates /alert-templates Liste des templates dynamiques
New Template /alert-templates/new Création d'un template WYSIWYG
Edit Template /alert-templates/:templateId/edit Modification d'un template existant
Campuses /campuses Gestion des campus
Students /students Liste des étudiants actifs/inactifs
Promotions /promotions Gestion des promos (cycle + année)
Users /users Gestion des comptes admin (admin only)

Alertes et campagnes

Flux legacy retiré (/alertes/new)

Routes d'envoi legacy désactivées (HTTP 410)

Les anciennes routes POST /api/alerts/* (tepitech, stumpers, modules, roadblocks, cheaters, eval-internship, presences, projects, resend/:id) renvoient désormais 410 Gone. Côté frontend, les 8 formulaires par type (components/forms/alerts/), l'écran NewAlertScreen, la modale AlertPreviewModal et le bouton « renvoyer » de l'historique ont été supprimés.

La route /alertes/new est conservée mais redirige vers /alert-campaigns/new. Seules les lectures GET /api/alerts et GET /api/alerts/:id restent valides pour consulter l'historique des mails.

Les anciens types (Tepitech, Stumper, Module, Présence, Projet, Roadblock, -42, Évaluation de stage) sont désormais des templates DB (topics) utilisés dans le flux campagnes. Les seuils et codes couleur sont gérés côté backend via les colorRules des fileSchemas.

Flux campagnes /alert-campaigns

Les campagnes sont désormais le seul flux d'envoi. Le composer propose deux modes (kind) :

  • From template (kind:"template") : on choisit un template DB qui déclare les champs (variablesSchema) et fichiers (fileSchemas) à fournir.
  • Free email (kind:"free") : composer libre — objet + corps WYSIWYG + insertion de variables {{...}} + liste d'emails libres (extraRecipients), sans template. Un mail libre peut être enregistré comme template réutilisable. En mode libre, au moins un destinataire est requis (étudiants ciblés et/ou emails libres).

L'envoi est asynchrone : send met les mails en file (status: queued), le worker backend les envoie (sent / partial_failed). La liste et le détail d'une campagne sont pollés tant qu'une campagne est queued, pour voir le statut basculer.

Workflow UI (mode template) :

  1. Choisir le campus, puis le ciblage : sélection d'étudiants ou groupe. Les filtres promo/classe ne s'affichent (et ne sont envoyés) qu'en mode groupe.
  2. Choisir le topic/template.
  3. Remplir uniquement les champs définis par template.variablesSchema. Les options dépendant de la classe (sessions Tepitech : 6 pour TEK1/PSO, 4 pour TEK2/TEK3 ; solo stumper : 10 ; duo stumper : 7) sont bornées via field-options.
  4. Charger les fichiers définis par template.fileSchemas.
  5. Prévisualiser via POST /api/alert-campaigns/preview-draft (ou /:id/preview sur un brouillon).
  6. Sauvegarder en brouillon, ou envoyer.
Action UI Endpoint
Preview sans sauvegarde POST /api/alert-campaigns/preview-draft
Preview d'un brouillon POST /api/alert-campaigns/:id/preview
Sauvegarder brouillon POST /api/alert-campaigns
Modifier brouillon PUT /api/alert-campaigns/:id
Envoyer (asynchrone) POST /api/alert-campaigns/:id/send
Historique GET /api/alert-campaigns?scope=history
Brouillons GET /api/alert-campaigns?scope=drafts
Détail / suivi statut GET /api/alert-campaigns/:id
Supprimer brouillon DELETE /api/alert-campaigns/:id
Catalogue variables (helpers WYSIWYG) GET /api/alert-campaigns/variables
Options de champ par classe GET /api/alert-templates/:id/field-options?classe=
Enregistrer mail libre comme template POST /api/alert-campaigns/:id/save-as-template

La liste /alert-campaigns sépare History et Drafts. Le bouton Details ouvre une sidebar avec le ciblage, les variables, les fichiers, les surcharges et la timeline. Les brouillons peuvent être édités ou supprimés ; les campagnes envoyées restent en historique.

Validation des fichiers

Le composer réutilise le panneau de validation des fichiers :

  • colonnes requises/trouvées ;
  • colonnes vides ;
  • cellules incomplètes ;
  • logins inconnus ou non alignés avec les étudiants ciblés ;
  • aperçu coloré selon les règles du backend.

Les templates récents utilisent fileSchemas pour déclarer plusieurs fichiers attendus, par exemple notes + présences. Les anciens templates sans fileSchemas gardent un fallback rows compatible avec l'ancien flux.

Erreurs et warnings

preview et send renvoient une validation centralisée { errors[], warnings[] } :

  • errors (HTTP 400) : bloquant. Le composer les affiche et empêche l'envoi (ex. missing_required_field, invalid_session, missing_required_file, no_recipient, missing_free_subject/missing_free_body).
  • warnings : informatif, non bloquant (ex. unknown_variable, empty_cell, row_count_mismatch). L'utilisateur confirme avant d'envoyer.

Chaque objet contient un message en français prêt à afficher.

Templates dynamiques

Les templates sont gérés dans /alert-templates. L'éditeur est une page dédiée, pas une modale, avec un éditeur WYSIWYG pour le HTML du mail et des aides pour insérer les variables dynamiques.

Champs importants

Champ backend Usage frontend
name Nom affiché dans les listes et selects
topic Catégorie métier du template
campus Template global si vide, surcharge campus si renseigné
subjectTemplate Sujet du mail avec variables {{...}}
bodyTemplate Corps HTML édité en WYSIWYG
variablesSchema Source principale des champs de formulaire utilisateur
fileSchemas Fichiers attendus dans une campagne

variablesSchema pilote le type de champ affiché dans le composer :

Type Affichage
text Input simple
textarea Zone de texte longue
wysiwyg Éditeur riche
number Input numérique
date Sélecteur date
select Liste de choix

Options dépendant de la classe (sessions)

Pour les champs dont les options dépendent du topic/classe (sessions Tepitech, stumpers…), le composer ne se fie pas aux options brutes du template : il appelle GET /api/alert-templates/:id/field-options?classe=<classe> qui renvoie un variablesSchema aux options déjà résolues. C'est la source autoritaire ; un repli local existe le temps que l'API réponde. En mode « sélection d'étudiants » (sans classe de groupe), les options non bornées sont affichées et le backend valide invalid_session en filet.

Dans l'éditeur WYSIWYG, l'insertion de variables et des blocs prêts (salutation/signature) se fait via des selects compacts dans la barre d'outils, alimentés par le catalogue GET /api/alert-campaigns/variables (repli sur une liste interne).

Les variables système ne doivent pas être demandées à l'utilisateur :

student.* recipient.* promo.* campus.* row.* file.* files.* computed.*

Elles peuvent être insérées comme placeholders dans l'éditeur, mais elles sont résolues par le backend au moment du preview/envoi. Exemples : {{computed.projectResultSummary}}, {{files.grades.grade}}, {{recipient.firstname}}.

Surcharges de campagne

Dans le composer, l'utilisateur peut surcharger le template choisi pour une campagne précise :

  • overrideSubjectTemplate pour le sujet ;
  • overrideBodyTemplate pour le corps HTML ;
  • overrideVariables pour ajuster les variables de la campagne ;
  • studentOverrides pour des cas ciblés par étudiant, si le backend en expose déjà.

La preview affiche le HTML rendu dans une iframe sandboxée pour éviter d'afficher le code HTML brut.

Gestion multi-campus

Les campus sont intégrés aux écrans étudiants, promos et campagnes :

  • Les promos sont filtrées par campus.
  • Le changement de campus d'un étudiant filtre la liste des promos disponibles.
  • Si un campus n'a pas de promo, l'interface bloque ou guide l'utilisateur au lieu d'afficher un select vide ambigu.
  • Les templates peuvent être globaux ou spécifiques à un campus.

Gestion des étudiants

Soft delete (désactivation)

Les étudiants ne sont jamais supprimés définitivement — ils sont désactivés pour préserver l'historique des alertes.

Action Méthode Endpoint
Désactiver PUT /api/students/:id/deactivate
Réactiver PUT /api/students/:id/reactivate
Désactiver en masse POST /api/students/bulk/deactivate
Lister les inactifs GET /api/students?active=false

La page Students dispose d'un toggle Active/Inactive pour basculer entre les deux vues :

  • Vue Active : modifier, désactiver (individuel ou en masse), déplacer (classe/promo)
  • Vue Inactive : réactiver

Autres actions

  • Import CSV : upload en masse de nouveaux étudiants
  • Export XLS : export de la liste filtrée
  • Move (bulk) : déplacer des étudiants sélectionnés vers une autre classe/promo
  • Recherche : par nom d'étudiant ou par nom de référent
  • Filtres : campus, promo, classe, tri par nom

Architecture

Arborescence

frontend/
├── src/
│   ├── components/
│   │   ├── forms/users/     # Formulaires utilisateurs / profil
│   │   ├── modals/          # Modals (Admin + User)
│   │   ├── shared/          # DataTable, PageHeader, SearchInput, ConfirmDialog, CampusSelect
│   │   │   └── alerts/      # RichTemplateEditor, VariableField, FileUploadField, FileValidationPanel
│   │   └── ui/              # Composants shadcn/ui
│   ├── constants/           # Routes, types utilisateurs, classes
│   ├── context/             # UserContext (auth globale)
│   ├── hooks/               # React Query hooks + utilitaires
│   ├── lib/                 # Axios instance, queryClient, utils
│   ├── pages/               # Écrans par rôle (Admin, User, Auth)
│   ├── router/              # AppNavigation, AuthRouter, AdminRouter
│   └── services/            # Anciens services (legacy, migration en cours)

Hooks React Query

Chaque ressource a son propre fichier de hooks dans src/hooks/ :

Fichier Hooks principaux
useAlerts.js useAlerts(filters), useAlert(id)lecture seule (les mutations legacy useCreateAlert/usePreviewAlert/useResendAlert ont été retirées, routes 410)
useUsers.js useUsers(filters), useCreateUser(), useUpdateUser(), useDeleteUser()
useStudents.js useStudents(filters), useCreateStudent(), useUpdateStudent(), useDeactivateStudent(), useReactivateStudent(), useBulkDeactivateStudents(), useBulkUpdateStudents()
usePromos.js usePromos(filters), useDeletePromo()
useCampuses.js useCampuses(filters), hooks de création/modification/suppression campus
useAlertTemplates.js Liste, détail, useResolvedAlertTemplate, useTemplateFieldOptions(id, classe), création/modification/suppression
useAlertCampaigns.js Liste, détail (polling option), preview draft + brouillon, création/update, envoi, suppression, useCampaignVariables(), useSaveCampaignAsTemplate()

Authentification

  1. L'utilisateur se connecte via JWT classique ou Microsoft SSO
  2. Le token JWT est stocké dans localStorage
  3. L'intercepteur Axios l'injecte automatiquement dans chaque requête
  4. En cas de 401, l'intercepteur redirige vers /auth/login

Déploiement

Pipeline CI/CD (GitHub Actions)

Le pipeline .github/workflows/deploy.yml comporte 3 jobs :

graph LR
    A[build-and-push] --> B[deploy]
    B --> C[notify]
  1. build-and-push : Build Docker multi-stage (node:20-alpine → nginx:alpine), push sur GHCR
  2. deploy : SCP du docker-compose.yml, SSH pour pull + restart, healthcheck sur port 3004
  3. notify : Affiche le statut du déploiement

Variables Vite = build time

Les variables VITE_* sont injectées à la compilation via des build-args Docker (Vite les embarque dans le bundle JS). Elles ne sont pas lisibles au runtime.

docker-compose.yml

services:
  frontend:
    image: ghcr.io/epitechafrik/alert-parent-frontend:${IMAGE_TAG:-latest}
    container_name: alert-parent-frontend
    restart: always
    ports:
      - "127.0.0.1:3004:3000"
    env_file:
      - .env
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:3000"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

Dockerfile (multi-stage)

# Stage 1 : Build avec pnpm
FROM node:20-alpine AS builder
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
ARG VITE_REACT_APP_API_URL
ARG VITE_REACT_APP_FRONT_URL
ARG VITE_MICROSOFT_CLIENT_ID
ARG VITE_MICROSOFT_TENANT_ID
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

# Stage 2 : Serveur nginx
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 3000
CMD ["nginx", "-g", "daemon off;"]

Variables d'environnement

Variable Description Exemple
VITE_REACT_APP_API_URL URL de l'API backend https://api.epitools.bj/api
VITE_REACT_APP_FRONT_URL URL du frontend https://alert.epitools.bj
VITE_MICROSOFT_CLIENT_ID Client ID Azure AD (SSO) 2bda619b-...
VITE_MICROSOFT_TENANT_ID Tenant ID Azure AD 901cb4ca-...

Ces variables sont stockées dans le secret GitHub DOTENV_FILE et injectées comme build-args dans le pipeline.

Accès

L'application est accessible via Nginx reverse proxy sur https://alert.epitools.bj.

server {
    server_name alert.epitools.bj;
    location / {
        proxy_pass http://127.0.0.1:3004;
    }
}

Rollback

# 1. Trouver la version précédente
docker images ghcr.io/epitechafrik/alert-parent-frontend --format "table {{.Tag}}\t{{.CreatedAt}}"

# 2. Déployer une version spécifique
cd /root/projects/alert-parent/alert-parent-frontend
export IMAGE_TAG=sha-XXXXXXX
docker compose pull frontend
docker compose up -d --no-deps frontend

# 3. Vérifier
curl -sf http://127.0.0.1:3004 && echo "OK" || echo "FAIL"