Base de code du service public numérique Aides Agri.
Cette base de code gère un catalogue des dispositifs d’aide publics destinés aux exploitations agricoles françaises. Elle propose deux interfaces utilisateurs :
- Un outil d’administration et d’édition des aides par l’équipe Aides Agri
- Un parcours usager pour aiguiller les exploitantes et exploitants agricoles vers des dispositifs adaptés à leur situation et à leur besoin
De manière classique pour un produit porté par beta.gouv.fr, et dont le cœur de complexité technique se situe dans la base de données plutôt que dans l’interface utilisateur :
- Base de données relationnelle : PostgreSQL
- Framework web : Django
- Interface web publique :
- Templates Django
- Système de design de l'État français (DSFR), intégré via l’app Django django-dsfr
- Interactions web : StimulusJS et htmx
- Interface web d’administration : Django admin
- Hébergement web : Scalingo, un PaaS similaire à Heroku mais hébergé en France chez Outscale
- Envoi de courriels : Brevo
- Suivi de l’activité des utilisateurs : Matomo, sur une instance hébergée par la DINUM
- Suivi des erreurs logicielles (Python et Javascript) : Sentry, sur une instance hébergée par la DINUM
- Suivi de la disponibilité du service : via une vue dédiée à La Ruche de l’outil updown.io
- Suivi des bonnes pratiques techniques : via le DashLord de La Ruche
Le projet Django est situé dans le répertoire conf. Il comprend, en plus des classiques points d’entrées WSGI/ASGI et définition des URLs :
- Les réglages :
- Les settings Django de base sont dans
settings/base.py - Les settings Django des apps installées (réutilisables ou spécifiques) sont dans
settings/apps/* - Un assemblage par défaut des settings est disponible dans
settings/default.py - Puis un assemblage spécifique à chaque contexte d’exécution est disponible :
settings/devel.pypour le développement localsettings/testing.pypour l’exécution des tests, que ce soit en local ou dans la CIsettings/scalingo.pypour l’exécution déployée chez Scalingo, quel que soit l’environnement
- Les settings Django de base sont dans
- Une spécialisation de l’admin Django pour forcer la double-authentification
Note
Elles sont choisies selon les critères suivants :
- Viabilité
- Simplicité (notamment éviter les dépendances ajoutant des briques d’infrastructure)
- Valeur ajoutée par rapport à un développement spécifique
Liste que je vais tenter de garder à jour :
- django-dsfr : intégration du DSFR avec Django
- django-anymail : envoi de courriels via Brevo sans complexité
- django-csp : sécurisation des ressources demandées par les pages web
- dj-importmap : automatisation de la construction de l’élément
<importmap> - django-two-factor-auth : second facteur d’authentification pour l’interface d’admin
- django-pgtrigger : gestion d’un TTL sur des valeurs écrites dans PostgreSQL, pour un système de verrou
- django-reversion : historisation des modifications apportées aux aides via l’interface d’admin
- django-tasks : worker (pas encore en version 1.0, mais remplace Celery de manière bien plus légère, avec PostgreSQL en backend, et compatible nativement avec l’avenir de Django, qui intégrera à partir de sa version 6.0 une interface logicielle pour les workers)
- django-htmx : intégration facilitée de htmx (n’a pas une valeur ajoutée énorme pour ce produit aujourd’hui mais est parfaitement viable)
- django-admin-extra-buttons : personnalisation facile et élégante de l’admin Django
ui: pour des extensions àdjango-dsfret la définition de templates de base, de styles de base, de composants réutilisables, etc.admin_concurrency: implémente un système de verrous sur l’édition de contenus dans l’admin Django ; option choisie après avoir constaté qu’aucune brique open-source sur le sujet ne correspondait aux exigences de viabilité et de simplicité)
aides: implémente les entités et les logiques métier liées aux dispositifs d’aide publics à l’agricultureagri: implémente le parcours utilisateur destiné aux exploitantes et exploitants agricoles afin de les aiguiller vers les aides pertinentes pour leur situation et leur besoinaides_feedback: implémente de quoi permettre à nos utilisatrices et utilisateurs de donner leur avis sur le parcours qui leur est proposé ainsi que sur les contenus qui leur sont présentéspac: implémente une représentation en base de données relationnelle du Plan Stratégique National de la PAC 2023-2027 ; c’est un outil à usage interne technique uniquementproduct: implémente les aspects périphériques du site web, comme les pages légales ; cette app Django pourrait être amenée à être extraite de cette base de code pour la rendre réutilisable au sein d’un modèle de base de code Django pour beta.gouv.fr
Note
Ce diagramme ne devrait jamais montrer de dépendance cyclique
graph TD;
agri-->aides;
agri-->aides_feedback;
agri-->ui;
aides-->admin_concurrency;
aides-->aides_feedback;
aides-->ui;
product-->ui;
- L’application contient très peu de CSS, l’essentiel du style étant assuré par le DSFR
- Les quelques fichiers CSS spécifiques sont rangés dans le répertoire
static/de l’app Django concernée - Aucun mécanisme de pre-processing ou post-processing n’est appliqué
- Quand il y a besoin d’interactivité dans le navigateur, un contrôleur Stimulus est créé dans le répertoire
static/de l’app Django concernée - Les contrôleurs Stimulus étant des modules ESM, ils sont importés dans les pages directement en utilisant un importmap présent dans le template de base, qui contient donc tous les modules réutilisables, et qui peut être surchargé page par page (chaque page ayant alors la responsabilité de réécrire un importmap contenant tous les modules réutilisables en plus de ses modules spécifiques)
Parfois le besoin se fait ressentir d’un composant web (HTML/CSS/JS fonctionnant ensemble et utilisable à plusieurs endroits de l’application). Dans ce cas, les éléments sont rangés de la manière suivante :
- Les templates dans
app_django/templates/app_django/components - Les CSS et JS dans
app_django/static/app_django/components
L’app Django ui contient une page de présentation des composants web réutilisables, qu’il est conseillé d’utiliser pour présenter le composant dans ses différentes variantes et ainsi le documenter.
Dans un souci de simplicité et de maîtrise des coûts, les éléments d’infrastructure nécessaires à ce produit sont minimalistes :
- Un conteneur exécutant le service
web(doublé en production pour éviter les coupures de service en cas de surcharge momentanée) :- Le logiciel de serveur d’applications gunicorn est positionné devant l’interface WSGI de Django
- La brique logicielle whitenoise se charge de servir les fichiers statiques (JS/CSS/images, mais aussi
robots.txtetfavicon.ico) du projet Django sans hébergement externe
- Un conteneur exécutant le service
worker - Une base de données PostgreSQL
Le déploiement s’effectue entièrement via le buildpack Python de Scalingo configuré pour Django (voir la doc).
Ce produit est déployé en trois versions :
devc’est l’intégration continue de la branchemain, et parfois le bon endroit pour tester un truc vite fait en cas de doute sur l’environnement localinternec’est pour montrer des choses à l’équipe Aides Agriprodse passe de présentation
Les fichiers JS et CSS ne sont ni compilés, ni transpilés, ni minifiés, ni "uglyfiés" :
- Les fichiers tierces-parties sont vendorés (listés dans
package.jsonpuis copiés dans ce dépôt, dans le répertoirestatic/vendorgrâce à ce Github workflow) ; de cette manière :- Les dépendances sont clairement identifiées et centralisées
- Les dépendances peuvent être mises à jour automatiquement par, par exemple, Dependabot
- Aucune étape de construction spécifique n’est nécessaire
- Les fichiers CSS et JS sont chargés depuis le domaine de l’application, ce qui facilite la mise en œuvre d’une CSP robuste
- Tous les fichiers statiques (ceux présents dans le répertoire
static/de chaque app Django, tierce-partie ou spécifique) sont collectés par la commandecollectstaticde Django qui les place dans le répertoirestaticfiles/, qui est ensuite servi parwhitenoise
La présence des outils suivants est requise sur le système :
- uv pour gérer les dépendances Python
- just pour exécuter les commandes disponibles en profitant de l’environnement virtuel de uv et des variables d’environnement présentes dans le fichier
.env - Docker pour avoir un PostgreSQL indépendant du système
- Installer les dépendances Python
just installPour démarrer, très peu de variables d’environnement sont requises :
PYTHONUNBUFFERED=1
DJANGO_SETTINGS_MODULE=conf.settings.devel
ENVIRONMENT={TON_PRÉNOM}
SECRET_KEY={CE_QUE_TU_VEUX}- Lancer PostgreSQL
docker compose up- S’assurer que le schéma de la base est à jour
just migrate- Lancer le site
just runserver- Peupler la configuration DSFR
just manage loaddump dsfr_config
- Créer un super-utilisateur
just manage createsuperuser
- Commande générique pour accéder au manage.py de Django avec les bonnes variables d’environnement et l’environnement virtuel uv activé :
just manage COMMAND
- Les raccourcis suivants sont disponibles :
just runserverjust shelljust makemigrationsjust migratejust test
just scalingo-ssh {ENVIRONNEMENT}permet d’atterrir en SSH sur un nouveau conteneur clone du conteneurwebjust scalingo-django-shell {ENVIRONNEMENT}permet d’atterrir en shell Django sur un nouveau conteneur clone du conteneurwebjust scalingo-django-command {ENVIRONNEMENT} {COMMANDE}permet de lancer une commande Django sur un nouveau conteneur clone du conteneurweb
- La branche
mainest bloquée, chaque évolution doit se faire sur une branche et faire l’objet d’une PR - Chaque PR doit porter dans sa description un lien vers la raison pour laquelle l’évolution du code est nécessaire (Notion en cas de nouvelle fonctionnalité ou feedback, Sentry en cas de crash applicatif)
- Chaque évolution de code doit venir avec ses tests ; les tests fonctionnels sont à privilégier, et l’approche TDD est encouragée en cas de correction de bug
- La branche
mainest déployée sur l’environnementdevà chaque merge - Les autres environnements font l’objet de déploiements déclenchés manuellement via l’interface de Scalingo
This project is tested with BrowserStack.
