Skip to content

Vue d'ensemble de l'architecture

English version
Retour au sommaire


Présentation générale

Racines est une PWA (Progressive Web App) de compagnon d'apprentissage des langues africaines. L'application est organisée autour de trois rôles (Joueur, Locuteur, Admin) avec des routes et des APIs dédiées.


Diagramme d'architecture

Internet
    │
    ▼
┌─────────────────────────────────────┐
│             Traefik                 │  ← Reverse proxy + TLS
│         (port 80/443)               │
└──────────────────┬──────────────────┘
                   │
                   ▼
┌─────────────────────────────────────┐
│          Next.js App                │  ← Port 3000
│    (App Router, Server Components)  │
│                                     │
│  ┌──────────┐  ┌────────────────┐  │
│  │  Pages   │  │  API Routes    │  │
│  │  /       │  │  /api/*        │  │
│  │  /[lang] │  │                │  │
│  │  /admin  │  │                │  │
│  │  /speaker│  │                │  │
│  └──────────┘  └───────┬────────┘  │
└───────────────────────┬┴────────────┘
                        │
           ┌────────────┴────────────┐
           ▼                         ▼
┌─────────────────┐       ┌─────────────────┐
│   PostgreSQL    │       │     MinIO        │
│   (Port 5432)   │       │  (Port 9000)     │
│                 │       │  Bucket: audios  │
│  languages      │       │  (public-read)   │
│  cards          │       └─────────────────┘
│  items          │               │
│  speakers       │               │ URL publique
│  admins         │               ▼
│  statistics     │     ┌─────────────────┐
│  contact_msgs   │     │  CDN / Client   │
│  quiz_sessions  │     │  (AUDIO_CDN_URL) │
└─────────────────┘     └─────────────────┘

Stack technique

Couche Technologie Rôle
Framework Next.js 16 (App Router) SSR, API Routes, routage
UI React 19 + TypeScript Composants, état
Styling Tailwind CSS 4 Styles utilitaires
Base de données PostgreSQL 15 Données applicatives
ORM / Client DB pg (node-postgres) Requêtes SQL brutes avec pool
Stockage audio MinIO (S3-compatible) Fichiers audio MP3
Traitement audio FFmpeg (fluent-ffmpeg) Conversion, compression, normalisation
Auth admin PBKDF2 + JWT (jose) Authentification sécurisée
PWA Service Worker + IndexedDB v3 Mode hors ligne
Charts Recharts Graphiques admin
Import Excel xlsx Parsing des fichiers .xlsx
Email Nodemailer Formulaire de contact
Reverse proxy Traefik TLS, routing, CORS

Flux de données principaux

1. Flux de lecture (joueur)

Joueur (navigateur)
    │
    ├─ SSR (Server Component) ──► PostgreSQL → cartes + items
    │
    ├─ Hydratation client
    │
    └─ Lecture audio ──────────► CDN MinIO (AUDIO_CDN_URL) direct
                                  ou fallback /api/audio/serve/[...path]

2. Flux d'upload audio (locuteur)

Locuteur (navigateur)
    │
    └─ POST /api/audio/upload
            │
            ├─ Vérification code speaker (table speakers)
            ├─ FFmpeg processing (mono, 96kbps MP3)
            ├─ Upload vers MinIO (bucket: audios)
            └─ UPDATE items SET audio_url = ... (PostgreSQL)

3. Flux hors ligne (joueur)

Joueur installe l'app
    │
    └─ Service Worker INSTALL
            │
            └─ PRECACHE_URLS (assets statiques)

Joueur télécharge une langue
    │
    └─ Message CACHE_PAGES → Service Worker
            │
            ├─ Étape 1 : Ping /api/health/live
            ├─ Étape 2 : GET /api/languages/[id]/content → IndexedDB
            ├─ Étape 3 : Fetch audios → cache racines-audio-cache-v3
            ├─ Étape 4 : Nettoyage orphelins
            └─ Étape 5 : Cache HTML pages

Décisions d'architecture structurantes

Pas de TTS (Text-to-Speech)

L'application n'utilise jamais de voix de synthèse. Si un item n'a pas d'enregistrement natif (audio_url IS NULL), le bouton audio est simplement absent. La qualité prime sur la complétude.

Offline-first

Le contenu est conçu pour fonctionner sans connexion après téléchargement. Le Service Worker est la clé de voûte de cette architecture.

Audio CDN direct

En production, les audios sont servis directement depuis MinIO via AUDIO_CDN_URL — le serveur Next.js n'est pas dans le chemin de lecture. Le proxy fallback (/api/audio/serve/) n'est utilisé qu'en développement.

PostgreSQL avec SQL brut

Pas d'ORM. Les requêtes sont écrites en SQL natif via le pool pg. Cela offre un contrôle total sur les performances et les agrégations complexes.

Service Worker conditionnel

Le SW est désactivé sur /admin et /speaker pour éviter les conflits de cache dans ces interfaces à état.


Structure des dossiers source

src/
├── app/                        # Next.js App Router
│   ├── page.tsx                # Page d'accueil (/)
│   ├── layout.tsx              # Root layout (AUDIO_CDN_URL injection)
│   ├── [language]/             # Pages joueur
│   │   ├── page.tsx            # Hub de la langue
│   │   ├── words/              # Défi Mot
│   │   ├── phrases/            # Défi Phrase
│   │   └── revision/           # Révision QCM
│   ├── admin/                  # Interface admin (protégée JWT)
│   ├── speaker/                # Interface locuteur
│   ├── contact/                # Formulaire de contact
│   └── api/                    # API Routes
├── components/                 # Composants React
│   ├── admin/                  # Composants admin
│   ├── revision/               # Composants QCM
│   └── [shared]/               # Nav, Audio, Modales...
├── contexts/                   # Contextes React
│   ├── LanguageContext.tsx      # Déverrouillage langues, flag admin
│   └── SpeakerContext.tsx       # Auth locuteur
├── hooks/                      # Hooks personnalisés
│   └── useAuth.tsx             # Hook auth admin
├── lib/                        # Utilitaires et services
│   ├── postgres.ts             # Pool PostgreSQL
│   ├── auth.ts                 # PBKDF2, JWT
│   ├── auth-middleware.ts      # Middleware de protection
│   ├── audio-url.ts            # Génération URLs audio
│   ├── minio-client.ts         # Client MinIO
│   ├── offline-download.ts     # Orchestration téléchargement offline
│   ├── offline-data.ts         # Lecture données depuis IndexedDB
│   ├── network-state.ts        # Circuit breaker réseau
│   ├── statistics.ts           # Tracking événements
│   └── quizUtils.ts            # Logique QCM
├── types/                      # Types TypeScript
│   └── index.ts                # Tous les types métier
└── data/
    └── quiz-distractors.ts     # Données des distracteurs QCM

Étapes suivantes