Architecture Scoring & Data
Décomposition visuelle de la méthodologie de scoring et de l'infrastructure data derrière Relocate Index — des données institutionnelles brutes au classement pays personnalisé en temps réel.
Vue d'ensemble : Architecture de Scoring à 3 Couches
Couche 1 — Données brutes (Ingestion)
Données institutionnelles stockées par pays et par source dans une table de données brutes. Chaque enregistrement porte le nom de la source, le code indicateur, l'année et la valeur brute. Les sources vont de l'accessible via API (World Bank, Open-Meteo) au seed manuel depuis des rapports publiés (IMD, InterNations, Pew, PISA).
Couche 2 — Scores normalisés (Transformation)
Toutes les valeurs brutes converties sur une échelle 0-100 via normalisation min-max sur le dataset de 60 pays, avec « plus haut = mieux » systématique. Les inversions interviennent à l'étape de normalisation — les scores bruts GPI vont de 1,0 à 3,5 (plus bas = plus pacifique), inversés en 0-100 (plus haut = plus pacifique). Les bornes min-max sont stockées dans une table de paramètres et recalculées quand des pays sont ajoutés. Résultat stocké dans une table de scores normalisés.
Couche 3 — Composite (Côté Client)
Somme pondérée calculée entièrement dans le navigateur. Les utilisateurs règlent des sliders de 0 à 100 par dimension. Les poids se normalisent en interne pour sommer à 1,0. Un slider à 0 exclut la dimension ; les poids restants se re-normalisent. Tous les sliders à 0 déclenche un état d'erreur. Les dimensions NULL sont exclues du composite avec re-normalisation automatique.
Décision : tout le scoring est côté client. Le volume de données est 60 × 10 = 600 scores — tient dans un seul petit payload JSON. Chargé une seule fois au chargement de la page depuis une materialised view. Recalculé à chaque changement de slider sans aucun aller-retour API. Ce choix d'architecture rend le re-classement en temps réel gratuit.
Plongées par Dimension
Healthcare (V2) — Formule à Trois Piliers
healthcare = weighted_blend(UHC, HAQ, capacity)
capacity = weighted_blend(physicians_norm, beds_norm, nurses_norm)
- ◆ Le système existe-t-il ? → WHO Universal Health Coverage Service Coverage Index
- ◆ Produit-il de bons résultats ? → IHME GBD Healthcare Access & Quality Index (mortalité évitable sur 32 causes)
- ◆ Dispose-t-il de ressources structurelles ? → OECD/WHO physicians, hospital beds, nurses pour 1 000 habitants
Décision produit : cette formule a subi 3 itérations. La version UHC-only classait les USA #1 (score UHC 90 — les services existent, mais l'accès requiert une assurance). Ajouter le % OOP ne corrigeait pas (11 % de 4 500 Mds $ = 1 472 $/personne, mais 11 % paraît trompeur en pourcentage). La formule à trois piliers différencie correctement : les services existent (UHC) ≠ les résultats sont bons (HAQ) ≠ les ressources sont suffisantes (capacity). Si les données HAQ ou capacity sont NULL, la formule bascule en mode dégradé — les piliers restants absorbent le poids.
Civic Culture — Gouvernance à Deux Niveaux + Sécurité de rue
civic_culture = weighted_blend(governance, street_safety) — à dominante gouvernance
governance = weighted_blend(WGI_rule_of_law, WGI_corruption_control)
street_safety = 100 − numbeo_crime_index
- ◆ Qualité institutionnelle → World Bank Worldwide Governance Indicators (issus de 35 sources de données cross-pays — enquêtes, évaluations d'experts, rapports d'ONG). Rule of Law mesure l'exécution des contrats, les droits de propriété, la qualité police/justice. Corruption Control mesure l'exercice du pouvoir public à des fins privées.
- ◆ Sécurité vécue → Numbeo Crime Index (gratuit, scrapé). Capture l'expérience quotidienne de la sécurité personnelle dans l'espace public, que la focale institutionnelle de WGI ne capte pas.
Décision : la pondération à dominante gouvernance reflète que la qualité de gouvernance institutionnelle est un signal plus profond et plus durable que la perception de la criminalité de rue (qui peut basculer sur un seul fait divers médiatisé). Mais un pays avec d'excellentes institutions et une criminalité de rue élevée ne devrait pas scorer aussi bien qu'un pays où les deux niveaux sont alignés.
Climate — Profils Discrets avec Paramètres Calibrés
climate = f(avg_temp, rain_days, sunshine_hours, profile_params)
Cinq profils — Warm & Sunny, Hot & Tropical, Mild & Green, Cold & Crisp, No Preference — chacun avec une température de référence, une courbe de pénalité par écart, un seuil de pluie et un seuil d'ensoleillement distincts. Les profils sont calibrés pour que les multiplicateurs de pénalité correspondent à la tolérance réelle de l'utilisateur : un profil tropical tolère une forte pluviométrie avec une pénalité minimale, tandis qu'un profil ensoleillé pénalise lourdement la même pluviométrie.
Décision produit : profils discrets plutôt que sliders continus. Un utilisateur tropical ne voit aucun problème à 200+ jours de pluie — le profil ne pénalise que 5 points. Un utilisateur warm-and-sunny perd 15 points pour la même pluviométrie. Cette asymétrie encode un savoir métier. Un slider continu avec un seul multiplicateur de pénalité ne peut pas la capturer. Les composantes climatiques brutes sont stockées en base ; les profils sont appliqués entièrement côté client sans requêtes supplémentaires.
Pipeline de Données Automatisé
4 Supabase Edge Functions · pg_cron · Rafraîchissement Mensuel
- ◆ Rafraîchissement World Bank — pull des derniers indicateurs WGI, price level et GDP PPP via API
- ◆ Rafraîchissement WHO — pull des données UHC et OOP health expenditure via GHO API
- ◆ Rafraîchissement Climate — fetch des moyennes annuelles Open-Meteo (temp, pluie, ensoleillement) par capitale
- ◆ Recalcul des scores — re-run de la normalisation min-max, application de toutes les formules dimensionnelles (dont Healthcare V2), et rafraîchissement de la materialised view
Décision : rafraîchissement mensuel pour les sources accessibles via API. Les sources annuelles (IMD, InterNations, EF EPI, GPI, Pew, IHME GBD, OECD capacity, PISA) sont mises à jour quand de nouvelles éditions sont publiées — seed manuel via des scripts dédiés car les données sous-jacentes changent une fois par an (PISA : tous les 3 ans). Automatiser leur ingestion ajouterait de la complexité pour zéro bénéfice pratique. Service role key stockée dans Supabase Vault. Le frontend n'utilise que la anon key pour un accès en lecture seule à la materialised view.
Gestion des NULL & Qualité des Données
- ◆ Les scores de dimension NULL sont exclus du calcul composite. Les poids restants se re-normalisent pour sommer à 1,0.
- ◆ Les pays avec trop de dimensions NULL reçoivent un flag « données limitées » dans l'UI.
- ◆ Flag de discordance warmth : quand l'écart entre Hofstede IVR et InterNations dépasse un seuil calibré, l'UI signale la discordance. Suède : IVR élevé, InterNations bas — culturellement chaleureuse en interne, barrière sociale élevée envers les étrangers. Portugal : IVR bas, InterNations élevé — culture réservée, accueil sincère.
- ◆ Les pays anglophones natifs (UK, Irlande, Australie, Nouvelle-Zélande, Canada, US) sont hardcodés à 100 pour English proficiency quel que soit le coverage EF EPI.
- ◆ Les badges de type de système healthcare (Couvert / Assurance obligatoire / Lié à l'employeur / Prévoir du privé) ajoutent un contexte non-scoring sur ce que le système de chaque pays implique pour le budget d'un expatrié.
Décision : la gestion des NULL n'est pas un fallback — c'est une feature produit. Un pays avec d'excellents scores sur 7 dimensions et pas de données sur 3 devrait quand même se classer correctement sur les 7 qu'il a. L'alternative — exclure les pays avec la moindre donnée manquante — éliminerait des candidats solides (Taiwan : 7 indicateurs NULL dus à la non-reconnaissance par la World Bank) et pénaliserait la disponibilité des données plutôt que la qualité du pays.
Onboarding → Mapping des Poids
6 questions — couvrant la situation du foyer, la source de revenu, l'importance de la culture civique, l'importance de la chaleur sociale, la préférence climatique et les besoins de communauté religieuse — chacune mappée à des ajustements de poids dimensionnels en fonction du profil de l'utilisateur. Les mappings sont conçus pour que chaque réponse élève naturellement les dimensions les plus pertinentes pour la situation de l'utilisateur (ex. : les familles voient school culture et healthcare monter ; les remote workers voient purchasing power monter).
Skip sur n'importe quelle question applique les poids par défaut. L'intégralité du parcours tourne dans un state Zustand — zéro aller-retour serveur — et se transfère de manière fluide vers la vue classement.
Décision produit : l'onboarding est un outil de découverte, pas un outil de configuration. La plupart des utilisateurs arrivent en pensant au salaire et au coût de la vie. Les 6 questions les exposent à la culture civique, la chaleur sociale, l'environnement scolaire, la liberté religieuse et le climat comme priorités potentielles qu'ils n'avaient pas envisagées — avant que le classement ne leur montre quoi que ce soit. La première mission du produit est d'élargir ce que l'utilisateur pense devoir évaluer.