Trouver, sur une carte, les endroits au soleil ou à l'ombre — une terrasse de café à 18 h, un banc à l'ombre en août. Les ombres sont calculées à la demande, jamais précalculées : relief, bâtiments et végétation, à n'importe quelle date et n'importe quelle heure.
Ce dépôt porte le moteur, le serveur et l'outillage de données. L'app iOS et le site web vivent dans leurs propres dépôts (voir plus bas).
Vision produit, décisions d'architecture et historique des choix : AGENTS.md. Ce README-ci décrit l'agencement du dépôt et ce qui se déploie.
Le serveur est la vérité soleil/ombre : il assemble une DSM (terrain +
bâtiments + canopée), lance le ray marching et répond « ce lieu est-il au
soleil à t ? ». Le client ne fait que du rendu, et relit localement le
bitfield sun_day que le serveur lui a donné pour toute la journée — d'où un
slider fluide sans une requête par cran.
| Répertoire | Rôle |
|---|---|
helios-core/ |
Le moteur. Position solaire NOAA, DSM, ray marching. Crate Rust zéro dépendance, portable serveur / mobile / WASM. README |
helios-server/ |
L'API (axum) : /places, /sunlit, /sun-hours, tuiles de canopée, contributions, comptes, remontée OSM. Contient aussi les binaires import et tilegen. README |
cloudflare/ |
Worker qui sert sunmap.pmtiles (sur R2) en /{z}/{x}/{y}.mvt pour le client. README |
scripts/ |
Pipeline de données : extraction osmium, import d'une zone, envoi R2, purge de cache, allègement de modèles 3D. |
tools/asc/ |
Fiche App Store (textes + captures, 5 langues) poussée par l'API App Store Connect. Node, zéro dépendance. README |
docs/ |
Déploiement OVH, procédure d'import de zone, format PMTiles, état de l'art des données d'élévation. |
Dockerfile, docker-compose.yml |
Image de production et pile déployée sur la VM. |
Ignorés par git, chacun pour une bonne raison :
| Chemin | Pourquoi |
|---|---|
ios/ |
Dépôt séparé sunmap-ios — l'app SwiftUI/Mapbox. |
web/ |
Dépôt séparé sunmap-web — le site Next.js. |
pbf/ |
Extraits OSM téléchargés (des Go), régénérables depuis Geofabrik. |
tiles/ |
sunmap.pmtiles, produit par tilegen, monté dans le conteneur. |
target/ |
Artefacts Cargo. |
.env, helios-server/.env |
Secrets : base de données, OAuth OSM, tag d'image. |
cargo test -p helios-core # 14 tests, sans réseau ni base
cargo run --release --bin helios-server # API sur le port 8080Le serveur exige DATABASE_URL (PostgreSQL avec PostGIS — la géométrie OSM a
quitté la base pour l'archive vectorielle, mais les lieux gardent un
geometry(Point, 4326)) et VECTOR_TILES pointant sur tiles/sunmap.pmtiles. Détail dans helios-server/README.md.
Ajouter une zone (bâtiments, végétation, établissements, mobilier) :
scripts/import-zone.sh https://download.geofabrik.de/europe/france-latest.osm.pbf --uploadProcédure complète : docs/import-zone.md.
Seul le backend Rust. L'app iOS, le site et le Worker Cloudflare ne passent pas par Docker.
Le Dockerfile construit depuis la racine du dépôt (le
workspace Cargo entier doit être visible, helios-server dépendant de
helios-core par chemin relatif) et produit une image debian:bookworm-slim
contenant trois binaires :
helios-server— l'API ;import— chargement des lieux en base ;tilegen— extrait OSM → archive vectorielle.
Les deux outils voyagent avec le serveur pour que les imports tournent sur la
VM : la VM n'a pas de toolchain Rust, et les identifiants de la base managée
n'ont ainsi pas à quitter la production. Le processus est non-root, les
migrations SQL sont embarquées dans le binaire (sqlx::migrate!) et rejouées
au démarrage.
docker-compose.yml décrit la pile de la VM OVH :
api— l'image ci-dessus, tirée de GHCR, sans port publié sur l'hôte ;proxy— Nginx Proxy Manager (TLS Let's Encrypt,80/443; l'admin81est lié à127.0.0.1uniquement, un port publié par Docker contournant ufw).
La base de données n'est pas dans la pile : PostgreSQL managé OVH, joint
par DATABASE_URL. Le drapeau ALLOW_REMOTE_DB=1 y est posé délibérément —
sans lui le serveur refuse une base distante, garde-fou contre un cargo run
de poste de dev qui appliquerait ses migrations sur la production.
Un seul workflow : .github/workflows/deploy.yml,
sur push vers main, et seulement si le push touche l'un de ces chemins :
Cargo.toml Cargo.lock helios-core/** helios-server/**
Dockerfile .dockerignore docker-compose.yml
.github/workflows/deploy.yml
Autrement dit : une modification de doc, de script, de tools/ ou de
cloudflare/ ne déploie rien — un build Rust de plusieurs minutes suivi
d'un redémarrage de l'API ne se justifie pas. workflow_dispatch permet de
redéployer à la main (rollback, VM réinstallée).
Le déroulé :
- Build sur les runners GitHub, pas sur la VM — un
cargo build --releasedemande plus de RAM que la VM n'en a, et construire sur place couperait l'API pendant tout le build. Image poussée sur GHCR (ghcr.io/vahanlab/sunmap-api) en deux tags :latestet le SHA du commit. - Déploiement SSH sur la VM (environnement GitHub
production, donc approbation manuelle possible) :git pull --ff-only, réécriture deAPI_TAGdans.env,docker compose pullpuisup -d --no-deps api. Seulapiredémarre — le proxy et ses certificats n'ont aucune raison de bouger. - Vérification : après 10 s, l'état du conteneur et son compteur de redémarrages. Si l'API n'est pas debout (échec de migration, base injoignable), les 100 dernières lignes de log partent dans le job et celui-ci échoue.
- Purge des images de plus d'une semaine — jamais des volumes ni du bind mount
./tiles.
Un rollback consiste à remettre l'ancien API_TAG dans le .env de la VM et
relancer docker compose up -d api : rien à reconstruire.
Secrets attendus (Settings → Secrets and variables → Actions) : DEPLOY_HOST,
DEPLOY_USER, DEPLOY_SSH_KEY, DEPLOY_KNOWN_HOSTS, plus la variable
optionnelle DEPLOY_PATH. Préparation de la VM :
docs/deploiement-ovh.md.
- Worker Cloudflare :
cd cloudflare && npm run deploy(Node 22 minimum). Aucun workflow ne le fait — le Worker change rarement. - Archive vectorielle :
scripts/import-zone.sh … --uploadpoussesunmap.pmtilessur R2, puisscripts/cf-purge.pyvide le cache au bord. - Fiche App Store :
node tools/asc/src/cli.js push.
- Commentaires et documentation en français.
helios-corereste zéro dépendance ; les dépendances vivent dans les binaires.helios-core/src/sun.rsetSunPosition.swift(dépôt iOS) sont des ports exacts l'un de l'autre : toute modification de l'un se répercute sur l'autre, tests compris.- Grille DSM :
xvers l'est,yvers le sud (ligne 0 = bord nord). Azimut en degrés depuis le nord, sens horaire ; élévation en degrés au-dessus de l'horizon.