Commit Graph

9 Commits

Author SHA1 Message Date
Gwadaking
e0ed71535e fix: Tippecanoe compilé depuis source (multi-stage build, absent de bookworm)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 03:44:00 -04:00
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
Gwadaking
cda9a7a8ff security: appliquer les findings de l'audit OWASP (H1→B3)
H1 — trusted_proxies RFC-1918 dans framework.yaml : rate limiting
     opérationnel derrière Traefik (IP client réelle, pas IP Traefik)

H2 — En-têtes HTTP dans Caddyfile : X-Frame-Options DENY,
     X-Content-Type-Options nosniff, Referrer-Policy, Permissions-Policy,
     suppression header Server

H3 — API Platform docs désactivés en when@prod (Swagger UI, ReDoc)

M1 — Rate limiter sur DELETE /api/push/subscribe (manquant)
M2 — Validation FILTER_VALIDATE_URL sur endpoint push avant stockage
M3 — APP_ENV=prod dans backend/.env (était dev — risque si .env.local absent)
M4 — Limite 4096 octets sur le body JSON (FeedbackController + PushController)
M5 — Service Worker : open redirect corrigé (targetUrl validé contre l'origine)

B1 — robots.txt créé (bloque /api/ et /bundles/)
B3 — --time-limit=3600 sur les workers Messenger (rotation + libération mémoire)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 00:49:15 -04:00
Gwadaking
48e6e5060c feat: ingestion automatique toutes les 6h + indicateur fraîcheur UI
- Symfony Scheduler (MainSchedule) : cron 0,6,12,18h UTC
- IngestionScheduleMessage + IngestionScheduleHandler : pipeline complet
  ingestion → forecasts → impact scores pour toutes les zones Antilles
- messenger.yaml : transport scheduler_main + async Redis (rs971_async)
- entrypoint.sh : 2 workers en background (scheduler_main + async)
- GET /api/status : date/heure de la dernière observation
- SargassesMap : badge "Données du JJ/MM à HH:MM" en bas à gauche

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:31:58 -04:00
Gwadaking
da7d62fa6a refactor: simplifier Dockerfile et hook — code via volume, pas image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:13:09 -04:00
Gwadaking
7ecb71599d fix: move cache:warmup to runtime entrypoint, fix POSTGRES_PASSWORD default
cache:warmup at build time fails because .env.local is not available in the
image (gitignored). Moved to entrypoint.sh which runs after volume mounts.
Also added default value for POSTGRES_PASSWORD in docker-compose.yml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 17:44:05 -04:00
Gwadaking
2cef3725e9 feat: Phase 3 complete — push alerts, feedback scoring, S3 fallback, SPA routing, mobile CSS
- ImpactScoreService: implement getFeedbackBonus() (ST_Distance query on UserFeedback within 20km/6h)
- ImpactScoreService: trigger PushNotificationService when score >= 70
- PushNotificationService: send VAPID WebPush to spot subscribers, clean expired subs
- PushController: GET vapid-public-key, POST/DELETE subscribe with rate limiting
- SentinelHubClient: add optional $collection param, add Sentinel-3 OLCI FAI evalscript (MCI)
- IngestionService: add $collection param + HighCloudCoverageException for fallback logic
- IngestionService: add ingestWithFallback() — tries S2, falls back to S3 on high cloud
- IngestSentinelCommand: --source=auto (default) triggers ingestWithFallback
- FeedbackController: rate limiting via apiFeedbackLimiter
- Migration: push_subscription table
- rate_limiter.yaml: api_read(120/min), api_feedback(10/min), api_push(5/min)
- sw.js: service worker handling push events + notificationclick
- usePushSubscription hook: subscribe/unsubscribe lifecycle with VAPID
- SpotPanel: PushButton component integrated
- SpotPanel.css + TimelineSlider.css: mobile responsive (bottom-sheet on small screens)
- Caddyfile: SPA served at / with try_files fallback, sw.js served from root scope
- vite.config.js: build outDir → backend/public (not /spa)
- deploy/post-receive.sh: full deploy script (composer, npm build, migrations, cache, docker up)
- docs/roadmap.md: all Phase 3 + transversal items marked done

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 03:43:56 -04:00
Gwadaking
bf64340525 Phase 1 : pipeline d'ingestion Sentinel-2
- SentinelHubClient : auth OAuth2, Catalog API (cloud coverage),
  Process API avec evalscript AFAI binaire (UINT8, cloud-side)
- IngestionService : orchestration complète — job tracking,
  rejet nuages, téléchargement GeoTIFF, polygonize GDAL,
  simplification PostGIS, persistance SargassumObservation
- IngestSentinelCommand : 5 zones Antilles configurées,
  options --date et --zone, appelable via cron docker exec
- Dockerfile : ajout gdal-bin + python3-gdal
- Correction entity : paramètre immutable retiré de #[ORM\Column]

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 02:45:12 -04:00
Gwadaking
f685c96ed6 Phase 0 : scaffolding complet
- Structure monorepo (backend Symfony, frontend React/Vite)
- Docker : FrankenPHP + PostgreSQL/PostGIS + Redis + Traefik labels
- Caddyfile, Dockerfile, .env.example, .gitignore
- MapLibre GL JS + react-map-gl installés
- Roadmap mise à jour

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 02:23:10 -04:00