docs: refonte du README (pastilles + captures d écran à jour)
3 changed files +85 −235
modified
README.md
+85 −235
@@ -1,271 +1,121 @@ | ||
| 1 | −<div align="center"> | |
| 2 | − | |
| 3 | 1 | # Immo·Ka |
| 4 | 2 | |
| 5 | −### **Toutes les propriétés à vendre du Québec. Un seul endroit.** | |
| 6 | − | |
| 7 | −**[www.immo-ka.com](https://www.immo-ka.com)** | |
| 8 | − | |
| 9 | − | |
| 10 | − | |
| 11 | − | |
| 12 | − | |
| 13 | − | |
| 14 | − | |
| 15 | − | |
| 16 | − | |
| 17 | − | |
| 18 | − | |
| 19 | − | |
| 20 | − | |
| 21 | − | |
| 22 | − | |
| 23 | − | |
| 24 | − | |
| 25 | −</div> | |
| 26 | − | |
| 27 | −--- | |
| 28 | − | |
| 29 | −## Description | |
| 3 | +**Toutes les propriétés à vendre du Québec — maisons, condos, plex et terrains — réunies au même endroit, toujours à jour.** | |
| 30 | 4 | |
| 31 | −**Immo-Ka** est un **agrégateur immobilier indépendant** : toutes les **maisons, condos, plex et terrains à vendre au Québec**, réunis au même endroit. Chercher une propriété au Québec, c'est normalement jongler entre les sites de RE/MAX, Royal LePage, Sutton, Via Capitale, Century 21 et des dizaines d'autres bannières — chacun avec sa navigation, ses filtres, son format. **Immo-Ka retourne le problème** : **un connecteur dédié par agence de courtage** visite chaque source, **normalise chaque propriété vers un schéma unique** (`PropertyListing`), **déduplique par numéro Centris**, et détecte les changements en continu — avec **lien direct vers l'annonce originale**. **Toujours à jour, automatiquement.** | |
| 5 | +[](https://www.immo-ka.com) | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 32 | 14 | |
| 33 | −> Les sites d'agences n'offrent pas de webhooks. Immo-Ka reproduit l'équivalent : | |
| 34 | −> **synchronisation périodique + hash de contenu** → ajouts, **changements de prix** et | |
| 35 | −> retraits (propriété vendue) détectés automatiquement, avec **délai de grâce** contre | |
| 36 | −> les ratés ponctuels et **détection de dérive** par source. | |
| 15 | +**Immo-Ka** est un **agrégateur immobilier indépendant** pour la province de Québec. Chercher une propriété, c'est normalement jongler entre les sites de RE/MAX, Royal LePage, Sutton, Via Capitale, Century 21, DuProprio et des dizaines d'autres bannières — chacun avec sa navigation, ses filtres et son format. Immo-Ka retourne le problème : **un connecteur dédié par source** (105 connecteurs enregistrés — flux centraux de bannières, sous-agences en plan B, plateformes sans courtier) visite chaque site, **normalise chaque annonce vers un schéma unique** (`PropertyListing`), **déduplique par numéro Centris** et détecte les changements en continu, avec lien direct vers l'annonce originale. | |
| 37 | 16 | |
| 38 | −C'est le pendant « à vendre » de [Lou-Ka](https://www.lou-ka.com) (location) — même architecture, schéma adapté à la vente. Immo-Ka fait partie de l'univers **Groupe KA** (Lou-Ka, Auto-Ka, Fabri-Ka, Food-Ka, Ora-Ka, Vrai-Prix…) : compte **KA ID** unique et **favoris partagés** entre toutes les plateformes. | |
| 17 | +Les sites d'agences n'offrent pas de webhooks : Immo-Ka en reproduit l'équivalent par **synchronisation périodique + hash de contenu** — ajouts, changements de prix et retraits (propriété vendue) détectés automatiquement, avec délai de grâce contre les ratés ponctuels. Couverture (métriques de l'agrégat) : **57 900+ propriétés actives**, **22 bannières**, **159 sous-agences**, **2 825 villes**. C'est le pendant « à vendre » de [Lou-Ka](https://www.lou-ka.com) (location), branché sur le moteur d'estimation [Vrai-Prix](https://www.vrai-prix.com) et sur le compte unique **KA ID** du Groupe KA. | |
| 39 | 18 | |
| 40 | −**Fiches enrichies** : galerie photo complète · caractéristiques Centris · pièces & dimensions · **estimation de valeur Vrai-Prix** (fourchette + confiance + analyse) · **rôle d'évaluation foncière** (valeur au rôle terrain/bâtiment, année de construction et superficies officielles — jointes localement depuis les 3,7 M d'unités de la base Vrai-Prix) · **jours sur le marché** · **statistiques de quartier** (recensement StatCan, proximité, îlot de chaleur) · **carte 3D Ka Maps** · historique de prix · favoris **KA ID** · **référencement programmatique** (une page indexable par ville et par type, HTML complet rendu côté serveur). | |
| 19 | +## Captures d'écran | |
| 41 | 20 | |
| 42 | −## Aperçu | |
| 43 | − | |
| 44 | −| Accueil — moteur de recherche | Grille de résultats | | |
| 45 | −|---|---| | |
| 46 | −|  |  | | |
| 47 | − | |
| 48 | −| Carte Ka Maps — grappes de prix en direct | Fiche — galerie, Vrai-Prix, courtier | | |
| 49 | −|---|---| | |
| 50 | −|  |  | | |
| 51 | − | |
| 52 | −| Fiche — pièces, emplacement, quartier | Page ville indexable (`/a-vendre/quebec`) | | |
| 53 | −|---|---| | |
| 54 | −|  |  | | |
| 55 | − | |
| 56 | −| Statistiques du marché agrégé | Agences — 22 bannières, 159 sous-agences | | |
| 57 | −|---|---| | |
| 58 | −|  |  | | |
| 59 | − | |
| 60 | −<div align="center"> | |
| 61 | − | |
| 62 | −| Mobile | | |
| 63 | −|---| | |
| 64 | −| <img src="docs/screenshots/mobile.png" alt="Version mobile" width="360" /> | | |
| 65 | − | |
| 66 | −</div> | |
| 21 | +<p align="center"> | |
| 22 | + <img src="docs/screenshots/immo-ka-desktop.png" width="640" alt="Accueil — desktop"> | |
| 23 | + <img src="docs/screenshots/immo-ka-mobile.png" width="200" alt="Accueil — mobile"> | |
| 24 | +</p> | |
| 67 | 25 | |
| 68 | 26 | ## Fonctionnalités |
| 69 | 27 | |
| 70 | −| | Fonctionnalité | Détails | | |
| 71 | −|---|---|---| | |
| 72 | −| 🔎 | **Recherche & filtres** | texte libre (adresse, ville, n° MLS), ville + secteur, type, agence, prix, chambres, salles de bain, superficie ; tri prix/récence ; **état dans l'URL** (partageable) | | |
| 73 | −| 🗺 | **Carte Ka Maps** | framework carto maison du Groupe KA (moteur **Mapbox GL 3D**) : grappes de prix, marqueurs colorés selon l'écart au Vrai-Prix, « rechercher en déplaçant la carte », popups éditoriales, bascule 2D/3D | | |
| 74 | −| 🏠 | **Fiche complète** | galerie + lightbox (jusqu'à **40+ photos 1600 px**), fiche technique à rangées, tableau des caractéristiques Centris, pièces & dimensions par étage, inclusions, description, mini-carte d'emplacement (5/15 min à pied) | | |
| 75 | −| 💰 | **Vrai-Prix** | **estimation de valeur marchande** (modèle hédonique + comparables du moteur [Vrai-Prix](https://github.com/spboucher-ai/vrai-prix)) : jauge P10–P90, marqueurs estimation/prix demandé, verdict (sur-évalué / aligné / sous l'estimation), lien vers l'analyse détaillée | | |
| 76 | −| 📈 | **Historique de prix** | baisses et hausses du prix demandé horodatées (table `price_log`) | | |
| 77 | −| 🏘 | **Quartier** | aire de diffusion du recensement (± 500 habitants) : revenu médian, loyer moyen, âge médian, % locataires, % français, proximité épiceries/parcs/soins (**StatCan**), îlot de chaleur (**INSPQ**) | | |
| 78 | −| 📊 | **Stats** | volumes par type et par agence, prix moyens, **écart prix demandé vs estimation Vrai-Prix par bannière** (médiane, P25–P75, % sur-évalués) + **rapport PDF Groupe-KA** | | |
| 79 | −| 🏢 | **Agences** | registre éclaté par bannière → sous-agence (bureau), avec compte d'annonces **dédupliqué** | | |
| 80 | −| ♥ | **Favoris & KA ID** | connexion « Se connecter avec **KA ID** » (SSO du hub groupe-ka.com, JWT HS256), favoris stockés au hub — le même cœur ♥ suit l'utilisateur sur **toutes les plateformes Ka** | | |
| 81 | −| 💬 | **KA Agent** | bulle de chat Groupe KA intégrée (widget `ka-agent.js`) | | |
| 82 | −| 🔍 | **SEO programmatique** | HTML complet **rendu serveur** sur chaque route, une page indexable par ville / type / ville+type, sitemaps, données structurées — voir section dédiée | | |
| 83 | − | |
| 84 | −## Couverture (métriques en direct) | |
| 85 | − | |
| 86 | −**57 900+ propriétés actives** · **26 sources** avec annonces · **22 bannières** · **159 sous-agences** · **2 825 villes** · prix moyen ≈ **683 000 $** | |
| 87 | − | |
| 88 | −| Source | Annonces | Méthode technique | | |
| 89 | −|---|---:|---| | |
| 90 | −| RE/MAX Québec | ~21 300 | Meilisearch public + sharding FSA postal + page détail enrichie | | |
| 91 | −| DuProprio | ~7 300 | API interne JSON (sans courtier) | | |
| 92 | −| Kijiji Québec | ~7 000 | flux annonces immobilier à vendre (filtre anti-prix-bidon < 5 000 $) | | |
| 93 | −| LesPAC Québec | ~4 100 | listing + fiche détail (adresse civique, galerie basephoto) | | |
| 94 | −| Via Capitale | ~4 100 | portail central (Firecrawl stealth, pagination `criteresJson`) | | |
| 95 | −| Groupe Sutton | ~3 100 | sitemap `sitemap_inscription.cfm` → n° Centris | | |
| 96 | −| Proprio Direct | ~2 500 | API interne JSON | | |
| 97 | −| Century 21 Québec | ~1 600 | sous-agences source.immo (« All Quebec ») | | |
| 98 | −| Domicilia (réseau Humania) | ~1 400 | API du réseau | | |
| 99 | −| Ubee · Vendirect · Engel & Völkers | ~3 400 | plateformes + property-sitemap → JSON-LD | | |
| 100 | −| Royal LePage | ~900 | recherche par ville filtrée QC + sharding + dédup MLS | | |
| 101 | −| Barnes · Profusion (Christie's) · KW · M Immobilier · Sotheby's · L'Expert PM | ~1 200 | Algolia, WordPress JSON-LD, HTML SSR, Centris | | |
| 102 | −| Sous-agences RE/MAX · Via Capitale · Century 21 | *backup* | 60+ connecteurs `*_ag_*` auto-générés, dédup par n° Centris | | |
| 103 | − | |
| 104 | −Les sous-agences servent de plan B : si le flux central d'une bannière tombe, elles prennent le relais **sans double-comptage** (déduplication pré-calculée par numéro Centris, colonne `dup_hidden`). | |
| 105 | − | |
| 106 | −## Stack technique | |
| 107 | − | |
| 108 | −- **Backend** : **Python 3.14** · **FastAPI** (API JSON + rendu SEO serveur + service du frontend) · **SQLite en mode WAL** (accès concurrents lecture/écriture) | |
| 109 | −- **Frontend** : **React 18 + Vite + TypeScript** · react-router · design system **ka-ui** (badge + footer communs du Groupe KA) | |
| 110 | −- **Cartographie** : **Ka Maps** — framework carto partagé du Groupe KA sur moteur **Mapbox GL 3D** | |
| 111 | −- **Ingestion** : **92 connecteurs** (API JSON internes — Meilisearch, Algolia, source.immo, wp-json —, JSON-LD, sitemaps, **Firecrawl** pour les sites SPA/anti-bot) | |
| 112 | −- **Enrichissement** : géocodage avec cache, POI de proximité, quartier **StatCan/INSPQ**, estimations **Vrai-Prix** + **rôle d'évaluation** (jointure d'adresse locale : valeurs officielles, année, superficies — en repli des colonnes quand la source ne les donne pas) | |
| 113 | −- **Auth** : **SSO KA ID** (JWT HS256 du hub groupe-ka.com, stdlib pure) | |
| 114 | −- **Exploitation** : **PM2** + tunnel **ngrok** | |
| 115 | − | |
| 116 | −### Architecture | |
| 28 | +- **Recherche & filtres** — texte libre (adresse, ville, n° MLS), ville + secteur, type, agence, prix, chambres, salles de bain, superficie ; tri par prix ou récence ; état encodé dans l'URL (partageable). | |
| 29 | +- **Carte Ka Maps** — framework carto maison du Groupe KA (moteur Mapbox GL 3D) : grappes de prix, marqueurs colorés selon l'écart au Vrai-Prix, « rechercher en déplaçant la carte », bascule 2D/3D. | |
| 30 | +- **Fiche complète** — galerie + lightbox, caractéristiques Centris, pièces & dimensions par étage, inclusions, description, mini-carte d'emplacement. | |
| 31 | +- **Estimation Vrai-Prix** — valeur marchande estimée (modèle hédonique + comparables) : jauge P10–P90, verdict sur-évalué / aligné / sous l'estimation. | |
| 32 | +- **Rôle d'évaluation foncière** — valeur au rôle terrain/bâtiment, année de construction et superficies officielles, jointes localement depuis la base Vrai-Prix. | |
| 33 | +- **Historique de prix** — baisses et hausses du prix demandé horodatées (table `price_log`) + jours sur le marché. | |
| 34 | +- **Quartier** — aire de diffusion du recensement : revenu médian, loyer moyen, % locataires, proximité épiceries/parcs/soins (StatCan), îlot de chaleur (INSPQ). | |
| 35 | +- **Couches territoriales** — registre des loyers, zones inondables (BDZI), qualité de l'air, prix de l'essence, commerces et transport en commun, **estimation Hydro-Québec précalculée** lors de la sync. | |
| 36 | +- **Stats** — tableau de bord `/stats` : volumes par type et bannière, écart prix demandé vs estimation Vrai-Prix, panneaux territoire + rapport PDF Groupe-KA. | |
| 37 | +- **Agences** — registre par bannière → sous-agence, comptes d'annonces dédupliqués. | |
| 38 | +- **KA ID & favoris** — SSO du hub groupe-ka.com (JWT HS256), favoris partagés sur toutes les plateformes Ka ; widget de chat **KA Agent** intégré. | |
| 39 | +- **SEO programmatique** — HTML complet rendu côté serveur, une page indexable par ville / type / ville+type, sitemaps et données structurées. | |
| 40 | + | |
| 41 | +## Architecture | |
| 42 | + | |
| 43 | +| Composant | Rôle | | |
| 44 | +|---|---| | |
| 45 | +| `immoka/connectors/` | 105 connecteurs enregistrés (API JSON internes — Meilisearch, Algolia, source.immo, wp-json —, JSON-LD, sitemaps, Firecrawl pour les sites SPA/anti-bot) | | |
| 46 | +| `immoka/ingest.py` + `normalize.py` + `schema.py` | boucle de sync : normalisation vers `PropertyListing`, upsert par hash de contenu, dédup Centris (`dup_hidden`), délai de grâce sur les retraits | | |
| 47 | +| `immoka/web.py` + `seo.py` | FastAPI : API JSON, rendu SEO serveur, service du build frontend | | |
| 48 | +| Enrichissement | `geocode.py`, `poi.py`, `quartier.py`, `vraiprix.py`/`vraiprix_local.py`, `hydro.py`, `inondation.py`, `air.py`, `gaz.py`, `commerces.py`, `quality.py`/`imgaudit.py` (couche qualité + quarantaine) | | |
| 49 | +| Base de données | **SQLite en mode WAL** : `data/immoka.db` (annonces) + bases annexes (`quartier.db`, `vraiprix.db`, `hydro.db`, `air.db`, `gaz.db`, `commerces.db`, `inondation.db`, `transit.db`, `rdl.db`) | | |
| 50 | +| Frontend | React 18 + Vite + TypeScript, react-router, design system ka-ui, cartes `@groupe-ka/ka-maps` (Mapbox GL 3.28) | | |
| 117 | 51 | |
| 118 | −```mermaid | |
| 119 | −flowchart LR | |
| 120 | − subgraph Sources["Agences & plateformes du Québec"] | |
| 121 | − S1["RE/MAX · Sutton · Via Capitale<br/>Century 21 · Royal LePage · Proprio Direct<br/>DuProprio · Kijiji · LesPAC · E&V · Barnes<br/>… 92 connecteurs"] | |
| 122 | − end | |
| 123 | − subgraph ImmoKa["Immo-Ka"] | |
| 124 | − C["Connecteurs<br/><i>1 adaptateur / source</i>"] --> N["Normalisation<br/><i>schéma PropertyListing</i>"] | |
| 125 | − N --> D[("SQLite WAL<br/>hash + diff + dédup Centris<br/>+ géocodage + POI + quartier")] | |
| 126 | − D --> A["API FastAPI<br/>listings · facets · geojson · stats"] | |
| 127 | − D --> SEO["Rendu SEO serveur<br/><i>immoka/seo.py</i><br/>HTML + JSON-LD + sitemaps"] | |
| 128 | − A --> F["React 18 + Vite + Ka Maps<br/>liste · carte · fiche · stats"] | |
| 129 | − SEO --> G["🕷 Moteurs de recherche"] | |
| 130 | − end | |
| 131 | − W["⏱ Watcher (PM2)"] -.-> C | |
| 132 | − S1 --> C | |
| 133 | − F --> U["🔑 Acheteur"] | |
| 134 | − H["🌐 Hub groupe-ka.com<br/>KA ID · favoris"] <--> F | |
| 135 | −``` | |
| 52 | +**Processus PM2 (production)** : | |
| 136 | 53 | |
| 137 | −| Couche | Rôle | Fichiers | | |
| 54 | +| Processus | Commande | Rôle | | |
| 138 | 55 | |---|---|---| |
| 139 | −| **Connecteurs** | 1 module par source : API JSON interne (Meilisearch, Algolia, source.immo, wp-json), JSON-LD, sitemap, ou Firecrawl pour les sites SPA/anti-bot ; registres auto-générateurs pour les bannières à sous-agences | `immoka/connectors/*.py` | | |
| 140 | −| **Schéma** | `PropertyListing` : adresse, secteur, ville, région, type canonique, prix, chambres/SdB, superficies, année, MLS, courtier, pièces (dimensions), **toutes les photos**, caractéristiques structurées | `immoka/schema.py`, `immoka/normalize.py` | | |
| 141 | −| **Diff engine** | upsert par hash de contenu, délai de grâce (2 syncs), détection de dérive par source, historique de prix, **déduplication inter-agences par n° Centris** + **dédup inter-sources par adresse** (même adresse normalisée + type + prix ±1 %, garde-fou apt/unité) | `immoka/db.py`, `immoka/ingest.py` | | |
| 142 | −| **Enrichissement** | géocodage avec cache, commodités de proximité (POI), statistiques de quartier StatCan/INSPQ, estimations Vrai-Prix + rôle d'évaluation (year_built/lot_sqft en repli, provenance `details.*_source`) | `immoka/geocode.py`, `immoka/poi.py`, `immoka/quartier.py`, `immoka/vraiprix*.py` | | |
| 143 | −| **API** | filtres ville/secteur/région/type/agence/prix/chambres/superficie, facettes, stats, GeoJSON borné par bbox pour la carte | `immoka/web.py` | | |
| 144 | −| **SEO** | rendu HTML serveur par route, pages programmatiques, sitemaps, robots.txt, 301/410/404 | `immoka/seo.py` | | |
| 145 | −| **Auth & favoris** | SSO KA ID (JWT HS256 du hub, stdlib pure), profil hub, favoris centraux | `immoka/auth.py`, `immoka/hubprofile.py`, `immoka/hubfav.py`, `immoka/favorites.py` | | |
| 146 | −| **Frontend** | React 18 + Vite + TS + react-router + Ka Maps : accueil (liste/carte), fiche, pages ville/type, Stats, Agences, profil KA | `frontend/` | | |
| 147 | − | |
| 148 | −## Référencement (SEO) | |
| 149 | − | |
| 150 | −Le SPA React est doublé d'un **rendu HTML côté serveur** (`immoka/seo.py`, branché sur le catch-all FastAPI) : chaque URL livre son contenu complet dès la première requête, **sans exécution JavaScript** — React prend le relais au montage. | |
| 151 | − | |
| 152 | −- **Chaque page** a un `<title>`, une meta description, un canonical et des balises `og:`/`twitter:` uniques, plus le contenu réel (H1, stats, liste d'annonces avec liens) directement dans le HTML initial. | |
| 153 | −- **Pages programmatiques** alignées sur les recherches réelles : `/a-vendre/{ville}` (**1 589 pages**), `/a-vendre/{ville}/{type}` (**2 702 pages**), `/type/{type}` (21 pages) — statistiques (nombre, prix médian/moyen), liste paginée (48/page), maillage interne (types de la ville, villes voisines), seuil de qualité (≥ 3 annonces). | |
| 154 | −- **Fiches** : URL stable et lisible `/propriete/{uid}/{slug-adresse-ville}` (301 depuis l'uid nu), JSON-LD `RealEstateListing` + `Offer` (prix CAD, adresse, géolocalisation, photos) + `BreadcrumbList`. | |
| 155 | −- **Cycle de vie propre** : propriété retirée/vendue → **410 Gone** avec liens de sortie ; uid inconnu → **404** réel. Fini les soft-404. | |
| 156 | −- **`sitemap.xml`** : index + sous-sitemaps (**57 900+ fiches**, villes, villes-types, types, pages) avec `lastmod`, régénérés automatiquement. **`robots.txt`** propre. | |
| 157 | −- Le slug est calculé par le **même algorithme** en Python (`seo.py`) et en TypeScript (`api.ts`) — les liens du SPA et du serveur coïncident. | |
| 158 | − | |
| 159 | −## API | |
| 56 | +| `immo-ka-web` | `.venv/bin/python run.py serve 8096` | API + frontend + SSR SEO | | |
| 57 | +| `immo-ka-sync` | `.venv/bin/python run.py watch 240` | resynchronisation des sources aux 4 h | | |
| 58 | +| `immo-ka-ngrok` | `ngrok http --url=www.immo-ka.com 8096` | tunnel vers le domaine public | | |
| 160 | 59 | |
| 161 | −Toutes les réponses sont en **JSON**, compressées (gzip), CORS ouvert. | |
| 60 | +## Structure du repo | |
| 162 | 61 | |
| 163 | −| Endpoint | Description | | |
| 62 | +| Répertoire | Contenu | | |
| 164 | 63 | |---|---| |
| 165 | −| `GET /api/listings` | recherche paginée — filtres `city`, `sector`, `region`, `property_type`, `source`, `price_min/max`, `bedrooms_min`, `bathrooms_min`, `area_min`, `q`, `sort`, `limit`, `offset` | | |
| 166 | −| `GET /api/listings/{uid}` | fiche complète : photos, caractéristiques, pièces, historique de prix, `days_on_market` (+ `details.listed_at` si la source la donne), POI, quartier, Vrai-Prix + rôle d'évaluation | | |
| 167 | −| `GET /api/listings.geojson` | marqueurs de carte allégés, bornés par `bbox=ouest,sud,est,nord` | | |
| 168 | −| `GET /api/facets` | valeurs distinctes (villes, secteurs, types, sources) pour les filtres | | |
| 169 | −| `GET /api/sources` · `GET /api/agencies` | registre des sources et arbre bannière → sous-agences | | |
| 170 | −| `GET /api/stats` | totaux, prix moyens, écarts Vrai-Prix par bannière, journal des syncs | | |
| 171 | −| `GET /api/seo/resolve` | slug de page programmatique → valeurs exactes | | |
| 172 | −| `GET /sitemap.xml` · `/sitemaps/*.xml` · `/robots.txt` | référencement | | |
| 173 | −| `POST /api/sync` | déclenche une synchronisation (toutes les sources ou une seule) | | |
| 64 | +| `immoka/` | paquet Python : connecteurs, ingestion, API/SSR, enrichissements, stats | | |
| 65 | +| `frontend/` | SPA React 18 + Vite + TypeScript (pages, composants, ka-maps, ka-ui) | | |
| 66 | +| `data/` | bases SQLite (immoka.db + bases annexes) et registres d'agences JSON | | |
| 67 | +| `docs/` | captures d'écran, docs des connecteurs, rapports de validation | | |
| 68 | +| `scripts/` | outillage (génération des docs connecteurs, rafraîchissement Via Capitale, validation du rendu) | | |
| 69 | +| `run.py` / `requirements.txt` | point d'entrée CLI (`sync`, `watch`, `serve`, `list`, `geocode`, `poi`, `quartier`, …) et dépendances backend | | |
| 174 | 70 | |
| 175 | −## Structure du projet | |
| 71 | +## Développement (remote-first) | |
| 176 | 72 | |
| 177 | −``` | |
| 178 | −immo-ka/ | |
| 179 | −├── run.py # point d'entrée : list · sync · serve · watch | |
| 180 | −├── immoka/ | |
| 181 | −│ ├── web.py # API FastAPI + service du frontend + catch-all SEO | |
| 182 | −│ ├── seo.py # rendu HTML serveur, sitemaps, robots, slugs | |
| 183 | −│ ├── schema.py # PropertyListing (schéma normalisé) | |
| 184 | −│ ├── normalize.py # types canoniques, extraction chambres/SdB | |
| 185 | −│ ├── db.py # SQLite WAL : upsert, diff, dédup Centris, price_log | |
| 186 | −│ ├── ingest.py # orchestration des syncs | |
| 187 | −│ ├── geocode.py · poi.py · quartier.py # enrichissement | |
| 188 | −│ ├── vraiprix.py · vraiprix_local.py # estimations de valeur | |
| 189 | −│ ├── auth.py · hubprofile.py · hubfav.py · favorites.py # KA ID + favoris | |
| 190 | −│ └── connectors/ # 92 connecteurs (31 modules + registres auto-générés) | |
| 191 | −├── frontend/ # React 18 + Vite + TS | |
| 192 | −│ └── src/ | |
| 193 | −│ ├── pages/ # Home · Listing · Category · Stats · Sources · Profil | |
| 194 | −│ ├── components/ # ListingCard · MapView · PropertyMap · QuartierBlock · Icons | |
| 195 | −│ └── kamaps/ # intégration Ka Maps (Groupe KA) | |
| 196 | −├── data/ | |
| 197 | −│ ├── sources.json # registre des sources (50 entrées, statuts) | |
| 198 | −│ └── immoka.db # SQLite (non versionnée) | |
| 199 | −└── docs/screenshots/ # captures de ce README | |
| 200 | −``` | |
| 73 | +La **source de vérité est le repo git sur le nœud M4M64a** (`~/apps/immo-ka`) — immo-ka n'a **aucune copie laptop**. Toute modification se fait sur le nœud via SSH : édition, build, redémarrage, puis commit/push depuis le nœud (agent forwarding actif). | |
| 201 | 74 | |
| 202 | −## Démarrage local | |
| 75 | +- Remote `origin` = **spbgit**, le git perso ([git.spboucher.ai](https://git.spboucher.ai)) : alias SSH **`gitsrv`** configuré sur le nœud → `gitsrv:srv/git/immo-ka.git` (bare repo hébergé sur M3U96a). | |
| 203 | 76 | |
| 204 | 77 | ```bash |
| 78 | +ssh M4M64a | |
| 79 | +cd ~/apps/immo-ka | |
| 80 | + | |
| 81 | +# Backend | |
| 205 | 82 | python3 -m venv .venv && .venv/bin/pip install -r requirements.txt |
| 206 | 83 | |
| 207 | −# frontend | |
| 84 | +# Frontend | |
| 208 | 85 | cd frontend && npm install && npm run build && cd .. |
| 209 | 86 | |
| 210 | −# (optionnel) sites JavaScript / anti-bot | |
| 211 | −echo "FIRECRAWL_API_KEY=fc-votre-cle" > .env | |
| 87 | +# Ingestion et service | |
| 88 | +.venv/bin/python run.py list # lister les connecteurs | |
| 89 | +.venv/bin/python run.py sync # synchroniser (ou : sync <source> …) | |
| 90 | +.venv/bin/python run.py serve 8096 # API + frontend | |
| 212 | 91 | |
| 213 | −.venv/bin/python run.py list # 92 connecteurs enregistrés | |
| 214 | −.venv/bin/python run.py sync # toutes les agences (ou: sync remax_quebec sutton) | |
| 215 | −.venv/bin/python run.py serve 8090 # API + frontend + SEO → http://localhost:8090 | |
| 216 | −.venv/bin/python run.py watch 180 # synchronisation en boucle (minutes) | |
| 217 | −``` | |
| 218 | − | |
| 219 | −Vérifier le rendu SEO en local : | |
| 92 | +# Après un changement en prod | |
| 93 | +pm2 restart immo-ka-web # (ou immo-ka-sync selon le changement) | |
| 220 | 94 | |
| 221 | −```bash | |
| 222 | −curl -s localhost:8090/a-vendre/quebec | grep '<title>' | |
| 223 | −curl -s localhost:8090/sitemap.xml | |
| 95 | +git add <fichiers> && git commit && git push origin main | |
| 224 | 96 | ``` |
| 225 | 97 | |
| 226 | −## Ajouter une agence | |
| 227 | − | |
| 228 | −1. Créer `immoka/connectors/<id>.py` : sous-classe de `BaseConnector`, définir `source_id`, implémenter `fetch() -> list[PropertyListing]`. Le registre est **auto-découvrant** — aucun fichier partagé à modifier. | |
| 229 | −2. Ajouter l'entrée dans `data/sources.json`. | |
| 230 | −3. Tester : `.venv/bin/python run.py sync <id>`. | |
| 231 | − | |
| 232 | −Pour une bannière à sous-agences (RE/MAX, Via Capitale, Century 21), un module génère un connecteur par sous-agence depuis un registre JSON — nommer les `source_id` en `<banniere>_ag_<slug>` active automatiquement la déduplication. | |
| 233 | − | |
| 234 | 98 | ## Déploiement |
| 235 | 99 | |
| 236 | −Déployé sur le cluster **MacLustr**, nœud **M4M64a** (`~/apps/immo-ka`), **port 8096**, exposé sur **[www.immo-ka.com](https://www.immo-ka.com)** via **PM2** : | |
| 237 | − | |
| 238 | −| Processus PM2 | Rôle | | |
| 239 | −|---|---| | |
| 240 | −| **`immo-ka-web`** | API + frontend + rendu SEO (`run.py serve 8096`) | | |
| 241 | −| **`immo-ka-sync`** | watcher de synchronisation (`run.py watch`) | | |
| 242 | −| **`immo-ka-ngrok`** | tunnel ngrok → **www.immo-ka.com** | | |
| 243 | − | |
| 244 | −Base **SQLite en mode WAL** pour les accès concurrents lecture/écriture. Variables d'environnement sur le nœud (`.env`) : `KA_SSO_SECRET`, `KA_HUB_URL`, `IMMOKA_BASE_URL`, `AUTH_SECRET`, `FIRECRAWL_API_KEY`. | |
| 245 | − | |
| 246 | −## Développement remote-first | |
| 100 | +En production sur le **nœud M4M64a** du cluster MacLustr (`~/apps/immo-ka`), servi sur le **port 8096** et exposé via un tunnel **ngrok** sur **[www.immo-ka.com](https://www.immo-ka.com)**. Trois processus PM2 : `immo-ka-web` (serveur), `immo-ka-sync` (boucle de sync aux 4 h), `immo-ka-ngrok` (tunnel). La base `data/` de prod est resynchronisée en continu — ne jamais l'écraser. | |
| 247 | 101 | |
| 248 | −⚠️ **La source de vérité est le repo git sur le nœud M4M64a** (`~/apps/immo-ka`) — **il n'existe aucune copie laptop**. Toute modification se fait **sur le nœud via SSH** : édition, build frontend, `pm2 restart immo-ka-web`, puis `git add/commit/push` **depuis le nœud**. | |
| 102 | +## Écosystème Groupe KA | |
| 249 | 103 | |
| 250 | −- **Remote `origin` = spbgit** (le git perso — **git.spboucher.ai**, bare repo `~/srv/git/immo-ka.git` sur M3U96a), joignable via l'**alias SSH `gitsrv`** configuré sur le nœud. **Pas GitHub.** | |
| 251 | −- Le push fonctionne grâce à l'**agent forwarding** actif pendant une session SSH depuis le laptop. | |
| 252 | −- Référence complète (ports, PM2, gotchas gitsrv) : `~/Desktop/cluster-skill/KA-REMOTE-DEV.md`. | |
| 104 | +- [groupe-ka.com](https://www.groupe-ka.com) — portail | |
| 105 | +- [lou-ka.com](https://www.lou-ka.com) — logements à louer | |
| 106 | +- [immo-ka.com](https://www.immo-ka.com) — propriétés à vendre | |
| 107 | +- [vrai-prix.com](https://www.vrai-prix.com) — estimation immobilière | |
| 108 | +- [auto-ka.com](https://www.auto-ka.com) — véhicules | |
| 109 | +- [fabri-ka.com](https://www.fabri-ka.com) — produits québécois | |
| 110 | +- [food-ka.com](https://www.food-ka.com) — épicerie/alimentation | |
| 111 | +- [resto-ka.com](https://www.resto-ka.com) — restaurants | |
| 112 | +- [sorti-ka.com](https://www.sorti-ka.com) — sorties et événements | |
| 113 | +- [job-ka.com](https://www.job-ka.com) — emplois | |
| 114 | +- [crea-ka.com](https://www.crea-ka.com) — créateurs | |
| 115 | +- [trouve-ka.com](https://www.trouve-ka.com) — petites annonces | |
| 116 | +- [api-ka.com](https://www.api-ka.com) — API de données | |
| 253 | 117 | |
| 254 | 118 | --- |
| 255 | 119 | |
| 256 | −## Auteur | |
| 257 | − | |
| 258 | −**Immo-Ka est une application du [Groupe-Ka](mailto:contact@groupe-ka.com)** | |
| 259 | −📧 [contact@groupe-ka.com](mailto:contact@groupe-ka.com) · | |
| 260 | −[info@groupe-ka.com](mailto:info@groupe-ka.com) (demandes d'information) · | |
| 261 | −[admin@groupe-ka.com](mailto:admin@groupe-ka.com) (retraits & renseignements personnels) | |
| 262 | − | |
| 263 | −Développé par **Simon-Pierre Boucher** — [contact@spboucher.ai](mailto:contact@spboucher.ai) | |
| 264 | − | |
| 265 | −*Agrégateur indépendant — les annonces proviennent des sites publics des agences de courtage et sont rafraîchies automatiquement ; chaque fiche renvoie vers l'annonce originale de l'agence. Conditions d'utilisation et politique de confidentialité : `/conditions` et `/confidentialite` sur [www.immo-ka.com](https://www.immo-ka.com).* | |
| 266 | − | |
| 267 | −<div align="center"> | |
| 268 | − | |
| 269 | −**Un service <a href="https://www.groupe-ka.com">Groupe Ka</a>** | |
| 270 | − | |
| 271 | −</div> | |
| 120 | +© Groupe KA — Simon-Pierre Boucher · contact@spboucher.ai | |
| 121 | +Ce repo vit sur **spbgit** ([git.spboucher.ai](https://git.spboucher.ai)). | |
added
docs/screenshots/immo-ka-desktop.png
+0 −0
Binary file not shown.
added
docs/screenshots/immo-ka-mobile.png
+0 −0
Binary file not shown.