- Dots de statut en temps réel dans le StatsPanel (ok/slow/error + latence)
- Bannière d'alerte si un service est inaccessible
- EndpointPopover : sélection parmi nœuds connus, test de latence live, URL custom
- Rechargement automatique des données après changement d'endpoint
- SubsquidAdapter et CesiumAdapter lisent l'URL active depuis EndpointConfig
- InfoPanel mis à jour (overlay DU + statut des services)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bouton DU (gauche carte) : affiche en overlay des cercles verts
proportionnels au nombre de membres WoT actifs géolocalisés par ville.
Chargement à la demande, mis en cache 1h.
Pipeline :
SubsquidAdapter.fetchActiveMemberKeys() → isMember:true (~7000)
CesiumAdapter.resolveGeoByKeysBatched() → lots de 500 clés
DataService.fetchMemberCities() → agrégation + cache 1h
HeatMap → CircleMarkers Leaflet en overlay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Un profil Cesium+ (clé 2QsNk...) a city:null. La contrainte
.string().optional() accepte undefined mais pas null → ZodError
silencieux dans resolveGeoByKeys → geoMap vide → 0 transactions
affichées en mode 30 jours.
Correction : .string().nullable().optional() pour title et city.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extrait le pays depuis le champ city Cesium+ en priorité (ex: "Heusy, 4800, Belgique" → BE)
- Bounding boxes réordonnées : petits pays (LU, BE, CH, NL) avant FR pour éviter les faux positifs
- Affiche l'heure du dernier refresh sur le badge live
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restore full Cesium+ city field (including postal code), restructure
the city card so name wraps on two lines with country badge + tx count
+ volume all readable without truncation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Emoji flags render as boxes on Linux. Replace with a small FR/BE/CH
badge. Also strip postal codes from Cesium+ city names (e.g.
"Saint-Jean-de-Laur, 46260" → "Saint-Jean-de-Laur").
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Determine country from geoPoint coordinates using bounding boxes
for the main Ğ1 community countries (FR, BE, CH, ES, DE, IT, ...).
Display the emoji flag before each city name in the top villes panel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cesium+ stores geoPoint in multiple Elasticsearch formats (object,
string "lat,lon", array [lon,lat]). Using z.object() caused a ZodError
that silently swallowed the entire Cesium+ response, leaving geoMap
empty and displaying 0 geolocalized transactions.
Replace the strict Zod schema with z.unknown() and a parseGeoPoint()
helper that normalizes all three formats. Also add [GéoFlux] debug
logs to DataService to trace keyMap/duniterKeys/geoMap pipeline steps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Au lieu de chercher par nom (title), on résout maintenant par clé :
1. buildIdentityKeyMap() : charge toutes les identités Ğ1v2 depuis Subsquid
avec leur ownerKeyChange → currentSS58 → genesisKey → duniterKey
2. ss58ToDuniterKey() : conversion SS58 v2 (préfixe 2 octets) → base58 Ed25519
= _id Cesium+ (même matériau cryptographique, encodage différent)
3. resolveGeoByKeys() : query Cesium+ par ids{} → résultat exact, pas d'ambiguïté
4. Cache keyMap 10 min : 1 requête Subsquid pour ~8000 identités, pas par refresh
Résultat : les membres migrés v1→v2 avec un profil Cesium+ sont correctement
géolocalisés même si leur nom v2 diffère de leur nom v1.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CesiumAdapter : terms query en minuscules (champ title analysé par ES)
- CesiumAdapter : z.coerce.number() pour geoPoint.lat/lon (37% des profils
stockent les coordonnées en string → ZodError silencieux → 0 géolocalisées)
- CesiumAdapter : clé de la Map en toLowerCase() pour cohérence
- DataService : lookup geoMap par fromName.toLowerCase()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CesiumAdapter : utilise le champ `title` (analysé ES) au lieu de `title.keyword`
qui retournait 0 résultats ; coerce lat/lon en number (certains profils stockent des strings)
- DataService : sépare totalVolume (all tx blockchain) de geoCount (tx heatmap)
- StatsPanel : barre de couverture géo uniquement en mode live
- App : badge source "● live Ğ1v2" ou "○ mock"
- DataService.test.ts : mock SubsquidAdapter + CesiumAdapter directement (vi.mock hoistés)
pour que les tests soient déterministes quel que soit VITE_USE_LIVE_API dans .env.local
- tsconfig.app.json : exclude src/test pour éviter les erreurs de build prod
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>