Commit graph

2 commits

Author SHA1 Message Date
7b53d47d71 feat: intégration SQL sur PostgreSQL réel + boutons de crawl conscients du crawler
Some checks are pending
CI / javascript (push) Waiting to run
CI / python (push) Waiting to run
CI / mutation (push) Waiting to run
1. Suite d'intégration SQL (npm run test:integration:full)

Ferme le dernier angle mort : la SÉMANTIQUE du SQL. Le parseur de grammaire ne
voyait pas un nom de colonne inexistant, un type incompatible ou une fonction
PostGIS mal appelée — soit exactement la classe de bugs qui n'apparaissait
qu'en production.

Technique : chaque requête émise par l'application passe par `PREPARE`.
Postgres l'analyse et la planifie entièrement — colonnes, types, opérateurs
jsonb, fonctions PostGIS — SANS l'exécuter ni nécessiter de données. Rapide, et
ça couvre aussi les requêtes que le parseur JS ne sait pas lire :
jsonb_build_object, `jsonb - text[]`, `raw ? 'clé'`, make_interval, l'opérateur
spatial && et l'agrégation en grille des clusters.

Les migrations réelles sont appliquées dans l'ordre réel : une migration
invalide échoue ici, plus au redémarrage du conteneur en production.

54 tests. Exige Docker, donc HORS de `check` et du hook pre-push — la boucle
de développement reste à 6 s. Base jetable en tmpfs (fsync off).

Deux témoins vérifient que le détecteur n'est pas inopérant : une colonne
inexistante et un type incompatible doivent être rejetés.

2. Les boutons de crawl ne mentent plus

La production ne déploie pas le service crawler (docker-compose.yml ne le
contient pas). Les boutons « Crawl incrémental », « Enrichir » et « Crawl
complet » y créaient des demandes que personne ne consommait, avec un libellé
promettant une exécution « sous ~1 min ».

Ils s'appuient désormais sur le battement de cœur : pas de crawler vivant,
boutons désactivés et raison affichée. « Alimenter le géocodage » reste actif,
puisqu'il est traité par le geocoder.

Je n'ai PAS ajouté le crawler au compose de production : ce serait déclencher
du crawl depuis la prod, décision qui n'est pas la mienne.

Régression évitée au passage : re-rendre le bloc de traitements effaçait le
message de retour (« Demande #77 enregistrée »), puisque loadPilotage() est
rappelé après un clic réussi. L'état des boutons est donc mis à jour sans
reconstruire le DOM. Détecté par un test existant.

Correctif : la suite d'intégration était happée par le glob de vitest.config.js
et allongeait `check` de 6 à 22 s en exigeant Docker.

Tests : 580 JS + 54 intégration, 63 Python, 89 Playwright

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 20:53:35 +02:00
60074fb015 feat(qualité): outillage de test complet, CI locale, annulation réelle des runs
Some checks are pending
CI / javascript (push) Waiting to run
CI / python (push) Waiting to run
CI / mutation (push) Waiting to run
Le dépôt n'avait aucun test, aucun linter, aucune vérification de types.

Outillage
- ESLint 9 (flat config) sur api + les deux frontends, Ruff sur le Python
- tsc --checkJs sur l'API (pas de TypeScript, juste la vérification)
- Vitest : 401 tests JS ; pytest : 43 tests Python
- Tests de mutation (Stryker), deux profils : logique pure et API complète
- Hook pre-push `npm run check` (~17 s) — le déploiement Coolify est sur webhook,
  c'est donc la seule porte de qualité avant la mise en ligne
- Workflow Forgejo Actions prêt (inerte tant qu'aucun runner n'est enregistré)

Sécurité
- Injection SQL authentifiée dans resolve-conflict : `field` était interpolé
  dans le SET sans allowlist
- timingSafeEqual levait sur un jeton multi-octets (500 au lieu de 401)
- setErrorHandler écrasait tous les 4xx en 500
- .env.example : ADMIN_JWT_SECRET et ADMIN_SEED_* n'étaient documentés nulle part
  alors que leur absence casse toute connexion admin

Annulation réelle des crawl_run (migration 014)
- L'API posait status='error' sans que le crawler en sache rien : le process
  continuait, et son UPDATE final ne matchait plus (run réussi affiché en erreur)
- Protocole coopératif : drapeau cancel_requested lu à chaque lot, le crawler
  écrit lui-même status='cancelled'

Cohérence géographique (migration 014)
- Le trigger 013 supprimait les band_locations sans purger le point dénormalisé
- L'édition admin de lat/lon n'atteignait jamais band_locations : la carte
  ignorait la correction. Override step_order = -1, dans une transaction

Corrections
- limit/offset NaN → 500 au lieu de 400
- OPTIONS sans `return reply` (Fastify poursuivait le cycle de vie)
- listen() sans catch, cast ::text en dur sur les colonnes numériques
- /admin/api/logs ne renvoyait pas sa pagination
- a11y : sélecteur de langue annoncé comme liste vide (role=option manquant)

Nettoyage
- apps/web/quizz-site supprimé (sans rapport avec le projet)
- Code mort : openModal(), LANG_NAMES, double import, variables inutilisées
- .dockerignore ajoutés ; node_modules racine n'était pas gitignoré

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-18 10:05:40 +02:00