Développement

Installer les dépendances de documentation

Depuis la racine du projet :

pip install -r backend/requirements.txt
pip install -r docs/requirements.txt

Construire la documentation HTML

Sous Windows :

.\docs\make.bat html

Si sphinx-build n’est pas disponible dans le PATH mais que l’environnement virtuel contient bien les dépendances de documentation :

$env:DEBUG="True"
$env:SECRET_KEY="docs-local-secret-key-not-for-production"
.\.venv\Scripts\python.exe -m sphinx -b html docs\source docs\build\html

Sous Linux/macOS :

make -C docs html

La sortie HTML est générée dans docs/build/html/.

Lancer la stack locale

La stack Docker démarre le backend, le frontend, le kiosque Raspberry, le broker MQTT, Redis, TimescaleDB/PostgreSQL, Celery, Grafana et le reverse proxy Nginx :

docker compose up -d --build

Le parcours local recommandé pour une exécution proche production passe par Nginx :

https://localhost/          -> frontend
https://localhost/api/      -> API Django
https://localhost/admin/    -> admin Django
https://localhost/grafana/d/station-overview/station-vue-globale-supervision?orgId=1&from=now-6h&to=now&refresh=10s
                      -> dashboard Grafana de supervision
https://localhost/kiosk/    -> kiosque Raspberry

Le reverse proxy redirige http://localhost vers https://localhost. Le certificat fourni est auto-signé et réservé au développement local : le navigateur peut donc afficher un avertissement lors du premier accès. Les ports directs 8000, 5173, 3000 et 9000 restent exposés pour le diagnostic pendant le développement.

Si le fichier .env local a été créé avant l’activation de HTTPS, reprendre les valeurs de .env.example pour FRONTEND_BASE_URL, CORS_ALLOWED_ORIGINS, JWT_REFRESH_COOKIE_SECURE, SESSION_COOKIE_SECURE et CSRF_COOKIE_SECURE.

Accès depuis un téléphone sur le Wi-Fi local

Pour tester la session mobile, le téléphone et le PC doivent être sur le même réseau Wi-Fi. Le téléphone ne peut pas utiliser localhost pour joindre le PC : il doit ouvrir l’adresse IP Wi-Fi du PC, par exemple http://10.x.x.x:5173 en accès direct Vite ou https://10.x.x.x via Nginx si le certificat de développement est accepté.

Le script suivant met à jour les variables locales liées à l’adresse Wi-Fi au démarrage du poste de développement :

.\scripts\update-local-ip.ps1

Après changement de réseau, relancer ce script puis redémarrer les services qui lisent .env. Le QR de session mobile affiché par le kiosque doit contenir une URL joignable depuis le téléphone, pas une URL en localhost.

Commandes Docker courantes

Démarrer ou reconstruire la stack :

docker compose up -d --build
docker compose up -d

Consulter l’état et les logs :

docker compose ps
docker compose ps -a
docker compose logs --tail=100 backend
docker compose logs --tail=100 frontend
docker compose logs --tail=100 mqtt-bridge
docker compose logs --tail=100 mqtt
docker compose logs --tail=100 grafana

Relancer ou recréer un service sans supprimer les volumes :

docker compose restart backend
docker compose restart mqtt-bridge
docker compose up -d --force-recreate backend
docker compose up -d --force-recreate mqtt-bridge

Arrêter la stack en conservant les données :

docker compose down

Lancer le simulateur local de télémétrie :

docker compose up -d mqtt
docker compose --profile simulation run --rm mqtt-simulator

Le simulateur est lancé en conteneur éphémère. À l’arrêt, Docker supprime le conteneur et ne conserve pas de référence vers un ancien réseau Compose après un rebuild.

Si Docker signale encore network ... not found pour un ancien conteneur arrêté, supprimer uniquement le simulateur puis relancer la commande éphémère :

docker compose rm -sf mqtt-simulator
docker compose up -d mqtt
docker compose --profile simulation run --rm mqtt-simulator

Vérifier les réseaux attachés aux conteneurs :

docker network ls
docker inspect mqtt_simulator --format '{{json .NetworkSettings.Networks}}'
docker inspect mqtt_broker --format '{{json .NetworkSettings.Networks}}'

