Chapitre 1
Architecture
Les composants de la plateforme, les conteneurs qui les portent, les volumes de données et les flux réseau.
Concerne :Équipe techniqueHébergeur
La plateforme READ est une application web unique (un « monolithe modulaire »), livrée en conteneurs Docker et orchestrée par Docker Compose sur un seul serveur.
Composants logiciels#
- Application web en .NET 10 (Blazor, rendu côté serveur) : pages légères, peu de JavaScript (graphiques, calendrier, grille de saisie). Elle sert le site des comptes connectés (
/admin,/espace), le portail public (/) et l'API (/api/v1). - Module hors ligne (
/terrain/) : application WebAssembly installable sur un téléphone (PWA). Elle est servie par la même application et dialogue avec la plateforme par l'API, au moyen de jetons. - Base de données PostgreSQL 16. Les dates y sont enregistrées en UTC et affichées à l'heure de Niamey ; les montants sont en FCFA sans décimale.
- Relais HTTPS Caddy : il obtient et renouvelle automatiquement le certificat (Let's Encrypt), ajoute les en-têtes de sécurité, compresse les réponses et transmet les requêtes à l'application.
Chaque écriture en base produit une ligne du journal d'audit (anciennes et nouvelles valeurs), dans la même transaction. Le journal est en ajout seul : l'application n'a pas le droit de le modifier ni de le vider.
Conteneurs#
Le projet Compose s'appelle toujours read-plateforme (fixé dans compose.yaml), quel que soit le dossier où se trouve le code. Les conteneurs portent donc des noms comme read-plateforme-app-1.
| Service | Image | Rôle |
|---|---|---|
db | postgres:16.15-alpine | Base de données ; port non publié sur l'hôte |
migrations | read-plateforme:latest | Lancé à chaque docker compose up, puis arrêté : applique les migrations du schéma avec le compte propriétaire et crée ou met à jour le rôle restreint de l'application |
app | read-plateforme:latest | Application, port 8080 interne ; se connecte avec le rôle restreint |
caddy | caddy:2.11.7-alpine | Seul service exposé : ports 80 et 443 (TCP, et UDP pour HTTP/3) |
L'image read-plateforme:latest est construite sur le serveur à partir du code source (Dockerfile) : aucun registre d'images n'est nécessaire.
Remarque
Au premier démarrage sur une base vide, le service migrations écrit dans son journal une erreur sur la table __EFMigrationsHistory avant de la créer. Elle est normale.
Volumes de données#
| Volume | Contenu | Sauvegardé |
|---|---|---|
read-plateforme_pgdata | Fichiers de la base PostgreSQL | Oui, par pg_dump |
read-plateforme_app-donnees | Fichiers déposés : logo, pièces jointes, ressources de la bibliothèque, e-mails écrits localement (boite-envoi/) | Oui |
read-plateforme_app-keys | Clés de protection des données (cookies de session, jetons) | Oui |
read-plateforme_app-logs | Journaux quotidiens de l'application, 30 jours | Non |
read-plateforme_caddy-data | Certificats HTTPS | Non (redemandés automatiquement) |
read-plateforme_caddy-config | État de Caddy | Non |
Attention
Ne supprimez jamais les volumes pgdata, app-donnees ou app-keys : docker compose down -v efface toutes les données de la plateforme. Sans app-keys, toutes les sessions et tous les jetons du module hors ligne deviennent invalides (les utilisateurs doivent se reconnecter).
Flux réseau#
| Sens | Depuis | Vers | Port | Usage |
|---|---|---|---|---|
| Entrant | Internet | caddy | 80/TCP | Redirection vers HTTPS, validation du certificat |
| Entrant | Internet | caddy | 443/TCP et 443/UDP | Site, portail, API, module hors ligne |
| Entrant | Poste de l'équipe technique | Serveur | 22/TCP | SSH (déploiement, exploitation) |
| Interne | caddy | app | 8080 | Relais HTTP sur le réseau Docker |
| Interne | app, migrations | db | 5432 | Base de données |
| Sortant | caddy | Let's Encrypt | 443 | Obtention et renouvellement du certificat |
| Sortant | app | Serveur SMTP | 587 ou 465 (réglable) | E-mails (mot de passe oublié, notifications) |
| Sortant | Sauvegarde | Stockage objet S3 | 443 | Copie chiffrée hors serveur |
L'application ne croit l'adresse du client transmise par Caddy (en-tête X-Forwarded-For) que si la requête vient d'un réseau privé (réseau Docker) : la limitation des connexions et le journal d'audit voient la vraie adresse du visiteur.
Organisation du serveur#
| Emplacement | Contenu |
|---|---|
/opt/read/.env | Réglages et secrets (droits 600) ; lié dans code/deploy/.env |
/opt/read/code | Code de la version déployée ; fichier VERSION = commit |
/opt/read/code.ancien | Version précédente, pour un retour arrière |
/opt/read/deploiement.log | Compte rendu du dernier déploiement |
/var/backups/read | Sauvegardes locales, un dossier horodaté par jour |
/etc/systemd/system/read-sauvegarde.* | Minuteur de la sauvegarde quotidienne |
Tâches de fond#
L'application exécute elle-même quelques tâches, sans planificateur externe :
- chaque minute : envoi des e-mails de notification en attente ;
- chaque jour à partir de 7 h (heure de Niamey) : rappels (activités et rapports en retard), puis suppression des notifications de plus de 90 jours ;
- chaque jour (première passe cinq minutes après le démarrage) : suppression des listes de présence arrivées à échéance, effacement des coordonnées des demandes d'inscription refusées depuis 12 mois, purge des jetons de l'API expirés ou révoqués.
La sauvegarde, elle, est lancée par un minuteur systemd du serveur (chapitre Sauvegarde et restauration).