docs: README à jour avec screenshot
2 changed files +94 −42
modified
README.md
+94 −42
@@ -4,8 +4,8 @@ | ||
| 4 | 4 | |
| 5 | 5 | **La vraie valeur de votre propriété, sans boîte noire.** |
| 6 | 6 | |
| 7 | −Moteur d'évaluation immobilière transparent pour le Québec — 3,7 millions de propriétés, | |
| 8 | −745 119 ventes réelles, chaque calcul montré en entier. | |
| 7 | +Moteur d'évaluation immobilière **transparent** pour le Québec — **3 747 008 propriétés**, | |
| 8 | +**745 119 ventes réelles (2021-2026)**, chaque calcul montré en entier. | |
| 9 | 9 | |
| 10 | 10 |  |
| 11 | 11 |  |
@@ -23,15 +23,16 @@ Moteur d'évaluation immobilière transparent pour le Québec — 3,7 millions d | ||
| 23 | 23 | |
| 24 | 24 | **En production : [www.vrai-prix.com](https://www.vrai-prix.com)** |
| 25 | 25 | |
| 26 | −<img src="docs/screenshots/accueil.png" alt="Accueil Vrai-Prix — La vraie valeur, sans boîte noire" width="920"> | |
| 27 | − | |
| 28 | 26 | </div> |
| 29 | 27 | |
| 28 | + | |
| 29 | + | |
| 30 | 30 | --- |
| 31 | 31 | |
| 32 | 32 | ## Sommaire |
| 33 | 33 | |
| 34 | 34 | - [Ce que fait Vrai-Prix](#ce-que-fait-vrai-prix) |
| 35 | +- [Fonctionnalités](#fonctionnalités) | |
| 35 | 36 | - [Visite guidée](#visite-guidée) |
| 36 | 37 | - [Les chiffres qui comptent](#les-chiffres-qui-comptent) |
| 37 | 38 | - [Architecture](#architecture) |
@@ -40,32 +41,39 @@ Moteur d'évaluation immobilière transparent pour le Québec — 3,7 millions d | ||
| 40 | 41 | - [SEO programmatique](#seo-programmatique--376-m-durls-indexables) |
| 41 | 42 | - [Structure du projet](#structure-du-projet) |
| 42 | 43 | - [Endpoints](#endpoints) |
| 43 | −- [Démarrage](#démarrage) | |
| 44 | +- [Démarrage local](#démarrage-local) | |
| 45 | +- [Déploiement](#déploiement) | |
| 46 | +- [Développement remote-first](#développement-remote-first) | |
| 44 | 47 | - [Design](#design) |
| 45 | 48 | - [Auteur](#auteur) |
| 46 | 49 | |
| 47 | 50 | ## Ce que fait Vrai-Prix |
| 48 | 51 | |
| 49 | −Vrai-Prix estime la valeur marchande de **n'importe quelle propriété du Québec** (unifamiliale, plex, condo, chalet, terrain) et montre *pourquoi* — chaque comparable, chaque ajustement en dollars, la pondération du modèle, la fourchette et l'indice de confiance. Le différenciateur est la **transparence totale** : pas de score magique, pas de boîte noire. | |
| 52 | +Vrai-Prix estime la valeur marchande de **n'importe quelle propriété du Québec** (unifamiliale, plex, condo, chalet, terrain) et montre *pourquoi* — **chaque comparable, chaque ajustement en dollars**, la pondération du modèle, la fourchette et l'indice de confiance. Le différenciateur est la **transparence totale** : pas de score magique, **pas de boîte noire**. La méthodologie complète (normes **IAAO**) est publiée intégralement sur le site. | |
| 53 | + | |
| 54 | +Sous le capot : les **6 millésimes (2021-2026)** des rôles d'évaluation foncière géoréférencés du Québec (**MAMH**, données ouvertes) — soit **22 150 285 observations** — fusionnés spatialement avec **745 119 transactions réelles** (**99,88 %** d'appariement, distance médiane **0,6 m**), alimentant un **modèle hédonique LightGBM** et un **moteur de comparables ajustés**. | |
| 55 | + | |
| 56 | +## Fonctionnalités | |
| 50 | 57 | |
| 51 | 58 | | Fonctionnalité | Description | |
| 52 | 59 | |---|---| |
| 53 | −| 🔎 Recherche d'adresse | Plein-texte (FTS5) parmi 3 747 008 unités d'évaluation, tolérante aux fautes | | |
| 54 | −| 💰 Estimation hybride | 65 % modèle hédonique + 35 % comparables ajustés | | |
| 55 | −| 📊 Fourchette + confiance | P10–P90 par régression quantile, indice A–D obligatoire | | |
| 60 | +| 🔎 **Estimation par adresse** | Recherche plein-texte (**FTS5**) parmi **3 747 008 unités d'évaluation**, tolérante aux fautes | | |
| 61 | +| 🧮 **Plan B sans adresse** | **Estimation manuelle** (municipalité + caractéristiques) quand la propriété n'est pas au registre | | |
| 62 | +| 💰 **Estimation hybride** | **65 % modèle hédonique + 35 % comparables ajustés** | | |
| 63 | +| 📊 **Fourchette + confiance** | **P10–P90** par régression quantile, indice **A–D** obligatoire | | |
| 56 | 64 | | 🏠 Portrait de la propriété | Façade SVG dessinée par les données du registre, terrain à l'échelle, composition de la valeur | |
| 57 | −| 🗺️ Vrai-Prix Maps | Recherche par carte 3D (Mapbox GL via le framework partagé **Ka Maps**) — grappes de valeurs estimées pilotées par le viewport | | |
| 65 | +| 🗺️ **Vrai-Prix Maps** | Recherche par **carte 3D** (Mapbox GL via le framework partagé **Ka Maps**) — grappes de valeurs estimées pilotées par le viewport | | |
| 58 | 66 | | 📐 Plan des comparables | Carte « plan d'arpenteur » maison (SVG pur, zéro tuile) — azimut et distance réels | |
| 59 | −| 📈 Historique 2021→2026 | Six millésimes d'estimations par propriété, badges YoY | | |
| 60 | −| 🤖 Ka · agent IA | Agent conversationnel (Claude) branché sur 12 outils serveur : évaluation, comparables, stats, dossier d'expert | | |
| 61 | −| 🏢 Parc immobilier | Évaluation multi-adresses agrégée (jusqu'à 40 propriétés) + rapport consolidé | | |
| 62 | −| 📄 Rapports PDF | Standard (3 p.), professionnel bancaire (6 p.), parc (n+1 p.), statistique provincial — 100 % vectoriels | | |
| 63 | −| 📉 Statistiques | Valeur totale de la province (**2,01 billions $**), palmarès des 200 municipalités | | |
| 64 | −| 🏙️ Pages municipalités | 1 097 pages programmatiques (médiane, croissance, médianes par type) + ~5 900 pages municipalité × type | | |
| 65 | −| 🔑 KA ID | Connexion unique du Groupe KA (SSO signé via le hub groupe-ka.com, session sans base d'utilisateurs) | | |
| 66 | −| 🌐 Bilingue | FR (défaut) / EN, bascule instantanée côté client | | |
| 67 | −| 📱 App iOS | Compagnon natif SwiftUI (onglet carte MapKit) — dépôt séparé | | |
| 68 | −| ⚖️ Conformité | Loi 25, sélecteur de témoins, méthodologie publique intégrale | | |
| 67 | +| 📈 Historique 2021→2026 | **Six millésimes** d'estimations par propriété, badges YoY | | |
| 68 | +| 🤖 **Ka · agent IA** | Agent conversationnel (**Claude**) branché sur **12 outils serveur** : évaluation, comparables, stats, dossier d'expert | | |
| 69 | +| 🏢 Parc immobilier | Évaluation multi-adresses agrégée (jusqu'à **40 propriétés**) + rapport consolidé | | |
| 70 | +| 📄 Rapports PDF | Standard (3 p.), professionnel bancaire (6 p.), parc (n+1 p.), statistique provincial — **100 % vectoriels** | | |
| 71 | +| 📉 **Statistiques** | Valeur totale de la province (**2,01 billions $**), palmarès des **200** municipalités | | |
| 72 | +| 🏙️ Pages municipalités | **1 097** pages programmatiques (médiane, croissance, médianes par type) + **~5 900** pages municipalité × type | | |
| 73 | +| 🔑 KA ID | Connexion unique du **Groupe KA** (SSO signé via le hub groupe-ka.com, session sans base d'utilisateurs) | | |
| 74 | +| 🌐 Bilingue | **FR** (défaut) / **EN**, bascule instantanée côté client | | |
| 75 | +| 📱 App iOS | Compagnon natif **SwiftUI** (onglet carte MapKit) — dépôt séparé | | |
| 76 | +| ⚖️ **Méthodologie transparente** | Loi 25, sélecteur de témoins, méthodologie publique intégrale (7 sections, normes **IAAO**) | | |
| 69 | 77 | |
| 70 | 78 | ## Visite guidée |
| 71 | 79 | |
@@ -82,16 +90,16 @@ Vrai-Prix estime la valeur marchande de **n'importe quelle propriété du Québe | ||
| 82 | 90 | |
| 83 | 91 | ## Les chiffres qui comptent |
| 84 | 92 | |
| 85 | −Validation sur **102 943 ventes jamais vues** du modèle (holdout aléatoire) et test temporel strict (entraîné sans 2026, testé sur 68 364 ventes de 2026), selon la **norme IAAO sur études de ratios** : | |
| 93 | +Validation sur **102 943 ventes jamais vues** du modèle (holdout aléatoire) et **test temporel strict** (entraîné sans 2026, testé sur **68 364 ventes de 2026**), selon la **norme IAAO sur études de ratios** : | |
| 86 | 94 | |
| 87 | 95 | | Métrique | Holdout | Test temporel 2026 | Cible IAAO | |
| 88 | 96 | |---|---|---|---| |
| 89 | 97 | | Erreur médiane (MdAPE) | **11,0 %** | 14,0 % | — | |
| 90 | −| À ±20 % du prix réel | 72,1 % | 66,7 % | — | | |
| 91 | −| Ratio médian | 0,995 | 0,961 | 0,90–1,10 ✅ | | |
| 98 | +| À ±20 % du prix réel | **72,1 %** | 66,7 % | — | | |
| 99 | +| Ratio médian | **0,995** | 0,961 | 0,90–1,10 ✅ | | |
| 92 | 100 | | COD | 22,7 (condos : **11,9** ✅) | 23,7 | ≤ 15–20 | |
| 93 | 101 | | PRD | 1,092 | 1,075 | 0,98–1,03 | |
| 94 | −| R² (log) | 0,789 | 0,743 | — | | |
| 102 | +| R² (log) | **0,789** | 0,743 | — | | |
| 95 | 103 | |
| 96 | 104 | ## Architecture |
| 97 | 105 | |
@@ -120,36 +128,37 @@ Validation sur **102 943 ventes jamais vues** du modèle (holdout aléatoire) et | ||
| 120 | 128 | |
| 121 | 129 | ### Stack |
| 122 | 130 | |
| 123 | −- **Frontend / API** : Next.js 16 (App Router), TypeScript strict, Tailwind CSS 4 | |
| 124 | −- **Base** : SQLite (better-sqlite3) — 3,75 M unités, FTS5, index spatiaux *(non incluse dans ce dépôt)* | |
| 125 | −- **Cartes** : [`@groupe-ka/ka-maps`](https://github.com/spboucher-ai) (framework carto partagé du Groupe KA, moteur Mapbox GL, style Standard 3D) | |
| 126 | −- **Agent IA** : SDK Anthropic (Claude Haiku 4.5, streaming SSE, boucle agentique manuelle, prompt caching) | |
| 127 | −- **Rapports** : pdfkit, 100 % vectoriels, polices embarquées (Space Grotesk / Inter / JetBrains Mono) | |
| 128 | −- **Modèle** (pipeline externe) : LightGBM, scikit-learn, pandas, pyogrio/GDAL | |
| 129 | −- **Tests** : Vitest (moteur d'estimation) + Playwright (mobile, captures d'écran) | |
| 131 | +- **Frontend / API** : **Next.js 16** (App Router), **TypeScript strict**, **Tailwind CSS 4** | |
| 132 | +- **Base** : **SQLite** (better-sqlite3) — **3,75 M unités**, **FTS5**, index spatiaux *(non incluse dans ce dépôt)* | |
| 133 | +- **Cartes** : **`@groupe-ka/ka-maps`** (framework carto partagé du Groupe KA, moteur **Mapbox GL**, style Standard 3D) | |
| 134 | +- **Agent IA** : **SDK Anthropic** (Claude Haiku 4.5, streaming SSE, boucle agentique manuelle, prompt caching) | |
| 135 | +- **Rapports** : **pdfkit**, 100 % vectoriels, polices embarquées (Space Grotesk / Inter / JetBrains Mono) | |
| 136 | +- **Modèle** (pipeline externe) : **LightGBM**, scikit-learn, pandas, pyogrio/GDAL | |
| 137 | +- **Tests** : **Vitest** (moteur d'estimation) + **Playwright** (mobile, captures d'écran) | |
| 138 | +- **Prod** : **PM2** + **ngrok** sur le nœud **M3U96a** du cluster MacLustr | |
| 130 | 139 | |
| 131 | 140 | ## Le moteur d'estimation (`src/lib/engine.ts`) |
| 132 | 141 | |
| 133 | −1. **Comparables** : ventes candidates dans un rayon adaptatif (2,2 → 28 km), filtrées par type et superficie (±20 → ±40 %) ; | |
| 142 | +1. **Comparables** : ventes candidates dans un rayon adaptatif (**2,2 → 28 km**), filtrées par type et superficie (±20 → ±40 %) ; | |
| 134 | 143 | 2. **Ajustements affichés en dollars** : conditions de marché (indice mensuel $/m² lissé 3 mois), superficie (50 % du $/m² du comparable, plafonné ±25 %), âge (0,5 %/an, plafonné ±10 %) ; |
| 135 | 144 | 3. **Pondération gaussienne** : distance (σ 1 500 m), récence (σ 24 mois), similarité de superficie (σ 25 %) ; |
| 136 | −4. **Fusion** : 65 % modèle hédonique pré-calculé + 35 % médiane pondérée des comparables ; | |
| 137 | −5. **Confiance** : nombre de comparables, dispersion, largeur de fourchette → A/B/C/D. | |
| 145 | +4. **Fusion** : **65 % modèle hédonique** pré-calculé + **35 % médiane pondérée des comparables** ; | |
| 146 | +5. **Confiance** : nombre de comparables, dispersion, largeur de fourchette → **A/B/C/D**. | |
| 138 | 147 | |
| 139 | −Chaque fiche montre le calcul en entier : les comparables retenus, chaque ajustement, les poids, la réconciliation. Le rapport PDF « professionnel » reprend la grille d'ajustement au format des évaluateurs (avec les encadrés « ceci n'est pas un rapport OEAQ »). | |
| 148 | +Chaque fiche montre le calcul **en entier** : les comparables retenus, chaque ajustement, les poids, la réconciliation. Le rapport PDF « professionnel » reprend la grille d'ajustement au format des évaluateurs (avec les encadrés « ceci n'est pas un rapport OEAQ »). | |
| 140 | 149 | |
| 141 | 150 | ## Ka — l'agent IA |
| 142 | 151 | |
| 143 | −Page [`/ka`](https://www.vrai-prix.com/ka) : un agent conversationnel branché en direct sur le registre et le moteur. Boucle agentique manuelle (12 tours max) avec **12 outils serveur** : `chercher_propriete` (FTS avec relaxation progressive), `evaluer_propriete`, `dossier_complet` (évaluation + marché + tendance + comparables + synthèse en un appel), `comparables_detailles`, `indice_marche`, `stats_municipalite`, `stats_provinciales`, `evaluer_parc`, `comparer_proprietes`, `estimation_manuelle`, `chercher_proprietes_secteur`, `liens_rapports` (réfs persistantes anti-hallucination pour les PDF). Streaming SSE, tableaux HTML dans le fil, clarification quand l'adresse est ambiguë. | |
| 152 | +Page [`/ka`](https://www.vrai-prix.com/ka) : un agent conversationnel branché **en direct** sur le registre et le moteur. Boucle agentique manuelle (**12 tours max**) avec **12 outils serveur** : `chercher_propriete` (FTS avec relaxation progressive), `evaluer_propriete`, `dossier_complet` (évaluation + marché + tendance + comparables + synthèse en un appel), `comparables_detailles`, `indice_marche`, `stats_municipalite`, `stats_provinciales`, `evaluer_parc`, `comparer_proprietes`, `estimation_manuelle`, `chercher_proprietes_secteur`, `liens_rapports` (réfs persistantes anti-hallucination pour les PDF). **Streaming SSE**, tableaux HTML dans le fil, clarification quand l'adresse est ambiguë. | |
| 144 | 153 | |
| 145 | 154 | ## SEO programmatique — 3,76 M d'URLs indexables |
| 146 | 155 | |
| 147 | 156 | Tout le contenu est servi **en HTML complet dès la première requête** (SSR), avec un maillage interne crawlable : |
| 148 | 157 | |
| 149 | −- **`/municipalites`** → index A-Z des 1 097 municipalités ; | |
| 150 | −- **`/municipalite/[slug]`** (1 097 pages) → médiane 2026, valeur totale, croissance 2021→2026, médianes par type, 24 fiches liées, municipalités voisines ; | |
| 151 | −- **`/municipalite/[slug]/[type]`** (~5 900 pages) → `maison`, `plex`, `chalet`, `condo`, `terrain`, `maison-mobile`, `autre` ; | |
| 152 | −- **`/estimation/[id]`** (3,75 M fiches) → title et meta description **uniques par fiche** (adresse + estimation), canonical, JSON-LD `SingleFamilyResidence`/`Residence`/`Place` + `BreadcrumbList` ; | |
| 158 | +- **`/municipalites`** → index A-Z des **1 097 municipalités** ; | |
| 159 | +- **`/municipalite/[slug]`** (**1 097 pages**) → médiane 2026, valeur totale, croissance 2021→2026, médianes par type, 24 fiches liées, municipalités voisines ; | |
| 160 | +- **`/municipalite/[slug]/[type]`** (**~5 900 pages**) → `maison`, `plex`, `chalet`, `condo`, `terrain`, `maison-mobile`, `autre` ; | |
| 161 | +- **`/estimation/[id]`** (**3,75 M fiches**) → title et meta description **uniques par fiche** (adresse + estimation), canonical, JSON-LD `SingleFamilyResidence`/`Residence`/`Place` + `BreadcrumbList` ; | |
| 153 | 162 | - **Sitemaps** : `/sitemap-index.xml` → `/sitemap.xml` (7 043 pages) + `/estimation/sitemap/0-83.xml` (45 000 fiches chacun, générés à la volée depuis SQLite par plages de rowid) ; |
| 154 | 163 | - JSON-LD `Organization` + `WebSite` global, `robots.txt` propre, `noindex` sur les pages privées/paramétriques. |
| 155 | 164 | |
@@ -201,10 +210,11 @@ src/ | ||
| 201 | 210 | | `GET /api/report/pro?id=` | Rapport détaillé format professionnel (6 pages) | |
| 202 | 211 | | `GET /api/report/portfolio?ids=` | Rapport de parc consolidé | |
| 203 | 212 | | `GET /api/report/stats` | Rapport statistique provincial | |
| 213 | +| `GET /api/stats` · `/api/stats/dashboard` | Agrégats provinciaux (métriques live du hub Groupe KA) | | |
| 204 | 214 | | `GET /api/auth/ka/login` · `/callback` | SSO KA ID (hub groupe-ka.com) | |
| 205 | 215 | | `GET /api/auth/me` · `POST /api/auth/logout` | Session (cookie signé, sans table users) | |
| 206 | 216 | |
| 207 | −## Démarrage | |
| 217 | +## Démarrage local | |
| 208 | 218 | |
| 209 | 219 | ```bash |
| 210 | 220 | npm install |
@@ -228,12 +238,54 @@ npm run build && npm run start | ||
| 228 | 238 | |
| 229 | 239 | > **Captures d'écran** : `node scripts/screenshots.mjs` les régénère depuis la prod (Playwright). |
| 230 | 240 | |
| 241 | +## Déploiement | |
| 242 | + | |
| 243 | +L'app tourne en production sur le cluster **MacLustr** : | |
| 244 | + | |
| 245 | +| | | | |
| 246 | +|---|---| | |
| 247 | +| **Nœud** | **M3U96a** (Mac Studio M3 Ultra, 32 cœurs / 96 Go) — `~/apps/vrai-prix` | | |
| 248 | +| **Port** | **8090** (`next start -H 0.0.0.0 -p 8090`) | | |
| 249 | +| **Domaine** | **[www.vrai-prix.com](https://www.vrai-prix.com)** (tunnel ngrok) | | |
| 250 | +| **Processus PM2** | **`vrai-prix`** (app Next.js) + **`vrai-prix-ngrok`** (tunnel) | | |
| 251 | + | |
| 252 | +```bash | |
| 253 | +# sur M3U96a, après un changement : | |
| 254 | +cd ~/apps/vrai-prix | |
| 255 | +npm run build | |
| 256 | +pm2 restart vrai-prix | |
| 257 | +pm2 logs vrai-prix --lines 30 # vérifier le démarrage | |
| 258 | +``` | |
| 259 | + | |
| 260 | +## Développement remote-first | |
| 261 | + | |
| 262 | +⚠️ **La source de vérité est le repo git sur le nœud M3U96a** (`~/apps/vrai-prix`), **pas** une copie laptop. Toute modification se fait sur le nœud via SSH : édition, `npm run build`, `pm2 restart vrai-prix`, puis commit + push **sur le nœud**. | |
| 263 | + | |
| 264 | +- Remote **`origin` = spbgit** (git perso, git.spboucher.ai) — sur **M3U96a** le remote pointe directement sur le chemin local **`/Users/simon-pierreboucher/srv/git/vrai-prix.git`** (bare repo) ; | |
| 265 | +- Remote secondaire `github` → `github.com/spboucher-ai/vrai-prix` ; | |
| 266 | +- Référence complète du workflow : `~/Desktop/cluster-skill/KA-REMOTE-DEV.md`. | |
| 267 | + | |
| 268 | +```bash | |
| 269 | +ssh M3U96a | |
| 270 | +cd ~/apps/vrai-prix | |
| 271 | +# … modifier, builder, redémarrer … | |
| 272 | +git add <fichiers> && git commit -m "…" && git push origin main | |
| 273 | +``` | |
| 274 | + | |
| 231 | 275 | ## Design |
| 232 | 276 | |
| 233 | 277 | Identité « éditorial sharp » : papier grainé `#f5f3ee`, encre `#141814`, **accent rouge vif `#ff5148`**, bordeaux `#9e2a25` — bordures encre 1,5 px, ombres décalées, display uppercase (Space Grotesk), micro-étiquettes mono (JetBrains Mono), ticker marquee, visualisations SVG data-driven (façade du bâtiment, terrain à l'échelle, jauge de confiance, sparklines) — **zéro image bitmap dans l'app**. |
| 234 | 278 | |
| 235 | 279 | ## Auteur |
| 236 | 280 | |
| 237 | −**Simon-Pierre Boucher** — [contact@spboucher.ai](mailto:contact@spboucher.ai) · Groupe KA | |
| 281 | +**Simon-Pierre Boucher** — [contact@spboucher.ai](mailto:contact@spboucher.ai) | |
| 238 | 282 | |
| 239 | 283 | *Estimations statistiques à titre indicatif — ne remplacent pas une évaluation par un évaluateur agréé (OEAQ). Voir [conditions](https://www.vrai-prix.com/conditions) et [méthodologie complète](https://www.vrai-prix.com/methodologie).* |
| 284 | + | |
| 285 | +--- | |
| 286 | + | |
| 287 | +<div align="center"> | |
| 288 | + | |
| 289 | +Un service **Groupe Ka** | |
| 290 | + | |
| 291 | +</div> | |
added
docs/screenshot.png
+0 −0
Binary file not shown.