Interface utilisateur de la plateforme XCCM 2. Construit avec Next.js 16, React 19 et TailwindCSS 4.
- Stack technique
- Installation
- Variables d'environnement
- Structure du projet
- Pages et fonctionnalités
- Composants clés
- Hooks personnalisés
- Tests
- Déploiement
| Outil | Rôle |
|---|---|
| Next.js 16 (App Router) | Framework frontend |
| React 19 | UI |
| TailwindCSS 4 | Styles |
| Zustand 5 | État global |
| TipTap + Yjs | Éditeur collaboratif CRDT |
| Hocuspocus | Fournisseur WebSocket (collaboration) |
| Framer Motion | Animations |
| Recharts | Graphiques / analytics |
| next-intl | Internationalisation (i18n) |
| Vitest + RTL | Tests unitaires (36 tests) |
| Playwright | Tests E2E |
cd front-xccm2
npm install --legacy-peer-deps
# Configurer l'environnement
cp .env.example .env.local
# Éditer .env.local avec vos URLs
# Démarrer en développement (port 3000)
npm run dev| Variable | Valeur développement | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
http://localhost:3001 |
URL de l'API backend |
NEXT_PUBLIC_HOCUSPOCUS_URL |
ws://localhost:1234 |
URL du serveur WebSocket Synapse |
JWT_SECRET |
(même que le backend) | Vérification côté serveur Next.js |
En production, remplacer par les URLs Vercel / Railway.
front-xccm2/
├── app/ # Pages (Next.js App Router)
│ ├── (auth)/ # Pages auth (login, register, reset)
│ ├── (dashboard)/ # Interface principale après login
│ │ ├── account/ # Tableau de bord utilisateur
│ │ ├── editor/ # Éditeur de cours
│ │ ├── classrooms/ # Gestion des classes
│ │ ├── marketplace/ # Marketplace
│ │ └── vault/ # Coffre-fort
│ └── api/ # Routes API Next.js (auth proxy, etc.)
├── components/
│ ├── ui/ # Composants atomiques (Button, Input, Modal…)
│ ├── editor/ # Éditeur TipTap + outils
│ ├── classroom/ # Composants LMS
│ ├── ai/ # Panneau IA éditeur
│ └── ErrorBoundary.tsx # Gestion d'erreurs React
├── hooks/
│ ├── useDebounce.ts # useDebounce, useDebouncedCallback, useDebouncedState
│ ├── useAutoReconnect.ts # Reconnexion WebSocket avec backoff exponentiel
│ └── useSynapseSync.ts # Synchronisation Yjs / Hocuspocus
├── lib/
│ ├── fetchWithRetry.ts # fetch avec retry auto + timeout (500/429/408 retried)
│ └── authService.ts # Login, logout, refresh token
├── context/
│ └── AuthContext.tsx # Contexte d'authentification global
├── e2e/ # Tests Playwright
└── src/test/ # Tests Vitest (36 tests)
- Inscription / Connexion par email + mot de passe
- OAuth Google et Microsoft (via NextAuth)
- Réinitialisation de mot de passe par email
- Gestion automatique du refresh token
- Structure hiérarchique : Parties → Chapitres → Paragraphes → Notions
- Éditeur WYSIWYG TipTap avec collaboration temps réel (Yjs CRDT)
- Présence des curseurs collaborateurs
- Assistant IA Mistral intégré dans le panneau latéral
- Export PDF / JSON
- Création et gestion de classes
- Rejoindre une classe via un code d'invitation
- Publication de devoirs, suivi des soumissions
- Exercices interactifs (QCU, QCM, code, texte à trous)
- Tableau de bord analytique par classe
- Marketplace — navigation et achat de contenus pédagogiques
- Vault — bibliothèque personnelle
- Profil — paramètres, avatar, statistiques
- Mode sombre / clair — via
next-themes
import { ErrorBoundary } from '@/components/ErrorBoundary';
<ErrorBoundary fallback={<p>Erreur inattendue</p>}>
<MonComposant />
</ErrorBoundary>Capture les erreurs React, affiche un fallback. Prop onReset pour un bouton "Réessayer".
Retarde la mise à jour d'une valeur jusqu'à ce qu'elle n'ait pas changé pendant delay ms.
const debouncedSearch = useDebounce(searchTerm, 300);Version debounce d'une fonction callback.
const handleSearch = useDebouncedCallback((q: string) => fetchResults(q), 300);État avec valeur immédiate (UI) et valeur debounce (API).
const [query, debouncedQuery, setQuery] = useDebouncedState('', 300);Reconnexion automatique avec backoff exponentiel et jitter, pour les WebSocket.
const { startReconnect, stopReconnect, notifySuccess, reconnectState } = useAutoReconnect({
maxRetries: 10,
initialDelay: 1000,
onReconnectAttempt: (n) => console.log(`Tentative ${n}`),
onReconnectFailed: () => toast.error('Connexion impossible'),
});
// Quand la connexion est perdue :
startReconnect(() => provider.connect());
// Quand la connexion est rétablie :
notifySuccess();Détecte les événements online / offline du navigateur.
const { isOnline } = useNetworkStatus();fetch avec retry automatique sur erreurs réseau, HTTP 5xx, 429 et 408. Backoff exponentiel + jitter.
const res = await fetchWithRetry('/api/projects', {
retries: 3,
retryDelay: 1000,
timeout: 10000,
onRetry: (attempt, err) => console.warn(`Retry ${attempt}:`, err.message),
});npm test # 36 tests unitaires (Vitest)
npm run test:watch # Mode watch
npm run test:coverage # Couverture v8
npm run test:e2e # E2E Playwright (nécessite le serveur démarré)
npm run test:e2e:ui # E2E avec interface graphiqueCouverture unitaire :
components/ErrorBoundary— rendu, fallback, retrylib/fetchWithRetry— succès, retry réseau, retry 500, exhaust, 401 non-retried, callbackcontext/AuthContext— unauthenticated, login, logouthooks/useDebounce— délai, reset, useDebouncedCallback, useDebouncedStatehooks/useAutoReconnect— start/stop/success, maxRetries, useNetworkStatus
Tests E2E (e2e/) :
- Login / Logout golden path
- Identifiants invalides → message d'erreur
- Route protégée → redirection login
# Build
npm run build
# Déployer sur Vercel
vercel --prodVariables d'environnement à configurer sur Vercel :
NEXT_PUBLIC_API_URL=https://xccm-2-api.vercel.app
NEXT_PUBLIC_HOCUSPOCUS_URL=wss://votre-synapse.up.railway.app
JWT_SECRET=<même valeur que le backend>
| Commande | Description |
|---|---|
npm run dev |
Serveur de développement (port 3000) |
npm run build |
Build production |
npm start |
Serveur production |
npm run lint |
ESLint |
npm test |
Tests Vitest |
npm run test:coverage |
Tests + couverture |
npm run test:e2e |
Tests Playwright |