151 lines
4.6 KiB
Markdown
151 lines
4.6 KiB
Markdown
# ARCHITECTURE — Sargasse-Sentry
|
||
|
||
## Stack technique
|
||
|
||
| Couche | Technologie | Rôle |
|
||
|---|---|---|
|
||
| Backend | Symfony (PHP) | API JSON, crons, pipeline |
|
||
| Frontend | React SPA | Interface utilisateur |
|
||
| Maps | MapLibre GL JS + react-map-gl | Rendu cartographique |
|
||
| Base de données | PostgreSQL + PostGIS | Données géospatiales |
|
||
| Vector tiles | Tippecanoe (génération) | Tiles statiques pré-générées |
|
||
| Cache | Redis | Scores, résultats API |
|
||
| Reverse proxy | Traefik | Routage multi-tenant, SSL |
|
||
| Runtime PHP | FrankenPHP | Remplace php-fpm + nginx |
|
||
| Conteneurisation | Docker | Isolation, déploiement |
|
||
|
||
---
|
||
|
||
## Infrastructure
|
||
|
||
### Hébergement
|
||
|
||
VPS personnel, architecture **multi-tenant Docker + Traefik + FrankenPHP** (configuration existante partagée entre projets).
|
||
|
||
```
|
||
Internet
|
||
└── Traefik (reverse proxy, SSL Let's Encrypt)
|
||
├── sargasse-sentry.tld → container Symfony/FrankenPHP
|
||
├── [autres projets]
|
||
└── ...
|
||
|
||
Containers Sargasse-Sentry :
|
||
├── frankenphp (Symfony API + worker cron)
|
||
├── postgres (PostgreSQL + PostGIS)
|
||
└── redis (cache)
|
||
```
|
||
|
||
### CDN (optionnel, sans coût)
|
||
|
||
**Cloudflare free tier** peut être activé devant Traefik pour mettre en cache les vector tiles statiques et les réponses HTTP publiques. Aucun coût.
|
||
|
||
---
|
||
|
||
## Architecture applicative
|
||
|
||
### Backend — Symfony API
|
||
|
||
Symfony n'expose que du JSON (pas de Twig). Deux responsabilités :
|
||
|
||
1. **API REST** — endpoints consommés par le frontend React
|
||
2. **Pipeline** — crons + workers de traitement satellite
|
||
|
||
### Frontend — React SPA
|
||
|
||
Application React statique servie par FrankenPHP (ou Traefik directement). Consomme l'API Symfony et affiche les vector tiles via MapLibre GL JS.
|
||
|
||
---
|
||
|
||
## API Endpoints
|
||
|
||
### Spots & scores
|
||
|
||
```
|
||
GET /api/spots Liste des CoastalPoints
|
||
GET /api/spots/{id} Détail d'un CoastalPoint
|
||
GET /api/spots/{id}/score ImpactScore courant + horizons
|
||
GET /api/spots/{id}/score?at={datetime} Score à un instant donné
|
||
```
|
||
|
||
### Observations & prédictions
|
||
|
||
```
|
||
GET /api/observations?bbox={bbox}&date={date} Observations dans une zone
|
||
GET /api/observations/{id} Détail observation
|
||
GET /api/forecasts?observationId={id} Prédictions d'une observation
|
||
GET /api/forecasts?bbox={bbox}&horizon={h} Prédictions par zone + horizon
|
||
```
|
||
|
||
### Feedback
|
||
|
||
```
|
||
POST /api/feedback Soumettre un UserFeedback anonyme
|
||
```
|
||
|
||
### Tiles (statiques, hors API)
|
||
|
||
```
|
||
GET /tiles/observations/{z}/{x}/{y}.pbf
|
||
GET /tiles/forecasts/{horizon}/{z}/{x}/{y}.pbf
|
||
```
|
||
|
||
---
|
||
|
||
## Vector Tiles
|
||
|
||
### Stratégie : Tippecanoe + tiles statiques
|
||
|
||
- Les observations et prédictions sont converties en tiles `.pbf` après chaque ingestion (via Tippecanoe)
|
||
- Les tiles sont stockées sur le filesystem du VPS et servies statiquement
|
||
- Pas de rendu dynamique à la volée (Tegola écarté — complexité non justifiée au MVP)
|
||
- Cloudflare free tier peut mettre ces tiles en cache si activé
|
||
|
||
### Interdits
|
||
|
||
- GeoJSON brut exposé en production sur des géométries complexes
|
||
|
||
---
|
||
|
||
## Caching
|
||
|
||
| Données | Stratégie | TTL suggéré |
|
||
|---|---|---|
|
||
| Scores par spot | Redis | 3h (durée du cycle d'ingestion) |
|
||
| Résultats API observations | Redis | 3h |
|
||
| Vector tiles statiques | HTTP Cache + Cloudflare | Long (invalidation à chaque ingestion) |
|
||
| Endpoints publics | HTTP Cache | 15–30 min |
|
||
|
||
Règle : **1 requête = 1 zone + 1 timestamp**, pas de recalcul à la volée.
|
||
|
||
---
|
||
|
||
## Sécurité
|
||
|
||
- Rate limiting sur tous les endpoints publics (Symfony RateLimiter)
|
||
- Aucune donnée personnelle collectée (UserFeedback = fingerprint anonyme)
|
||
- Retry automatique pipeline avec backoff
|
||
- Logs structurés sur chaque DataIngestionJob
|
||
- Secrets (clés API Sentinel Hub, NOAA) via variables d'environnement Docker
|
||
|
||
---
|
||
|
||
## Schéma de flux de données
|
||
|
||
```
|
||
Sentinel Hub API
|
||
└── Cron Symfony (3h)
|
||
└── DataIngestionJob
|
||
├── Calcul AFAI → SargassumObservation
|
||
│ └── Tippecanoe → tiles statiques /tiles/observations/
|
||
└── Simulation dérive → SargassumForecast (×4 horizons)
|
||
├── Calcul ImpactScore par CoastalPoint → Redis
|
||
└── Tippecanoe → tiles statiques /tiles/forecasts/
|
||
|
||
NOAA GRIB API
|
||
└── (consommé pendant la simulation de dérive)
|
||
|
||
React SPA
|
||
├── MapLibre GL JS → /tiles/...pbf
|
||
└── Symfony API → /api/spots/{id}/score
|
||
```
|