Files
radarsargasses/docs/roadmap.md
Gwadaking 9712cb54db feat: phase A — backup B2, healthcheck /api/status, vector tiles Tippecanoe
- A1: scripts/backup-postgres.sh — pg_dump quotidien compressé → Backblaze B2 (rclone), rétention 30j
- A2: StatusController retourne HTTP 503 + healthy/alertReason si dernière observation > 6h
- A4: Dockerfile installe tippecanoe, GenerateTilesCommand génère 5 tilesets (obs + h6/12/24/48), Caddyfile sert /tiles/* sans fallback SPA, SargassesMap.jsx passe en sources vector tiles statiques
- chore: backend/public/assets/ ajouté au .gitignore (build artifacts)
- chore: setup vitest frontend + ImpactScoreServiceTest (session précédente)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 03:40:32 -04:00

8.2 KiB

ROADMAP — Sargasse-Sentry

Checklist permanente d'avancement projet. Mettre à jour au fil des implémentations.


Légende

  • À faire
  • [~] En cours
  • Terminé

Phase 0 — Fondations

Infrastructure & environnement

  • Initialisation dépôt Git (bare repo VPS + hook post-receive)
  • Configuration Docker (FrankenPHP + PostgreSQL/PostGIS + Redis)
  • Configuration Traefik (domaine radarsargasses971.com, SSL Let's Encrypt)
  • Variables d'environnement (.env + clés VAPID documentées)
  • Initialisation projet Symfony (symfony new backend)
  • Installation API Platform
  • Initialisation projet React (npm create vite@latest frontend)
  • Configuration MapLibre GL JS + react-map-gl

Base de données

  • Extension PostGIS activée (dans la migration)
  • Migration : SargassumObservation
  • Migration : SargassumForecast
  • Migration : DataIngestionJob
  • Migration : CoastalPoint
  • Migration : ImpactScore
  • Migration : UserFeedback
  • Migration : PushSubscription
  • Index spatiaux (GIST) + index BTREE définis

Phase 1 — MVP (Antilles, observations uniquement)

Pipeline d'ingestion

  • Cron VPS (docker exec toutes les 3h) → app:ingest-sentinel
  • Appel API Sentinel Hub (bandes B04, B08, B11 via evalscript)
  • Création DataIngestionJob (pending → success/failed)
  • Retry automatique + logging erreurs
  • Filtrage nuages via Catalog API (seuil 60%, configurable)
  • Calcul AFAI dans evalscript Sentinel Hub (formule complète)
  • Rasterisation → raster UINT8 binaire (evalscript cloud-side)
  • Vectorisation GDAL (gdal_polygonize.py) + simplification PostGIS
  • Persistance SargassumObservation
  • Génération vector tiles (Tippecanoe → .pbf) — différé Phase 2

API Backend

  • GET /api/spots — liste CoastalPoints (API Platform)
  • GET /api/spots/{id} — détail (API Platform)
  • GET /api/spots/{id}/score — score + niveau + trend
  • GET /api/observations?bbox=&date=&source= — PostGIS ST_Intersects
  • GET /api/observations/{id} — détail avec geometry GeoJSON
  • GET /api/forecasts — API Platform
  • POST /api/feedback — feedback anonyme (IP hachée)

Frontend React

  • Carte de base (MapLibre GL JS + fond CARTO dark)
  • Affichage observations GeoJSON (bbox dynamique au mouvement)
  • Marqueurs CoastalPoints avec sélection
  • SpotPanel : Spot Mode complet (score, niveau, distance, trend)
  • Bouton feedback terrain (confirmation/infirmation anonyme)
  • Build Vite → backend/public/ (SPA servie depuis la racine par Caddy)

Données initiales

  • Seed CoastalPoint zone Antilles — 29 points (plages, ports, surf, pêche)

Phase 2 — Dérive & Score

Pipeline — simulation de dérive

  • Vent horaire via Open-Meteo (gratuit, sans clé, JSON)
  • Échantillonnage PostGIS ST_GeneratePoints (30 points internes)
  • Déplacement horaire itératif (modèle Stokes 3% vent)
  • Reconstruction ST_ConcaveHull (PostGIS 3.4)
  • Génération horizons H+6, H+12, H+24, H+48 avec confiance décroissante
  • Persistance SargassumForecast
  • Génération vector tiles prédictions (Tippecanoe) — différé

Calcul ImpactScore

  • Score par CoastalPoint : distance(40) + densité(30) + vitesse(20) + tendance(10)
  • Persistance ImpactScore
  • Mise en cache Redis (TTL 3h) via ImpactScoreService

API Backend

  • GET /api/spots/{id}/score — score courant + horizons H+6/12/24/48
  • GET /api/spots/{id}/score?at={datetime} — score à un instant
  • GET /api/forecasts?bbox=&horizon= — prédictions par zone + horizon (API Platform)

Frontend React

  • Slider temporel (Now → +6h → +12h → +24h → +48h)
  • Spot Mode complet par horizon (OK / Risque / Impact + confiance)
  • Mise à jour dynamique polygones + score sur slider
  • Couche forecasts (violet pointillé) vs observations (orange plein)
  • Gradients radiaux densité — différé

Phase 3 — Feedback & Alertes

Boucle d'apprentissage

  • Bouton "Je confirme présence de sargasses"
  • POST /api/feedback — persistance UserFeedback anonyme
  • Intégration feedback dans calcul score (bonus +8 pts si présence confirmée < 6h dans rayon 20 km)

Alertes push

  • Commande app:generate-vapid-keys (génération clés VAPID)
  • GET /api/push/vapid-public-key — clé publique VAPID
  • POST /api/push/subscribe — enregistrement abonnement push
  • DELETE /api/push/subscribe — désinscription
  • PushNotificationService — envoi WebPush VAPID, nettoyage abonnements expirés
  • Déclenchement alertes si score ≥ 70 (HIGH_SCORE_THRESHOLD)
  • Service worker (sw.js) — réception push + ouverture app au clic
  • usePushSubscription hook React — subscribe/unsubscribe lifecycle
  • Bouton "Activer les alertes" dans SpotPanel

Transversal (continu)

  • Rate limiting endpoints publics (api_read 120/min, api_feedback 10/min, api_push 5/min)
  • Fallback Sentinel-2 → Sentinel-3 OLCI (mode auto dans IngestSentinelCommand)
  • Routing SPA corrigé (Caddyfile try_files + build vers backend/public/)
  • Vue mobile (SpotPanel bottom-sheet + TimelineSlider compact)
  • Post-receive hook complet (composer + npm build + migrations + cache + docker up)
  • Monitoring pipeline (alertes si ingestion échoue > N fois)
  • Logs structurés (Monolog JSON handler)
  • Configuration Cloudflare free tier (cache tiles statiques)
  • Tests fonctionnels pipeline (ingestion → score)

Phase A — Blindage opérationnel (priorité absolue)

Pré-requis à tout le reste. Un crash VPS sans backup = perte totale des données.

  • A1 Backup PostgreSQL automatisé — pg_dump quotidien compressé vers stockage externe (Backblaze B2), rétention 30 jours
  • A2 Monitoring pipeline — healthcheck externe (UptimeRobot) sur /api/status, alerte email si ingestion absente > 6h
  • A3 CI/CD via Gitea Actions — phpstan + phpunit + vitest bloquants sur chaque push ; deploy déclenché par action SSH uniquement si CI (Gitea installé sur VPS, runner à configurer)
  • A4 Vector tiles Tippecanoe — génération .pbf après chaque ingestion, served statiquement par Caddy ; remplacement des sources GeoJSON par sources vector côté frontend

Phase B — Crédibilité produit

Transforme le prototype en produit présentable à un partenaire.

  • B1 Analytics — Plausible (self-hosted sur VPS) ou Umami ; métriques sessions, pages vues, îles consultées
  • B2 Onboarding — modale premier lancement : légende polygones orange/violet, explication score, CTA "Sélectionnez un point côtier"
  • B3 Légende interactive carte — compléter le composant Legend existant (observations vs prédictions, niveaux de risque)
  • B4 CSP header — Content-Security-Policy adapté MapLibre GL JS + Web Workers + blob URLs
  • B5 HSTS — Strict-Transport-Security dans le Caddyfile

Phase C — Valeur ajoutée produit

  • C1 Vue historique — date picker sur le slider temporel, chargement des observations/scores passés (données déjà en base)
  • C2 Tests d'intégration pipeline — scénario ingestion GeoJSON synthétique → dérive → score ; couvre le type de bug ST_Distance/detected_at
  • C3 TypeScript frontend — activation progressive sur les nouveaux fichiers, typage des interfaces API (score, horizons, patches) en priorité
  • C4 Refactoring SargassesMap.jsx — découpage du composant monolithique (320 lignes) en sous-composants testables

Phase D — Expansion & B2B

À démarrer seulement après A entièrement livré et B partiellement livré.

  • D1 Documenter le coût marginal d'ajout d'une zone — temps + quota Sentinel Hub + coût stockage tiles, pour chiffrer l'expansion (Yucatán, Brésil, Açores…)
  • D2 API publique documentée avec clé — endpoint /api/v1/score + quota + documentation OpenAPI ; ouvre la porte au B2B (offices de tourisme, collectivités, assureurs maritimes)
  • D3 Expansion géographique — première zone hors Caraïbes (candidat : côtes du Yucatán, Mexico)