Fix 20+ defects found by real Docker/PostgreSQL deployment

Première exécution réelle de la stack (build des images, PostgreSQL 16,
parcours fonctionnels en HTTP) : 28 tables, 105 index, extension pg_trgm,
et 181 assertions rejouées après correction.

Santé : filtres enum invalides renvoyaient 500 au lieu d'une erreur
française ; plan_line s'arrêtait à la fin de la fenêtre du graphique au
lieu de la date d'atteinte de l'objectif ; deficit_target_kcal était
recalculé après le plancher calorique ; « dernière pesée » affichait deux
valeurs différentes selon l'endpoint ; objectif protéines absent.

Vape : durée de vie moyenne des résistances incluait la résistance en
cours ; archiver la recette active la laissait active ; coût théorique
inventé avant la date d'arrêt ; économies projetées dans le futur ;
€/ml arrondi à 2 décimales écrasait le modèle de coût DIY.

Finances : le sankey compensait crédits et débits non catégorisés ;
rows_total excluait les lignes filtrées, faussant l'arithmétique du
rapport d'import.

Socle : les erreurs HTTP du framework fuitaient en anglais dans
l'enveloppe française ; nginx renvoyait sa page 413 HTML au lieu du JSON
français ; fins de ligne normalisées en LF.

348 tests pytest (+7), ruff, tsc et vite build au vert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-14 11:40:05 +02:00
co-authored by Claude Opus 5
parent d32436db4c
commit fa3db7ff22
20 changed files with 408 additions and 78 deletions
+10
View File
@@ -8,6 +8,16 @@ server {
root /usr/share/nginx/html;
index index.html;
# Above client_max_body_size nginx answers on its own, with an English HTML
# page. Only files bigger than 25 MiB get here (between the API limit and
# 25 MiB the API answers first, in French): keep the §8.3 error envelope.
error_page 413 = @too_large;
location @too_large {
default_type application/json;
charset utf-8;
return 413 '{"error":{"code":"payload_too_large","message":"Fichier trop volumineux (limite : 20 Mio).","details":{}}}';
}
# Docker's embedded DNS. Without a resolver nginx resolves `api` once, at
# config load, and caches that IP forever: `compose restart api` (or any
# recreate) hands out a new IP and every /api/ call would 502 until nginx