You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Application web de gestion scolaire multi-filières, conçue pour tout établissement au Sénégal — franco-arabe, bilingue ou classique — grâce à des filières entièrement configurables par établissement (FR / AR / EN et toute combinaison, sans hypothèse de bilinguisme imposée). Gestion complète des élèves, du personnel, des classes, notes, bulletins, cahier de texte, finances, pointage (manuel et QR), emploi du temps, messagerie interne, bibliothèque et portail parents — interface trilingue Français / Arabe / Anglais (RTL pour l'arabe) et landing page publique.
Mono-établissement aujourd'hui, pensé pour devenir un SaaS multi-tenant. Le socle multi-tenant (etablissement_id partout, JWT scopé) existe déjà à ~80 % ; chaque établissement est actuellement déployé séparément. La bascule vers une offre SaaS multi-établissement (isolation RLS, onboarding, facturation) est un plan documenté, pas encore implémenté — voir docs/SAAS-INFRA-PLAN.md et la section Phase 4 — Multi-établissement.
Page d'accueil publique présentant la plateforme, ses modules et les guides par rôle, avec basculement thème
Élèves
Inscription (N filières via InscriptionClasse), fiche complète, matricule auto par établissement CODE-E-YY-NNN (ex. CAAM-E-26-001), transfert de classe en cours d'année, import CSV en masse, export Excel, opérations bulk (inscrire / désactiver / supprimer définitivement, admin), QR carte élève
Personnel
Comptes liés à un utilisateur, fonctions configurables (table Fonction), contrats CDD/CDI/stagiaire, état civil et qualifications, affectations matière×classe, QR carte professeur
Filières
Entité Filiere configurable par établissement : FR / AR / EN + combinaisons, N par établissement, langue & sens d'écriture (LTR/RTL), couleur propre
Classes
Rattachées à une filière et un niveau, capacité, par année scolaire ; duplication ; matières de la classe avec overrides de coefficient/barème par classe et par période ; listes PDF
Matières
Coefficient, note min et barème de saisie (note max) par défaut sur la matière, overridables par classe/période ; rattachement à un domaine pédagogique ; type Ressource/Compétence pour les grilles IEF
Domaines
Domaines pédagogiques IEF (Langue & Communication, Mathématiques, ESVS, EPSA…), grilles par groupe de niveau (CI-CP / CE1-CE2 / CM1-CM2)
Notes
Saisie en masse par classe/matière/période, validation sur le barème effectif, suppression en masse, politique de saisie configurable pour les professeurs (leurs matières/classes ou élargi)
Évaluations
Évaluations formatives (devoir, contrôle, test d'entrée, examen…) avec pondération
Cahier de texte
Séances faites (contenu, objectif) et devoirs à faire (leçon/exercice/récitation/autre) par classe×matière×date, vue « Ma journée » alignée sur l'emploi du temps, visa de la direction avec verrouillage de la période visée, indicateur de complétude (prévu vs. renseigné), export PDF (inspection), devoirs visibles côté portail parent
Bulletins
Par filière (FR / AR / EN — options construites dynamiquement selon les filières actives de l'établissement) + combiné au choix (filieres_combine) + annuel ; moyennes pondérées, mentions configurables (par filière et/ou niveau), échelle d'affichage par niveau (Niveau.note_max), classement, verrouillage de période (préflight + déverrouillage direction), templates HTML éditables (FR/AR/COMBINE/ANNUEL), aperçu PDF avant téléchargement, export PDF individuel ou classe entière, suivi de l'état de génération (à jour / périmé / partiel — recalculé après toute saisie de notes) avec régénération automatique des bulletins impactés et nettoyage des orphelins
Saisie par classe ou individuelle, justification, statistiques, alertes automatiques au-delà du seuil configurable
Pointage
Saisie journalière présence/absence/retard/congé du personnel, durée auto, historique, statistiques + pointage par QR code : QR signés HMAC par personnel, page publique /scanner, régénération des QR
Demandes d'absence personnel
Demandes de congé/absence du personnel avec workflow de traitement (approbation/refus)
Emploi du temps
Créneaux horaires par classe/professeur/matière, jours actifs flexibles par établissement, détection de conflits
Calendrier scolaire
Événements (vacances, examens, réunions, fermetures), navigation mensuelle, vue liste
Notifications in-app
Cloche avec badge, alertes d'absence, absences professeurs, refresh auto
Messagerie interne
Conversations filées, tout-à-tout + broadcast par rôle, raccourci Ctrl+Enter
Portail parents
Page publique sans compte (lien UUID, expiration automatique à la fin de l'année scolaire active) : notes, paiements, absences, devoirs (cahier de texte), informations de l'élève, téléchargement des bulletins PDF ; rotation du lien et écran dédié de gestion (liste, statut actif/révoqué/expiré, recherche, révocation)
Bibliothèque
Catalogue des livres, gestion des prêts/retours, suivi du stock et des retards
Finances
Paiements élèves (mensualités, inscriptions, saisie en masse), reliquats, paiements du personnel, numéros de reçu auto, exports Excel/PDF, catalogue de tarifs configurable
Documents officiels
25 types de documents (certificats, attestations, cartes élève/professeur avec QR, fiches de paie, convocations…) générés en PDF à partir de templates personnalisables, aperçu et génération par lot
Rapports
Présences (élèves/personnel), résultats par classe, bilan financier, grilles IEF, performance par domaine, relevés de notes, propositions de fin d'année, charges du personnel — avec aperçus HTML
Audit
Journal d'audit « qui fait quoi » : actions CREATE/UPDATE/DELETE par utilisateur et entité (accès direction)
Utilisateurs
Rôles depuis la DB, réinitialisation de mot de passe, désactivation/réactivation, suppression définitive
Paramètres
Établissement (code matricule, devise, en-têtes de bulletin FR/AR, logo/signature/cachet), config des notes (échelle, périodes configurables : nombre + noms FR/AR trimestres/semestres), niveaux, tarifs, fonctions, mentions, jours de cours, préférences de notifications, rendu des bulletins, politique de saisie des notes
Dashboard
Statistiques clés, graphique des encaissements (Recharts) + tableau de bord analytique direction
i18n FR/AR/EN
Interface trilingue (français, arabe, anglais — fallback FR) avec sélecteur de langue et bascule RTL instantanée pour l'arabe
Aide contextuelle
Bouton « ? » dans la barre du haut : rappel de l'objectif de la page courante et astuces d'utilisation, traduits FR/AR/EN, sur chaque écran de l'application
Dark mode
Persistant par utilisateur, actif dès la page de connexion
Observabilité
Sentry (backend + frontend) — capture des erreurs 5xx uniquement ; health check /health (DB + moteur PDF)
Stack technique
Couche
Technologie
Version
Backend
Node.js + Fastify
5.x
ORM
Prisma
5.x
Base de données
PostgreSQL
15+ (CI : 16)
Authentification
@fastify/jwt v10 + @fastify/cookie v11 + bcryptjs
cost 10
Rate limiting
@fastify/rate-limit
10.x
Validation
Zod (env + payloads, coerce pour les Decimal Prisma)
Note CLI Prisma : le CLI global peut être en v7.x alors que le projet utilise Prisma v5. Toujours utiliser ./node_modules/.bin/prisma dans ce projet pour éviter les conflits de version.
Chaque requête authentifiée extrait etablissement_id du JWT. Tous les services filtrent par cet identifiant — aucune donnée d'un autre établissement n'est accessible.
Rôles et accès (navigation)
Rôle
Pages accessibles
admin
Toutes
directeur
Toutes sauf Finances, Utilisateurs et Paramètres
gestionnaire
Toutes sauf Utilisateurs, Paramètres et Audit
agent de scolarité
Dashboard, Élèves, Emploi du temps, Calendrier, Messagerie, Bibliothèque, Absences, Finances
professeur
Dashboard, Classes, Notes, Évaluations, Cahier de texte, Bulletins, Activités, Emploi du temps, Calendrier, Messagerie, Absences
pointeur
Dashboard, Emploi du temps, Calendrier, Messagerie, Absences, Pointage
Le module Cahier de texte est accessible à admin, directeur, gestionnaire et professeur (groupe ACADEMIQUE) ; le visa (verrouillage d'une période) est réservé à la direction (admin, directeur).
Le journal d'audit (/audit) est réservé à la direction (admin, directeur) côté API.
Bulletins — filières et types
Type
Description
FR / AR
Bulletin d'une filière (français / arabe)
EN
Filière anglaise pleinement prise en charge (service, moteur de calcul, templates EN/ANNUEL_EN) ; le sélecteur du front l'affiche automatiquement dès qu'une filière EN est active. Seul le rapport socle IEF ne la ventile pas (grille officielle à colonnes fixes — par conception, cf. Dette technique)
COMBINE
Combiné au choix : fusionne les filières choisies à la génération (filieres_combine, ex. FR+AR, FR+EN) ; repli sur les filières actives de l'élève
ANNUEL
Récapitulatif annuel des périodes (trimestres/semestres selon l'établissement)
Points clés du calcul et du rendu :
Barème de saisie effectif d'une matière : ClasseMatierePeriode.note_max > ClasseMatiere.note_max_override > Matiere.note_max > ConfigNotes.note_max. Les notes sont normalisées sur la base canonique de l'établissement avant le calcul des moyennes.
Échelle d'affichage de la moyenne : portée par le niveau (Niveau.note_max, ex. primaire /10 et secondaire /20 dans le même établissement) ; repli sur ConfigNotes.note_max.
Mentions : configurables par établissement, avec portée filière et/ou niveau (résolution : filière+niveau > filière > niveau > établissement).
Coefficients par période : ClasseMatierePeriode permet de changer coefficient/barème/évaluée d'une matière entre le T1 et le T2 (fréquent en filière arabe).
Verrouillage de période : un préflight contrôle l'état avant génération ; la direction peut déverrouiller une période.
Templates éditables : un template HTML par type (FR/AR/COMBINE/ANNUEL), personnalisable par établissement, rendu par le moteur interne microTemplate.
Aperçu PDF : le même PDF que le téléchargement s'affiche d'abord dans une modale (iframe sur blob) avant l'enregistrement — l'utilisateur vérifie le rendu sans quitter l'application.
Cycle de vie des générations
Aucun fichier n'est stocké : chaque PDF est rendu à la volée (Puppeteer) à partir des données courantes ; seul Bulletin.generated_at trace la dernière génération. En conséquence, un bulletin peut devenir périmé si des notes ou le programme (coefficient/barème par période) changent après sa génération :
GET /bulletins/etat calcule pour une classe/période/filière un statut a_jour · perime · partiel · non_genere (badge affiché sur la page Bulletins).
Régénération automatique : toute saisie de notes (POST /notes/bulk) déclenche regenererBulletinsImpactes(), qui régénère uniquement les bulletins des élèves/matières/périodes touchés — sauf les bulletins déjà signés/validés, qui ne sont jamais écrasés silencieusement.
Nettoyage des orphelins : un bulletin qui ne correspond plus à aucune note existante (élève désinscrit, matière retirée) est supprimé automatiquement lors de la régénération plutôt que de rester figé sur des données disparues.
Jours de cours flexibles
Les jours actifs de la semaine sont configurables par établissement dans Paramètres → Pédagogie. L'emploi du temps n'affiche que les colonnes correspondant aux jours actifs. Un créneau sur un jour inactif est refusé par l'API.
Identité graphique
Identité enracinée dans la culture du daara sénégalais : papier chaud,
encre brune profonde, accent latérite (terracotta).
Mark complet : planchette lawh (forme arquée + trois lignes
d'écriture + monogramme « Dg ») (<LogoMark />) — usages : page de
connexion, en-tête bulletin PDF, page 404, splash mobile.
Installation
Prérequis
Node.js 20+
PostgreSQL 15+
1. Cloner
git clone https://github.com/kriimoohh/DaaraGest.git
cd DaaraGest
2. Backend
cd backend
npm install
# Configurer l'environnement
cp .env.example .env # puis éditer DATABASE_URL, JWT_SECRET et QR_SECRET# Appliquer les migrations (CLI local, pas global)
./node_modules/.bin/prisma migrate deploy
# Injecter les données initiales (dev)
npm run db:seed
# Démarrer
npm run dev # http://localhost:3000
3. Frontend
cd frontend
npm install
npm run dev # http://localhost:5173
Les deux serveurs doivent tourner simultanément.
Production (Railway) : npm start exécute prisma migrate deploy puis le
seed idempotent seed-prod.cjs avant de lancer le serveur — les migrations
sont donc appliquées automatiquement au déploiement.
Variables d'environnement
Validées au démarrage par Zod (src/config/env.ts) — le serveur refuse de démarrer si une variable requise est absente ou invalide.
Le seed de production (seed-prod.cjs) ne crée que le compte admin et les référentiels (rôles, niveaux, fonctions…).
Commandes disponibles
Backend
npm run dev # Serveur en mode watch (tsx)
npm run build # prisma generate + compilation TypeScript
npm start # Prod : migrate deploy + seed-prod + serveur compilé
npm test# Tests unitaires (Vitest, sans DB)
npm run test:integration # Tests d'intégration (*.itest.ts, nécessite Postgres)
npm run test:watch # Tests en mode watch
npm run test:coverage # Rapport de couverture de code
npm run lint # ESLint
npm run format # Prettier
npm run db:migrate # prisma migrate dev
npm run db:seed # Seed de développement
npm run db:cleanup # Script de nettoyage de données
npm run db:studio # Interface Prisma Studio
Frontend
npm run dev # Serveur Vite
npm run build # Build de production
npm run preview # Prévisualiser le build
npm test# Tests UI (Vitest + Testing Library)
API Reference
Préfixe : /api/v1. Toutes les routes requièrent Authorization: Bearer <token> (ou le cookie httpOnly), sauf : /health, POST /auth/login, POST /auth/refresh, GET /portail-parent/acces/:token (+ PDF bulletin), POST /pointage/scan et GET /pointage/scans-jour (protégés par signature HMAC des QR).
Auth
Méthode
Route
Description
POST
/auth/login
Connexion · rate-limited 5 req/min · verrouillage de compte après échecs répétés
POST
/auth/refresh
Renouveler le token via refresh token · rate-limited 10 req/min
POST
/auth/logout
Déconnexion + révocation du refresh token
GET
/auth/me
Profil connecté
PUT
/auth/change-password
Changer le mot de passe
PUT
/auth/profil
Mettre à jour nom, langue, thème
DELETE
/auth/sessions
Révoquer toutes les sessions actives
Années scolaires
Méthode
Route
Description
GET
/annees-scolaires
Liste
POST
/annees-scolaires
Créer
PUT
/annees-scolaires/:id
Modifier
PUT
/annees-scolaires/:id/activer
Définir comme active
DELETE
/annees-scolaires/:id
Supprimer
Filières
Méthode
Route
Description
GET
/filieres
Liste des filières de l'établissement
POST
/filieres
Créer (gestion)
PATCH
/filieres/:id
Modifier
DELETE
/filieres/:id
Supprimer (garde exhaustive des données liées)
Niveaux
Méthode
Route
Description
GET
/niveaux
Liste (avec échelle d'affichage note_max et groupe de grille IEF)
POST
/niveaux
Créer
PUT
/niveaux/:id
Modifier
DELETE
/niveaux/:id
Supprimer
Domaines pédagogiques
Méthode
Route
Description
GET
/domaines
Liste
POST
/domaines
Créer (gestion)
PUT
/domaines/:id
Modifier
DELETE
/domaines/:id
Supprimer (admin)
Matières
Méthode
Route
Description
GET
/matieres?filiere=
Liste (filtrable par filière)
POST
/matieres
Créer
PUT
/matieres/:id
Modifier
DELETE
/matieres/:id
Désactiver
Mentions
Méthode
Route
Description
GET
/mentions
Liste
POST
/mentions
Créer (gestion)
PATCH
/mentions/:id
Modifier
DELETE
/mentions/:id
Supprimer (la mention système « Insuffisant » est protégée)
Générer ou faire tourner (rotation, nouveau token) le lien de portail d'un élève — expiration auto à la fin de l'année scolaire active ; tracé dans l'audit (PORTAIL_GENERATE)
DELETE
/portail-parent/:token/revoquer
JWT
Révoquer un lien (tracé dans l'audit, PORTAIL_REVOKE)
GET
/portail-parent
JWT
Lister tous les tokens de l'établissement (actif/révoqué/expiré) — alimente l'écran dédié « Gestion du portail »
Politique de saisie des notes applicable à l'utilisateur courant
GET
/parametres/notifications
Préférences de notifications de l'établissement
PUT
/parametres/notifications
Modifier les préférences
Utilisateurs
Méthode
Route
Description
GET
/utilisateurs/roles
Liste des rôles (depuis la DB)
GET
/utilisateurs?page&search&role
Liste paginée
POST
/utilisateurs
Créer
PUT
/utilisateurs/:id
Modifier
DELETE
/utilisateurs/:id
Désactiver
PUT
/utilisateurs/:id/reactiver
Réactiver
DELETE
/utilisateurs/:id/definitif
Suppression définitive
PUT
/utilisateurs/:id/reset-password
Réinitialiser le mot de passe
Modules
Workflow typique en début d'année
Paramètres — Vérifier l'établissement (code matricule, devise), les filières actives, les tarifs, les jours de cours et la config des notes (nombre et noms des périodes : trimestres ou semestres)
Années scolaires — Créer l'année (ex: "2025-2026") et l'activer
Niveaux & Domaines — Vérifier les niveaux (échelle d'affichage, grille IEF) et les domaines pédagogiques
Matières — Vérifier/ajouter les matières par filière avec coefficients et barèmes
Classes — Créer les classes, rattacher les matières (overrides par classe/période si besoin)
Élèves — Ajouter manuellement ou importer via CSV (matricule auto CODE-E-YY-NNN), inscrire dans les classes par filière
Personnel — Créer les comptes du personnel et les affectations matière×classe
Emploi du temps — Saisir les créneaux par classe
Calendrier scolaire — Enregistrer les vacances et examens
Notes → Bulletins → Finances → Pointage au fil de l'année
Import CSV élèves
Format attendu (en-têtes obligatoires : nom_fr, prenom_fr, sexe) :
Les lignes invalides sont ignorées avec rapport d'erreur détaillé
Pointage par QR code
Chaque personnel dispose d'un QR code signé HMAC (QR_SECRET), affiché sur sa carte professionnelle (module Documents) ou récupérable dans Pointage
La page publique /scanner (tablette/téléphone à l'entrée) scanne les QR via la caméra
Un scan valide crée/complète la présence du jour (source='qr') — arrivée puis départ
Un QR peut être régénéré à tout moment (l'ancien est invalidé)
Le pointage manuel reste disponible pour les correctifs et les statuts congé/retard
Cahier de texte
Journal de classe quotidien, pensé pour rester au plus près du geste du professeur en salle :
Ma journée — vue du jour alignée sur l'emploi du temps : chaque créneau de la classe/matière propose de saisir directement la séance faite (contenu, objectif) ; une séance peut aussi être créée hors créneau
Devoirs à faire — leçon, exercice, récitation ou autre, avec date de remise (pour_le) distincte de la date de saisie (donne_le) ; visibles par le parent dans l'onglet Devoirs du portail
Complétude — indicateur « prévu vs renseigné » : nombre de créneaux de la période effectivement couverts par une séance saisie
Visa de la direction — la direction vise un intervalle [du, au] d'une classe, ce qui verrouille la saisie sur cette période (comme le verrouillage de période des bulletins)
Export PDF — cahier imprimable pour l'inspection académique
Portail parents
Le portail parent est accessible via un lien unique sans création de compte :
Page Élèves → cliquer l'icône portail sur la ligne de l'élève, ou l'écran dédié Gestion du portail (liste de tous les liens de l'établissement, recherche, statut actif/révoqué/expiré)
Cliquer Générer le lien → un UUID est créé, ou tourné (rotation : nouveau token, l'ancien devient invalide) s'il en existait déjà un
Copier et partager le lien via WhatsApp ou SMS
Le parent voit les notes par période, paiements, absences, devoirs (cahier de texte), informations de l'élève et peut télécharger ou prévisualiser les bulletins PDF
Le lien expire automatiquement à la fin de l'année scolaire active (repli sur une durée fixe si aucune année active) ; l'admin/direction/gestionnaire peut aussi le révoquer à tout moment
Chaque génération et révocation est tracée dans le journal d'audit (PORTAIL_GENERATE / PORTAIL_REVOKE)
Messagerie interne
Individuelle : envoyer à un ou plusieurs utilisateurs nommément
Broadcast : envoyer à un ou plusieurs rôles (ex: tous les professeurs)
Messages classés du plus ancien au plus récent dans le fil
Indicateur non-lus sur la liste de conversations
Raccourci Ctrl+Enter pour envoyer
Alertes automatiques (notifications)
Déclencheur
Destinataires
Élève atteint N × seuil_absences_alerte absences non-justifiées
admin, directeur, gestionnaire
Professeur marqué absent
admin, directeur
Sécurité
Mesure
Détail
Variables d'env
Validées par Zod au boot (config/env.ts) — fail-fast si JWT_SECRET/QR_SECRET absents ou < 32 caractères
Cookie httpOnly daaragest_token (le header Authorization: Bearer reste accepté pour les clients API)
Stockage token (frontend)
Aucun — le token n'est jamais exposé au JavaScript (cookie httpOnly), immunisé XSS ; seul le profil utilisateur est en Zustand
Mots de passe
bcrypt cost 10 · changement forcé à la 1re connexion (seed)
Verrouillage de compte
Compteur de tentatives + verrouillage temporaire après échecs répétés
Auth middleware
return reply.status(401) — arrêt immédiat sur token invalide
Rate limiting
Global : 1000 req/15 min par utilisateur (clé = hash du JWT ; repli sur l'IP pour les routes publiques — l'école entière partage une seule IP publique via NAT) · login 5/min · refresh 10/min · portail parent 30/min
CSRF
Validation de l'en-tête Origin sur toutes les mutations (POST/PUT/PATCH/DELETE) — indispensable car l'auth cookie est sameSite=none en prod
CORS
Origines configurables via CORS_ORIGIN (multi, séparées par virgules)
Redaction automatique des mots de passe, cookies et en-têtes Authorization
Multi-tenant
Chaque requête filtre par etablissement_id extrait du JWT
Validation
Zod sur tous les body POST/PUT · z.coerce.number() pour les Decimal Prisma
RBAC — routes
Groupes de rôles (ROLE_GROUPS) par route, y compris FINANCES/FINANCES_GESTION (le directeur n'a aucun accès finances, arbitrage établissement) — verrouillé par rbac.test.ts
RBAC — payloads
utils/sanitize.ts cure les réponses par rôle : le hash mot_de_passe ne sort jamais, et salaire_base/cni/qr_token (Personnel) sont réservés aux rôles de gestion — même quand un include Prisma récupère l'objet complet. Verrouillé par rbac/payloads.itest.ts (vérifie le contenu réel des réponses, pas seulement qui a le droit d'appeler la route)
PDF
escapeHtml() sur toutes les données utilisateur avant insertion dans les templates
QR codes
Signés HMAC-SHA256 (QR_SECRET) — un QR forgé est rejeté au scan ; régénérables individuellement à tout moment (l'ancien est invalidé)
Portail parent
Token UUID en base, révocable, expiration automatique (fin de l'année scolaire active), rotation, sans création de compte utilisateur, actions tracées dans l'audit
Endpoints publics
/pointage/scans-jour (kiosque) ne renvoie qu'identité + heures — jamais salaire/CNI/qr_token, même si l'établissement est devinable dans l'URL
Erreurs
Gestionnaire global : 4xx explicites, 5xx anonymisés + capture Sentry
Proxy
trustProxy activé (Railway) pour que le rate-limit voie la vraie IP cliente
Flux d'authentification
1. POST /auth/login → { user } + cookies httpOnly (daaragest_token + daaragest_refresh)
2. Le token n'apparaît jamais dans le body ni dans le JavaScript (immunisé XSS)
3. Chaque requête : cookie envoyé automatiquement (credentials: include) ;
Authorization: Bearer accepté en alternative pour les clients API
4. Backend : jwtVerify() → vérifie header puis cookie en fallback
5. Zod valide le payload JWT (id, role, etablissement_id, langue, theme, doit_changer_mdp)
6. À expiration : POST /auth/refresh renouvelle silencieusement via le cookie refresh
Principaux domaines couverts côté unitaire : calculs de bulletins (moyennes pondérées, mentions, classement, template), cycle de vie des générations (état à jour/périmé/partiel, régénération, orphelins), cahier de texte (génération HTML, complétude), pointage (calcHeures), matricules, reçus, validation des notes et barèmes, alertes d'absence, auth (hash, payload JWT, lockout), CSRF, documents/templates, RBAC de tous les groupes (routes et payloads), sécurité (injection, escapeHtml), politique de saisie des notes, filières, micro-templating.
Convention de ce projet : chaque nouveau test de garde (RBAC, sécurité, règle métier) doit être prouvé par injection de régression — casser temporairement le code protégé, confirmer que le test échoue, puis restaurer — sinon le test peut être un faux positif qui teste une copie de la logique plutôt que le code de production.
Intégration — Postgres 16 en service, replay complet des migrations depuis zéro (prisma migrate deploy), puis tests d'intégration
Frontend — type-check, tests, build Vite
⚠️npm test local ne couvre pas les tests d'intégration : lancer npm run lintetnpm run test:integration avant de pousser un changement de schéma ou de lecteurs.
Roadmap — chantiers en cours
Modules déjà implémentés : Filières génériques (entité Filiere, inscriptions N-filières, colonnes string supprimées — refonte soldée), Bulletins FR/AR/EN + combiné au choix, cycle de vie des générations (état à jour/périmé/partiel, régénération automatique après saisie de notes, nettoyage des orphelins) + aperçu PDF, Mentions configurables (seule source des seuils, libellé arabe sur les bulletins AR), Échelle d'affichage par niveau, Domaines & grilles IEF, Tarifs, Fonctions configurables, Cahier de texte (séances, devoirs, visa/verrouillage, complétude, export PDF, intégration portail parent), Pointage QR, Audit log, Demandes d'absence personnel, Évaluations formatives, Progression pluriannuelle, Activités parascolaires, Bibliothèque, Portail parents (bulletins PDF, expiration auto, rotation, écran de gestion dédié), Documents officiels (25 types), Rapports (11 types + aperçus), Tableau de bord analytique, Refresh tokens, Verrouillage de période des bulletins, Templates de bulletins éditables, RBAC route + payload (finances hors périmètre direction, payloads Personnel/Utilisateur curés par rôle), i18n FR/AR/EN synchronisée, aide contextuelle in-app (bouton « ? » par page), Sentry, CI complète.
Phase 4 — Multi-établissement
Le socle multi-tenant existe (etablissement_id partout, JWT scopé). Reste l'onboarding : module etablissements, super-admin plateforme, branding par école. C'est la trajectoire produit visée (passage d'un déploiement mono-établissement à un SaaS multi-tenant) ; le plan détaillé — isolation RLS, provisioning/facturation, infra cible, coûts — est dans docs/SAAS-INFRA-PLAN.md. À déclencher quand une deuxième école arrivera (la Phase A « isolation » de ce plan doit être terminée avant).
Pointage NFC
Les modèles PersonnelCarte, Pointage et HeureTravail sont présents en schéma mais sans API (décision : conservés tels quels). Le pointage QR couvre le besoin actuel ; le NFC reste une évolution possible (badges physiques).
Application mobile (React Native)
Expo + partage des types TypeScript, mode hors-ligne pour la saisie de notes et la messagerie.
Priorités suggérées
Chantier
Valeur métier
Complexité
Phase 4 multi-établissement
★★★☆☆
★★★★☆
Pointage NFC
★★☆☆☆
★★★★☆
App mobile
★★★★★
★★★★★
Dette technique
L'audit de cohérence de juillet 2026 (PR #126–#136) a soldé la dette précédemment listée ici : transition filières (colonnes string supprimées), consolidation des mentions (seuils fixes retirés), lien de navigation Audit, champs directeur legacy et stockage du token (cookie httpOnly seul). L'audit RBAC du 18 juillet 2026 (PR #157) a fermé le trou méthodologique restant : la matrice de rôles (rbac.test.ts) verrouillait qui appelle chaque route mais pas ce que la route renvoie — des include Prisma sans select laissaient fuiter le hash de mot de passe et la fiche RH (salaire, CNI, QR) à des rôles non autorisés, y compris sur un endpoint public. Corrigé via utils/sanitize.ts + rbac/payloads.itest.ts, avec au passage l'arbitrage établissement retirant tout accès finances au directeur. Restent connus :
1. Modèles NFC sans API (priorité basse — décision : conservés)
PersonnelCarte, Pointage, HeureTravail sont en schéma sans aucune route, réservés à un éventuel pointage par badge NFC. Le pointage QR couvre le besoin actuel.
2. Rapport socle IEF et filière EN (niche, par conception)
La grille officielle IEF est à colonnes fixes (LC FR / LC AR / Maths) — une matière-langue EN y tombe dans LC FR. L'anglais ne figure pas dans la grille officielle sénégalaise ; ne pas « corriger ».
About
DaaraGest, une application web de gestion d'école franco-arabe basée au Sénégal