docs: README v3 — chiffres live vérifiés, pastilles dynamiques, sections complètes
1 changed file +144 −60
modified
README.md
+144 −60
@@ -6,25 +6,46 @@ | ||
| 6 | 6 | <h1 align="center">Lou·Ka</h1> |
| 7 | 7 | <p align="center"><b>Tous les logements à louer</b></p> |
| 8 | 8 | |
| 9 | −<p align="center"> | |
| 10 | − <a href="https://www.lou-ka.com"><img src="https://img.shields.io/website?url=https%3A%2F%2Fwww.lou-ka.com&style=flat-square&label=www.lou-ka.com&up_color=ff6a00&up_message=en%20ligne" alt="Site"></a> | |
| 11 | − <a href="https://www.lou-ka.com/doc/"><img src="https://img.shields.io/badge/📖_documentation-%2Fdoc-ff6a00?style=flat-square" alt="Documentation"></a> | |
| 12 | − <a href="https://www.lou-ka.com/doc/lou-ka-documentation.pdf"><img src="https://img.shields.io/badge/guide-PDF-ff6a00?style=flat-square" alt="PDF"></a> | |
| 13 | − <img src="https://img.shields.io/badge/n%C5%93ud-M3U96b-1f6feb?style=flat-square" alt="Nœud"> | |
| 14 | − <img src="https://img.shields.io/badge/port-8095-141814?style=flat-square" alt="Port"> | |
| 15 | − <img src="https://img.shields.io/badge/process-PM2-2b037a?style=flat-square" alt="PM2"> | |
| 16 | −</p> | |
| 17 | −<p align="center"> | |
| 18 | − <img src="https://img.shields.io/badge/Python-3.14-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python"> | |
| 19 | − <img src="https://img.shields.io/badge/FastAPI-API_+_SSR-009688?style=flat-square&logo=fastapi&logoColor=white" alt="FastAPI"> | |
| 20 | − <img src="https://img.shields.io/badge/React_18-Vite_+_TS-087EA4?style=flat-square&logo=react&logoColor=white" alt="React"> | |
| 21 | − <img src="https://img.shields.io/badge/SQLite-WAL-003B57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite"> | |
| 22 | − <img src="https://img.shields.io/badge/Groupe-KA-ff6a00?style=flat-square" alt="Groupe KA"> | |
| 23 | −</p> | |
| 9 | +<div align="center"> | |
| 10 | + | |
| 11 | +<a href="https://www.lou-ka.com"><img src="https://img.shields.io/website?url=https%3A%2F%2Fwww.lou-ka.com&style=flat-square&label=www.lou-ka.com&up_color=ff6a00&up_message=en%20ligne" alt="Site"></a> | |
| 12 | +<a href="https://www.lou-ka.com/doc/"><img src="https://img.shields.io/badge/📖_documentation-%2Fdoc-ff6a00?style=flat-square" alt="Documentation"></a> | |
| 13 | +<a href="https://www.lou-ka.com/doc/lou-ka-documentation.pdf"><img src="https://img.shields.io/badge/guide-PDF-ff6a00?style=flat-square" alt="PDF"></a> | |
| 14 | +<img src="https://img.shields.io/badge/n%C5%93ud-M3U96b-1f6feb?style=flat-square" alt="Nœud"> | |
| 15 | +<img src="https://img.shields.io/badge/port-8095-141814?style=flat-square" alt="Port"> | |
| 16 | +<img src="https://img.shields.io/badge/process-PM2-2b037a?style=flat-square" alt="PM2"> | |
| 17 | + | |
| 18 | +</div> | |
| 19 | + | |
| 20 | +<div align="center"> | |
| 21 | + | |
| 22 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats&query=%24.total&label=annonces%20actives&color=ff6a00&style=flat-square" alt="Annonces actives (live)"> | |
| 23 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats&query=%24.sources&label=sources%20actives&color=ff6a00&style=flat-square" alt="Sources actives (live)"> | |
| 24 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats%2Fdetailed&query=%24.totals.cities&label=villes&color=ff6a00&style=flat-square" alt="Villes (live)"> | |
| 25 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats%2Fdetailed&query=%24.totals.regions&label=r%C3%A9gions&color=ff6a00&style=flat-square" alt="Régions (live)"> | |
| 26 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats%2Fdetailed&query=%24.totals.median&label=loyer%20m%C3%A9dian&suffix=%20%24&color=ff6a00&style=flat-square" alt="Loyer médian (live)"> | |
| 27 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fstats%2Fdetailed&query=%24.totals.gps_pct&label=g%C3%A9olocalis%C3%A9es&suffix=%20%25&color=ff6a00&style=flat-square" alt="Géolocalisées (live)"> | |
| 28 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fkascores%2Fstats&query=%24.couverture_pct&label=couverture%20KA%20Scores&suffix=%20%25&color=ff6a00&style=flat-square" alt="Couverture KA Scores (live)"> | |
| 29 | +<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.lou-ka.com%2Fapi%2Fct%2Fstats&query=%24.total&label=s%C3%A9jours%20court%20terme&color=ff6a00&style=flat-square" alt="Séjours court terme (live)"> | |
| 30 | + | |
| 31 | +</div> | |
| 32 | + | |
| 33 | +<div align="center"> | |
| 34 | + | |
| 35 | +<img src="https://img.shields.io/badge/Python-3.14-3776AB?style=flat-square&logo=python&logoColor=white" alt="Python"> | |
| 36 | +<img src="https://img.shields.io/badge/FastAPI-API_+_SSR-009688?style=flat-square&logo=fastapi&logoColor=white" alt="FastAPI"> | |
| 37 | +<img src="https://img.shields.io/badge/React_18-Vite_+_TS-087EA4?style=flat-square&logo=react&logoColor=white" alt="React"> | |
| 38 | +<img src="https://img.shields.io/badge/SQLite-WAL-003B57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite"> | |
| 39 | +<img src="https://img.shields.io/badge/Mapbox_GL-ka--maps-000000?style=flat-square&logo=mapbox&logoColor=white" alt="Mapbox GL"> | |
| 40 | +<img src="https://img.shields.io/badge/tunnel-ngrok-1F1E37?style=flat-square&logo=ngrok&logoColor=white" alt="ngrok"> | |
| 41 | +<img src="https://img.shields.io/badge/Groupe-KA-ff6a00?style=flat-square" alt="Groupe KA"> | |
| 42 | +<a href="https://git.spboucher.ai"><img src="https://img.shields.io/badge/remote--first-spbgit-8250df?style=flat-square&logo=git&logoColor=white" alt="spbgit"></a> | |
| 43 | + | |
| 44 | +</div> | |
| 24 | 45 | |
| 25 | 46 | Chercher un appartement au Québec, c'est ouvrir des dizaines de sites différents — chacun avec sa navigation, ses filtres, son format. **Lou·Ka retourne le problème** : un **connecteur dédié par gestionnaire immobilier** visite chaque site, **normalise chaque annonce** vers un schéma unique et **détecte les changements en continu** (synchronisation périodique + hash de contenu → ajouts, mises à jour et retraits automatiques ; une annonce disparue répond `410 Gone`). Chaque fiche renvoie vers l'annonce originale du gestionnaire via une passerelle de sortie transparente (`/passerelle/{uid}`). |
| 26 | 47 | |
| 27 | −Pour qui ? Les locataires qui cherchent (recherche filtrée, carte 3D, fiches complètes), les curieux du marché (observatoire des loyers, rapports PDF) et les gestionnaires (pages réclamables). **En chiffres** : 22 900+ annonces actives, 265 sources recensées, 212 connecteurs, 820 villes, 11 régions, ~70 % des annonces géolocalisées. | |
| 48 | +Pour qui ? Les locataires qui cherchent (recherche filtrée, carte 3D, fiches complètes), les curieux du marché (observatoire des loyers, rapports PDF) et les gestionnaires (pages réclamables). **En chiffres (au 2026-08-24)** : 45 762 annonces actives publiées, 281 sources recensées, 250 connecteurs (221 location long terme + 29 court terme), 1 233 villes, 11 régions, 97,4 % des annonces géolocalisées, loyer médian 1 700 $ — plus **41 460 séjours court terme** (chalets, Airbnb…) dans la section `/court-terme`. | |
| 28 | 49 | |
| 29 | 50 | ## Visite guidée |
| 30 | 51 | |
@@ -82,33 +103,48 @@ Pour qui ? Les locataires qui cherchent (recherche filtrée, carte 3D, fiches co | ||
| 82 | 103 | - **Recherche filtrée** — ville, quartier, type (3½, 4½…), loyer min/max, animaux, meublé, superficie, texte libre. |
| 83 | 104 | - **Vue carte 3D** — Lou-Ka Maps (framework `@groupe-ka/ka-maps`, moteur Mapbox GL JS) : clusters par prix moyen, « Rechercher dans cette zone », bascule 3D/2D, synchro liste ↔ carte. |
| 84 | 105 | - **Fiches complètes** — toutes les photos, digest structuré de la description (text mining regex FR, aucun LLM), badge marché, historique de prix (`price_log`), fiche PDF avec QR code. |
| 85 | −- **Couches de données de quartier** — recensement 2021, registre des loyers, inondation (BDZI), criminalité (SPVM), qualité de l'air, prix de l'essence, commerces et transport en commun, estimation Hydro-Québec, **KA Scores**. | |
| 106 | +- **Couches de données de quartier** — recensement 2021, registre des loyers (57 433 déclarations géocodées), inondation (BDZI), criminalité (SPVM, 12 mois par catégorie), qualité de l'air (RSQAQ/PST), prix de l'essence, commerces et transport en commun (métro/REM aux couleurs officielles), estimation Hydro-Québec live, **KA Scores** (95,5 % du parc couvert au 2026-08-24). | |
| 107 | +- **Location court terme** — section isolée `/court-terme` (sous-système `louka/shortterm/`, API `/api/ct/*`) : chalets, Airbnb (quadrillage carte quadtree limité à la frontière du Québec), Vrbo, Booking… 41 460 séjours, 22 sources actives sur 38 recensées, 27 régions (au 2026-08-24) ; SEO complet (JSON-LD `VacationRental`, sitemaps `sitemap-ct-N.xml`). | |
| 86 | 108 | - **Pages villes SEO** — `/villes`, `/ville/{slug}`, `/ville/{slug}/{type}` en SSR léger, sitemaps dynamiques (chunks de 10 000), JSON-LD (`RealEstateListing` + `Offer` CAD), vrais `404`/`410`. |
| 87 | −- **Observatoire du marché** — KPI temps réel, loyers médians par région/ville/taille, rapport de marché PDF multi-pages (`/api/stats/rapport.pdf`). | |
| 88 | −- **Registre des sources** — chaque gestionnaire, son statut, sa dernière synchro ; toute source non connectable est documentée avec sa raison dans `data/sources.json`. | |
| 109 | +- **Observatoire du marché** — KPI temps réel, loyers médians par région/ville/taille, panneaux territoire (registre des loyers, population, essence), rapport de marché PDF multi-pages (`/api/stats/rapport.pdf`) et rapports PDF personnalisés (catalogue + `ReportBuilder`). | |
| 110 | +- **Registre des sources** — chaque gestionnaire, son statut, sa dernière synchro ; toute source non connectable est documentée avec sa raison dans `data/sources.json` (281 entrées recensées). | |
| 111 | +- **Qualité éditoriale** — porte de pertinence (quarantaine des stationnements, garages, locaux commerciaux, locations à la nuit) : 59 668 annonces publiées / 1 175 en quarantaine, complétude moyenne 91,4 % (au 2026-08-24). | |
| 89 | 112 | - **Comptes & SSO KA** — « Se connecter avec KA » via le hub groupe-ka.com (JWT HS256, `ka_id` émis par le hub) + Google OAuth direct ; favoris synchronisés vers « Mon univers Ka » ; pages gestionnaires réclamables (`/g/{source_id}`). |
| 90 | −- **Widget KA Agent** — bulle de chat IA du Groupe KA intégrée au site. | |
| 113 | +- **Widget KA Agent** — bulle de chat IA du Groupe KA intégrée au site (déplaçable, position mémorisée). | |
| 91 | 114 | - **PWA installable** + app iOS SwiftUI 100 % native (dépôt séparé `lou-ka-ios` sur spbgit). |
| 92 | −- **Robustesse** — garde-fou anti-dérive (`DRIFT_RATIO = 0.25`) : si une source retourne soudainement beaucoup moins d'annonces, les retraits sont suspendus au lieu de vider l'inventaire. | |
| 115 | +- **Robustesse** — garde-fou anti-dérive (`DRIFT_RATIO = 0.25`, `louka/db.py`) : si une source retourne soudainement beaucoup moins d'annonces, les retraits sont suspendus au lieu de vider l'inventaire ; chaîne de fetch anti-bot résiliente (Oxylabs → Scrapfly → Bright Data). | |
| 93 | 116 | |
| 94 | 117 | ## API (endpoints principaux) |
| 95 | 118 | |
| 96 | 119 | Servis par `louka/web.py` (FastAPI) sur le port 8095. |
| 97 | 120 | |
| 98 | −| Endpoint | Rôle | | |
| 99 | −|---|---| | |
| 100 | −| `GET /api/search` | recherche unifiée liste ↔ carte (mêmes filtres, même compteur) | | |
| 101 | −| `GET /api/listings` · `GET /api/listings/{uid}` | annonces paginées + fiche détaillée (`410 Gone` si retirée) | | |
| 102 | −| `GET /api/listings.geojson` | flux GeoJSON pour la carte 3D | | |
| 103 | −| `GET /api/listings/{uid}/pdf` | fiche PDF avec QR code | | |
| 104 | −| `GET /api/facets` · `GET /api/sources` | facettes de filtres, registre des sources | | |
| 105 | −| `GET /api/fairvalue/{uid}` | badge marché (juste prix) d'une annonce | | |
| 106 | −| `GET /api/rdl` · `/api/inondation` · `/api/air` · `/api/gaz` · `/api/commerces` · `/api/hydro` | couches de quartier : registre des loyers, BDZI, qualité de l'air, essence, commerces/transport, estimation Hydro-Québec | | |
| 107 | −| `GET /api/kascores/stats` | statistiques du moteur KA Scores | | |
| 108 | −| `GET /api/stats` · `/detailed` · `/dashboard` · `/report` · `/catalog` · `POST /api/stats/report/custom` | observatoire + rapports PDF (catalogue et personnalisés) | | |
| 109 | −| `GET /api/stats/rapport.pdf` | rapport de marché PDF multi-pages | | |
| 110 | −| `POST /api/sync` | déclenchement d'une synchronisation | | |
| 111 | −| `GET /doc/` | guide d'utilisation en ligne | | |
| 121 | +### Location long terme | |
| 122 | + | |
| 123 | +| Méthode | Endpoint | Rôle | | |
| 124 | +|---|---|---| | |
| 125 | +| `GET` | `/api/search` | recherche unifiée liste ↔ carte (mêmes filtres, même compteur) | | |
| 126 | +| `GET` | `/api/listings` · `/api/listings/{uid}` | annonces paginées + fiche détaillée (`410 Gone` si retirée) | | |
| 127 | +| `GET` | `/api/listings.geojson` | flux GeoJSON pour la carte 3D | | |
| 128 | +| `GET` | `/api/listings/{uid}/pdf` | fiche PDF avec QR code | | |
| 129 | +| `GET` | `/api/facets` · `/api/sources` | facettes de filtres, registre des sources | | |
| 130 | +| `GET` | `/api/fairvalue/{uid}` | badge marché (juste prix) d'une annonce | | |
| 131 | +| `GET` | `/api/rdl` · `/api/inondation` · `/api/air` · `/api/gaz` · `/api/commerces` · `/api/hydro` | couches de quartier : registre des loyers, BDZI, qualité de l'air, essence, commerces/transport, estimation Hydro-Québec | | |
| 132 | +| `GET` | `/api/kascores/stats` | statistiques du moteur KA Scores | | |
| 133 | +| `GET` | `/api/stats` · `/detailed` · `/dashboard` · `/report` · `/catalog` | observatoire : KPI, détail, tableau de bord, rapports | | |
| 134 | +| `POST` | `/api/stats/report/custom` | rapport PDF personnalisé (ReportBuilder) | | |
| 135 | +| `GET` | `/api/stats/rapport.pdf` | rapport de marché PDF multi-pages | | |
| 136 | +| `POST` | `/api/sync` | déclenchement d'une synchronisation | | |
| 137 | +| `GET` | `/doc/` | guide d'utilisation en ligne | | |
| 138 | + | |
| 139 | +### Location court terme (`/api/ct`, préfixe du sous-système `louka/shortterm/`) | |
| 140 | + | |
| 141 | +| Méthode | Endpoint | Rôle | | |
| 142 | +|---|---|---| | |
| 143 | +| `GET` | `/api/ct/listings` · `/api/ct/listings/{uid}` | séjours paginés + fiche détaillée | | |
| 144 | +| `GET` | `/api/ct/listings.geojson` | flux GeoJSON de la carte court terme | | |
| 145 | +| `GET` | `/api/ct/facets` · `/api/ct/sources` | facettes, registre des sources court terme | | |
| 146 | +| `GET` | `/api/ct/stats` | KPI court terme (total, sources, régions, prix/nuit) | | |
| 147 | +| `POST` | `/api/ct/sync` | déclenchement d'une synchronisation court terme | | |
| 112 | 148 | |
| 113 | 149 | ## Architecture |
| 114 | 150 | |
@@ -116,36 +152,96 @@ Pipeline : **connecteurs → normalisation → déduplication → SQLite → API | ||
| 116 | 152 | |
| 117 | 153 | - **Backend Python 3.14 / FastAPI / Uvicorn** (`louka/web.py`) : API JSON + service du build Vite + SSR SEO (`louka/seo.py`). |
| 118 | 154 | - **SQLite (WAL)** (`louka/db.py`) : migrations auto, upsert par hash de contenu, anti-dérive ; bases annexes dans `data/` (quartier, air, gaz, hydro, commerces, inondation…). |
| 119 | −- **212 connecteurs** auto-découverts (`louka/connectors/`), extraction directe / Firecrawl / Scrapfly selon la source. | |
| 155 | +- **250 connecteurs** auto-découverts : 221 long terme (`louka/connectors/`) + 29 court terme (`louka/shortterm/connectors/`), extraction directe / Firecrawl / Scrapfly / Bright Data / acteurs Apify maison selon la source. | |
| 120 | 156 | - **Enrichissement** : géocodage (Nominatim + Adresses Québec), POI OSM, stats de quartier, KA Scores, estimation Hydro-Québec. |
| 121 | 157 | - **Frontend React 18 + Vite + TypeScript** (`frontend/`), cartographie `@groupe-ka/ka-maps` (Mapbox GL). |
| 122 | −- **CLI `run.py`** : `sync` · `watch` · `serve` · `geocode` · `poi` · `quartier` · `record` (fixtures HTTP pour tests hors-ligne). | |
| 158 | +- **CLI `run.py`** : `sync` · `watch` · `sync-ct` · `watch-ct` · `serve` · `geocode` · `quality` · `imgaudit` · `fairvalue` · `poi` · `quartier` · `kascores` · `rdl` · `air-refresh` · `gaz-refresh` · `hydro-precompute` · `record` (fixtures HTTP pour tests hors-ligne). | |
| 123 | 159 | |
| 124 | 160 | Processus PM2 sur le nœud : |
| 125 | 161 | |
| 126 | −| Processus | Rôle | Cadence | | |
| 127 | −|---|---|---| | |
| 128 | −| `lou-ka-web` | serveur FastAPI/Uvicorn (API + frontend + SSR) sur le port **8095** | continu | | |
| 129 | −| `lou-ka-sync` | boucle de resynchronisation des connecteurs (`run.py watch 60`) | cycle de 60 min | | |
| 130 | −| `lou-ka-ngrok` | tunnel ngrok vers **www.lou-ka.com** | continu | | |
| 162 | +| Processus | Commande réelle | Rôle | Cadence | | |
| 163 | +|---|---|---|---| | |
| 164 | +| `lou-ka-web` | `.venv/bin/python run.py serve 8095` | serveur FastAPI/Uvicorn (API + frontend + SSR) sur le port **8095** | continu | | |
| 165 | +| `lou-ka-sync` | `.venv/bin/python run.py watch 60` | boucle de resynchronisation des connecteurs long terme | cycle de 60 min | | |
| 166 | +| `lou-ka-ngrok` | `ngrok http --url=www.lou-ka.com 8095` | tunnel ngrok vers **www.lou-ka.com** | continu | | |
| 167 | + | |
| 168 | +La section court terme se resynchronise via `run.py watch-ct` (défaut 360 min) ou à la demande (`run.py sync-ct`, `POST /api/ct/sync`). | |
| 169 | + | |
| 170 | +## Démarrage rapide | |
| 131 | 171 | |
| 132 | −Points de configuration notables (variables d'environnement, sans secrets dans le repo) : clés Scrapfly/Firecrawl pour certains connecteurs, jeton Mapbox du frontend, secret SSO partagé avec le hub KA ID. Le registre des sources vit dans `data/sources.json` ; les bases SQLite de prod sont gitignorées. | |
| 172 | +```bash | |
| 173 | +# Backend (Python 3.14) | |
| 174 | +python3 -m venv .venv && .venv/bin/pip install -r requirements.txt | |
| 175 | + | |
| 176 | +# Frontend (nécessite le framework ka-maps bâti à côté : ../ka-maps) | |
| 177 | +cd frontend && npm install && npm run build && cd .. | |
| 178 | + | |
| 179 | +.venv/bin/python run.py sync # ingestion (toutes les sources ou une liste) | |
| 180 | +.venv/bin/python run.py sync-ct # ingestion court terme | |
| 181 | +.venv/bin/python run.py serve 8095 # API + frontend sur http://localhost:8095 | |
| 182 | +.venv/bin/python run.py watch 60 # resynchronisation en boucle (minutes) | |
| 183 | + | |
| 184 | +# Tests (pytest + fixtures HTTP rejouables hors-ligne) | |
| 185 | +.venv/bin/python -m pytest tests/ | |
| 186 | +``` | |
| 187 | + | |
| 188 | +En développement frontend : `cd frontend && npm run dev` (Vite sur `:5173`, proxy `/api`). | |
| 189 | + | |
| 190 | +## Variables d'environnement | |
| 191 | + | |
| 192 | +Aucun secret dans le repo — tout passe par l'environnement du nœud. Noms attendus : | |
| 193 | + | |
| 194 | +| Variable | Rôle | | |
| 195 | +|---|---| | |
| 196 | +| `SCRAPFLY_KEY` · `FIRECRAWL_API_KEY` · `APIFY_TOKEN` | extraction anti-bot / rendu / acteurs Apify maison | | |
| 197 | +| `BRIGHTDATA_API_KEY` · `BRIGHTDATA_ZONE` | Web Unlocker Bright Data (repli anti-bot) | | |
| 198 | +| `OXYLABS_PROXY` · `OXYLABS_PROXY_USER` · `OXYLABS_PROXY_PASS` | proxies résidentiels (1er maillon de la chaîne de fetch) | | |
| 199 | +| `GOOGLE_CLIENT_ID` · `GOOGLE_CLIENT_SECRET` | connexion Google OAuth directe | | |
| 200 | +| `KA_SSO_SECRET` · `KA_HUB_URL` · `SESSION_SECRET` | SSO KA ID (JWT HS256 partagé avec groupe-ka.com) + sessions | | |
| 201 | +| `HQ_CAPTCHA_PROVIDER` · `HQ_CAPTCHA_KEY` | résolution reCAPTCHA de l'estimation Hydro-Québec | | |
| 202 | +| `LOUKA_BASE_URL` | URL publique de base (liens PDF, sitemaps) | | |
| 203 | +| `LOUKA_<SOURCE>_*` (≈70 variables) | tuning par connecteur : limites de détail, TTL, pages max, cadence (ex. `LOUKA_KIJIJI_DETAIL_LIMIT`, `LOUKA_FBMP_CITIES`, `LOUKA_AIRBNB_BUDGET`) | | |
| 204 | +| `VITE_MAPBOX_TOKEN` (frontend) | jeton public Mapbox de la carte 3D | | |
| 205 | + | |
| 206 | +## Données & conformité | |
| 207 | + | |
| 208 | +- **Agrégateur indépendant** : aucune affiliation avec les gestionnaires immobiliers ; chaque fiche renvoie vers l'annonce originale via la passerelle de sortie transparente `/passerelle/{uid}` (mention affichée au pied du site). | |
| 209 | +- **Provenance** : sites publics des gestionnaires et portails d'annonces (281 sources recensées dans `data/sources.json`, statut et raison documentés pour chaque source non connectable) ; couches de quartier issues de données ouvertes (recensement 2021, registre des loyers, BDZI, SPVM, RSQAQ, Régie de l'énergie, OSM). | |
| 210 | +- **Cadence** : resynchronisation long terme en boucle de 60 min (`lou-ka-sync`), court terme par cycles de 360 min ; détection de changement par hash de contenu → ajouts, mises à jour et retraits automatiques. | |
| 211 | +- **Cycle de vie honnête** : une annonce retirée chez la source répond `410 Gone` et sort des sitemaps ; le garde-fou anti-dérive suspend les retraits massifs suspects plutôt que de vider l'inventaire. | |
| 212 | +- **Qualité** : porte de pertinence (quarantaine du hors-périmètre : stationnements, commerciaux, nuitées) et score de complétude par annonce (moyenne 91,4 %). | |
| 133 | 213 | |
| 134 | 214 | ## Structure du repo |
| 135 | 215 | |
| 136 | 216 | ``` |
| 137 | 217 | lou-ka/ |
| 138 | −├── run.py # point d'entrée CLI (sync / watch / serve / geocode / poi / quartier / record) | |
| 139 | −├── louka/ # paquet backend : web, seo, db, ingest, normalize, textmine, auth, kascores… + connectors/ (212) | |
| 218 | +├── run.py # point d'entrée CLI (sync / watch / sync-ct / watch-ct / serve / geocode / poi / quartier / record) | |
| 219 | +├── louka/ # paquet backend : web, seo, db, ingest, normalize, textmine, auth, kascores… | |
| 220 | +│ ├── connectors/ # 221 connecteurs long terme auto-découverts | |
| 221 | +│ └── shortterm/ # sous-système court terme isolé (db, ingest, web + 29 connecteurs) | |
| 140 | 222 | ├── frontend/ # React 18 + Vite + TypeScript (pages, composants, kamaps/) + public/doc/ (guide) |
| 141 | −├── data/ # sources.json (registre) + bases SQLite de prod (gitignorées) | |
| 142 | −├── scripts/ # build recensement/contexte/environnement, screenshots, check-order | |
| 223 | +├── data/ # sources.json (registre, 281 entrées) + bases SQLite de prod (gitignorées) | |
| 224 | +├── scripts/ # build recensement/contexte/environnement, docs connecteurs, screenshots, check-order | |
| 143 | 225 | ├── tests/ # pytest + fixtures HTTP rejouables hors-ligne |
| 144 | −├── actors/ # acteurs Apify d'appoint | |
| 226 | +├── actors/ # acteurs Apify d'appoint (ka-fb-marketplace, ka-apartments-com…) | |
| 145 | 227 | ├── reports/ # audits (fiches connecteurs, expansion par région, quartier…) |
| 146 | 228 | └── docs/ # captures d'écran + docs connecteurs + ka-maps |
| 147 | 229 | ``` |
| 148 | 230 | |
| 231 | +## Historique | |
| 232 | + | |
| 233 | +Repère des jalons (128 commits depuis la naissance) : | |
| 234 | + | |
| 235 | +| Date | Jalon | | |
| 236 | +|---|---| | |
| 237 | +| 2026-08-06 | naissance du projet : agrégateur Québec/Lévis/Grand Montréal, page Statistiques (`fb48938`, `ece6ed0`) | | |
| 238 | +| 2026-08-08 | Mission 1a — couche commune : schéma enrichi, normalisation centrale, robustesse, tests (`7323079`) | | |
| 239 | +| 2026-08-19 | KA Scores calculés sur 94,7 % du parc + standard « ordre des sections = ordre du DOM » (`747f631`, `a6e30ef`) | | |
| 240 | +| 2026-08-21→22 | porte de pertinence (quarantaine hors-périmètre) + chaîne de fetch anti-bot Oxylabs→Scrapfly→Bright Data + acteurs Apify maison FB Marketplace / Apartments.com (`8547737`, `8598785`, `e7f4876`) | | |
| 241 | +| 2026-08-22→23 | section « Location court terme » : sous-système isolé, Airbnb en quadrillage carte, 38 sources recensées, SEO complet (`38b708b`, `5c571bc`, `63456a0`) | | |
| 242 | +| 2026-08-23 | couches de quartier : registre des loyers (57 433 déclarations), inondation BDZI, criminalité SPVM, air, essence, commerces/transport, estimation Hydro-Québec live + rapports PDF personnalisés (`604455e` → `4d17c17`, `834c92c`) | | |
| 243 | +| 2026-08-24 | page documentation `/doc` + guide PDF + README v2/v3 (`963ba8f`, `4fa8714`) | | |
| 244 | + | |
| 149 | 245 | ## Documentation |
| 150 | 246 | |
| 151 | 247 | - **Guide en ligne** : [www.lou-ka.com/doc/](https://www.lou-ka.com/doc/) — à quoi sert le site, le parcours en 4 étapes (recherche → résultats → fiche → /stats), d'où viennent les données, FAQ. |
@@ -160,21 +256,9 @@ lou-ka/ | ||
| 160 | 256 | - L'agent forwarding SSH est actif : le `git push origin main` fonctionne pendant une session SSH depuis le laptop. |
| 161 | 257 | |
| 162 | 258 | ```bash |
| 163 | −# Backend | |
| 164 | −python3 -m venv .venv && .venv/bin/pip install -r requirements.txt | |
| 165 | − | |
| 166 | −# Frontend (nécessite le framework ka-maps bâti à côté : ../ka-maps) | |
| 167 | −cd frontend && npm install && npm run build && cd .. | |
| 168 | − | |
| 169 | −.venv/bin/python run.py sync # ingestion (toutes les sources ou une liste) | |
| 170 | −.venv/bin/python run.py serve 8095 # API + frontend | |
| 171 | −.venv/bin/python run.py watch 60 # resynchronisation en boucle (minutes) | |
| 172 | − | |
| 173 | 259 | pm2 restart lou-ka-web # après un changement en production |
| 174 | 260 | ``` |
| 175 | 261 | |
| 176 | −En développement frontend : `cd frontend && npm run dev` (Vite sur `:5173`, proxy `/api`). | |
| 177 | − | |
| 178 | 262 | ## Déploiement |
| 179 | 263 | |
| 180 | 264 | - **Nœud** : M3U96b (Mac Studio, cluster MacLustr) — répertoire `~/apps/lou-ka` |
| 181 | 265 | |