Vérifier Nginx et la messagerie IoT

Valider la configuration Docker Compose :

docker compose config --quiet

Valider la syntaxe du reverse proxy :

docker compose run --rm --no-deps reverse-proxy nginx -t

Vérifier la terminaison HTTPS locale :

curl -k https://localhost/

Envoyer une commande d’emplacement via le Raspberry :

curl -X POST http://localhost:9000/mqtt/command \
  -H "Content-Type: application/json" \
  -d '{"slot_id":"slot1","action":"START","session_id":"demo"}'

Tester le flux RFID local sans lecteur physique :

curl -X POST http://localhost:9000/rfid/scan \
  -H "Content-Type: application/json" \
  -d '{"uid":"04A3BC89F2"}'

Le kiosque interroge /rfid/scan et déclenche automatiquement le parcours RFID si l’écran d’accueil, l’écran RFID ou l’écran d’association badge est actif. /rfid/status expose le backend lecteur utilisé. Par défaut, RFID_READER_BACKEND=manual laisse les tests passer par l’endpoint local. Sur Raspberry, le lecteur cible ACR122U s’utilise avec RFID_READER_BACKEND=acr122u après installation de pyscard et du service PC/SC du système. RFID_READER_BACKEND=stdin reste disponible pour un lecteur configuré comme clavier série, et RFID_READER_BACKEND=nfcpy peut être utilisé avec un autre lecteur NFC compatible après installation optionnelle de nfcpy.

Écouter les télémétries reçues par Mosquitto :

docker compose exec mqtt mosquitto_sub -h localhost -t 'station/#' -v -C 5 -W 10

Publier une télémétrie de test :

docker compose exec mqtt mosquitto_pub -h localhost -t 'station/slot1/telemetry' -m '{"state":"charging","current":1.2,"voltage":12.0,"temperature":32.5,"humidity":45,"door":true,"cable":true}'

Vérifier l’accès PostgreSQL depuis le conteneur db :

docker compose exec db sh -lc 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "select now();"'

Le firmware ESP32 publie sa télémétrie sur station/<slot_id>/telemetry et écoute les commandes sur station/<slot_id>/cmd.

Ce qui est automatique

La référence backend est alimentée par Sphinx autodoc à partir des docstrings des modules Python, et le schéma OpenAPI est généré par drf-spectacular à partir des vues DRF et des serializers.

Les pages narratives, comme architecture.rst ou les notes de flux métier, ne sont pas réécrites automatiquement : elles doivent être maintenues dans le dépôt quand le comportement produit change.

Vérifier le schéma API

docker compose exec backend python manage.py spectacular --validate

Vérifier la configuration de production

Avant une mise en production, lancer le contrôle Django avec des variables réalistes. DEBUG doit être désactivé, SECRET_KEY doit être long et aléatoire, et ALLOWED_HOSTS doit contenir les domaines réels.

$env:DEBUG="False"
$env:SECRET_KEY="<secret-long-et-aleatoire>"
$env:ALLOWED_HOSTS="example.com"
.\.venv\Scripts\python.exe backend\manage.py check --deploy

Les cookies de session, CSRF et refresh JWT doivent être marqués Secure en production. SECURE_HSTS_SECONDS peut être activé après validation du HTTPS; SECURE_HSTS_PRELOAD ne doit être activé que si le domaine est prêt pour la preload list navigateur.

Le projet ajoute aussi des contrôles spécifiques à la station. Les erreurs api.E001 à api.E005 bloquent les secrets de démonstration et les cookies non sécurisés. Les avertissements api.W001 à api.W005 signalent les points à durcir avant exposition réelle : HSTS, ALLOWED_HOSTS, identifiants MQTT, TLS MQTT et mot de passe administrateur Grafana.

Lancer les tests

Les tests pytest sont exécutés automatiquement pendant le build de l’image backend. Si un test échoue, docker compose up -d --build s’arrête avant de lancer les services.

Le workflow GitHub Actions CI relance aussi les tests backend, Ruff, la qualité des docstrings backend, la validation du schéma OpenAPI, les contrôles de déploiement Django, les tests du kiosque Raspberry, la validation frontend avec npm run verify et la génération de la documentation HTML sur chaque push et pull request.

