Phase 2 : dérive, ImpactScore, slider temporel

Backend :
- OpenMeteoClient : vent horaire 72h (gratuit, sans clé)
- DriftSimulationService : échantillonnage ST_GeneratePoints,
  déplacement itératif Stokes 3%, reconstruction ST_ConcaveHull,
  4 horizons H+6/12/24/48, confiance décroissante
- ImpactScoreService : score 4 composantes (distance/densité/
  vitesse/tendance), cache Redis TTL 3h, invalidation à chaque calcul
- ComputeForecastsCommand : traite les observations sans forecast
- SpotScoreController : score courant + horizons depuis forecasts

Frontend :
- TimelineSlider : navigation Now/+6h/+12h/+24h/+48h
- SargassesMap : couche observations (orange) vs forecasts (violet)
  rechargée à chaque changement d'étape
- SpotPanel : affichage score par horizon actif + indicateur confiance
- Build → backend/public/spa/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gwadaking
2026-04-01 03:23:21 -04:00
parent 0c1deb93cb
commit 94bb6f5e8c
18 changed files with 983 additions and 186 deletions

View File

@@ -1,19 +1,26 @@
import { useState } from 'react';
import SargassesMap from './components/Map/SargassesMap';
import SpotPanel from './components/SpotPanel/SpotPanel';
import TimelineSlider from './components/Timeline/TimelineSlider';
import './App.css';
export default function App() {
const [selectedSpot, setSelectedSpot] = useState(null);
const [activeStep, setActiveStep] = useState('now');
return (
<div className="app">
<TimelineSlider activeStep={activeStep} onChange={setActiveStep} />
<SargassesMap
onSpotSelect={setSelectedSpot}
selectedSpotId={selectedSpot?.id}
activeStep={activeStep}
/>
<SpotPanel
spot={selectedSpot}
activeStep={activeStep}
onClose={() => setSelectedSpot(null)}
/>
</div>