Automatisations DevSecOps

Le dépôt contient aussi :

  • un workflow Documentation Pages pour reconstruire la documentation Sphinx et la publier sur GitHub Pages après chaque merge dans main ;

  • un workflow CodeQL pour analyser le code Python et JavaScript sur push, pull request, exécution manuelle et planification hebdomadaire ;

  • un workflow Generate SBOM and VEX pour produire les SBOM CycloneDX/SPDX, scanner l’image backend avec Grype, publier le SARIF dans GitHub Code Scanning et générer un brouillon OpenVEX si des vulnérabilités sont détectées ;

  • une configuration Dependabot pour proposer des mises à jour hebdomadaires des dépendances GitHub Actions, npm, pip et Docker.

Le workflow CodeQL versionné dans .github/workflows/codeql.yml est une configuration avancée. Le Default setup CodeQL de GitHub doit rester désactivé, sinon GitHub Code Scanning refuse les résultats SARIF produits par le workflow avancé.

Protection de la branche principale

La branche main est protégée côté GitHub. Les changements doivent passer par une pull request dont la branche est à jour et dont les statuts requis sont au vert :

  • Backend tests ;

  • Backend quality ;

  • Raspberry edge tests ;

  • Frontend verify ;

  • Documentation build ;

  • Analyze (python) ;

  • Analyze (javascript-typescript) ;

  • Backend image supply chain reports.

Les conversations de revue doivent être résolues avant fusion. Les force-pushs et suppressions de main sont désactivés, et la règle s’applique aussi aux administrateurs du dépôt. Dependabot crée une branche et une pull request par mise à jour proposée ; les montées de versions majeures doivent être relues avant fusion.

Publication de la documentation HTML

Le dossier docs/build/html est un artefact local ignoré par Git. Il peut être reconstruit sur le poste de développement, mais il ne doit pas être committé.

La publication officielle est assurée par le workflow Documentation Pages : il installe les dépendances de documentation, lance Sphinx puis publie docs/build/html via GitHub Pages à chaque merge dans main. Le workflow peut aussi être lancé manuellement depuis l’onglet Actions.

La documentation publiée est accessible sur :

https://bayhes5.github.io/Station_de_recharge/

Installer les dépendances de développement :

.\.venv\Scripts\python.exe -m pip install -r backend\requirements-dev.txt

Exécuter la suite pytest :

cd backend
..\.venv\Scripts\python.exe -m pytest

Relancer uniquement le build backend et donc les tests :

docker compose build backend

Exécuter les tests avec couverture :

cd backend
..\.venv\Scripts\python.exe -m pytest --cov=api --cov-report=term-missing

La configuration pytest utilise config.test_settings et une base SQLite de test, afin de ne pas dépendre de PostgreSQL pendant les tests unitaires.

Vérifier le frontend

Installer les dépendances frontend puis lancer les validations :

cd frontend
npm ci
npm run check:js
npm run verify

check:js valide la syntaxe des scripts JavaScript avec Node. verify enchaîne cette vérification, le build Vite de production et les tests end-to-end Playwright. Avant le premier lancement local, installer le navigateur de test avec npx playwright install chromium.

Contrôler les docstrings

Le backend configure Ruff et Interrogate dans backend/pyproject.toml. Ruff contrôle la qualité des docstrings existantes, tandis qu’Interrogate mesure les docstrings manquantes. Les docstrings utilisent le style Google, qui est repris par Sphinx grâce à sphinx.ext.napoleon.

Installer les dépendances de développement :

.\.venv\Scripts\python.exe -m pip install -r backend\requirements-dev.txt

Vérifier la qualité Python avec Ruff :

cd backend
..\.venv\Scripts\python.exe -m ruff check .

Mesurer la couverture documentaire :

cd backend
..\.venv\Scripts\python.exe -m interrogate api

Le seuil Interrogate est fixé à 100 : une nouvelle classe ou fonction suivie par l’audit doit donc recevoir une docstring. Ruff active les règles D pour les docstrings publiques, les règles E4/E7/E9/F pour les erreurs Python probables et B pour quelques pièges courants.