docs: refonte du README (pastilles + captures d écran à jour)
3 changed files +90 −191
modified
README.md
+90 −191
@@ -1,227 +1,126 @@ | ||
| 1 | +<!-- Auteur : Simon-Pierre Boucher — contact@spboucher.ai --> | |
| 2 | + | |
| 1 | 3 | # Lou·Ka |
| 2 | 4 | |
| 3 | −### Tous les **logements à louer du Québec**. Un seul endroit. | |
| 5 | +**Tous les logements à louer du Québec, agrégés au même endroit — un index fidèle, sans prix inventé ni coordonnée devinée.** | |
| 4 | 6 | |
| 5 | −**[www.lou-ka.com](https://www.lou-ka.com)** — un service **[Groupe Ka](https://www.groupe-ka.com)** | |
| 7 | +[](https://www.lou-ka.com) | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 6 | 11 | |
| 7 | − | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 8 | 17 | |
| 9 | − | |
| 10 | − | |
| 11 | − | |
| 12 | − | |
| 13 | − | |
| 14 | − | |
| 18 | +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}`). | |
| 15 | 19 | |
| 16 | − | |
| 17 | − | |
| 18 | − | |
| 19 | − | |
| 20 | − | |
| 21 | − | |
| 20 | +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. | |
| 22 | 21 | |
| 23 | −--- | |
| 22 | +## Captures d'écran | |
| 24 | 23 | |
| 25 | −## Description | |
| 24 | +<p align="center"> | |
| 25 | + <img src="docs/screenshots/lou-ka-desktop.png" width="640" alt="Accueil — desktop"> | |
| 26 | + <img src="docs/screenshots/lou-ka-mobile.png" width="200" alt="Accueil — mobile"> | |
| 27 | +</p> | |
| 26 | 28 | |
| 27 | −Chercher un appartement au Québec, c'est ouvrir des dizaines de sites web 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**. | |
| 29 | +## Fonctionnalités | |
| 28 | 30 | |
| 29 | −Lou-Ka n'est pas une plateforme d'annonces : c'est un **index fidèle** et un **agrégateur indépendant** de logements locatifs. **Aucun prix inventé**, **aucune coordonnée devinée**, et chaque fiche renvoie vers **l'annonce originale du gestionnaire** via une passerelle de sortie transparente (`/passerelle/{uid}`). | |
| 31 | +- **Recherche filtrée** — ville, quartier, type (3½, 4½…), loyer min/max, animaux, meublé, superficie, texte libre. | |
| 32 | +- **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. | |
| 33 | +- **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. | |
| 34 | +- **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**. | |
| 35 | +- **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`. | |
| 36 | +- **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`). | |
| 37 | +- **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`. | |
| 38 | +- **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}`). | |
| 39 | +- **Widget KA Agent** — bulle de chat IA du Groupe KA intégrée au site. | |
| 40 | +- **PWA installable** + app iOS SwiftUI 100 % native (dépôt séparé `lou-ka-ios` sur spbgit). | |
| 41 | +- **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. | |
| 30 | 42 | |
| 31 | −> Les sites d'agences n'offrent pas de webhooks. Lou-Ka reproduit l'équivalent : **synchronisation périodique + hash de contenu** → ajouts, mises à jour et retraits détectés automatiquement. Une annonce qui disparaît du site source disparaît de Lou-Ka (et répond **`410 Gone`** aux moteurs de recherche). | |
| 43 | +## Architecture | |
| 32 | 44 | |
| 33 | −**En chiffres** : **22 900+ annonces actives**, **275 sources recensées**, **212 connecteurs**, **820 villes**, **11 régions**, **~70 %** des annonces géolocalisées. | |
| 45 | +Pipeline : **connecteurs → normalisation → déduplication → SQLite → API/SSR/frontend**. | |
| 34 | 46 | |
| 35 | −## Fonctionnalités | |
| 47 | +- **Backend Python 3.14 / FastAPI / Uvicorn** (`louka/web.py`) : API JSON + service du build Vite + SSR SEO (`louka/seo.py`). | |
| 48 | +- **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…). | |
| 49 | +- **212 connecteurs** auto-découverts (`louka/connectors/`), extraction directe / Firecrawl / Scrapfly selon la source. | |
| 50 | +- **Enrichissement** : géocodage (Nominatim + Adresses Québec), POI OSM, stats de quartier, KA Scores, estimation Hydro-Québec. | |
| 51 | +- **Frontend React 18 + Vite + TypeScript** (`frontend/`), cartographie `@groupe-ka/ka-maps` (Mapbox GL). | |
| 52 | +- **CLI `run.py`** : `sync` · `watch` · `serve` · `geocode` · `poi` · `quartier` · `record` (fixtures HTTP pour tests hors-ligne). | |
| 53 | + | |
| 54 | +Processus PM2 sur le nœud : | |
| 36 | 55 | |
| 37 | −- **Recherche filtrée** — ville, quartier, type (**3½**, 4½…), loyer min/max, animaux, meublé, superficie, texte libre. | |
| 38 | −- **Vue carte 3D** — **Lou-Ka Maps** (framework **`@groupe-ka/ka-maps`**, moteur **Mapbox GL JS**) : clusters par prix moyen, « Rechercher dans cette zone », caméra partageable dans l'URL, bascule **3D/2D**, synchro liste ↔ carte. | |
| 39 | −- **Fiches complètes** — **toutes les photos**, digest structuré de la description (**text mining regex FR, aucun LLM**), badge marché, **historique de prix** (`price_log`), bloc « **Le quartier** » (recensement 2021, INSPQ, SPVM, écoles MEQ, POI OSM), **fiche PDF** avec QR code. | |
| 40 | −- **Pages villes SEO** — `/villes`, `/ville/{slug}`, `/ville/{slug}/{type}` avec **SSR léger**, sitemaps dynamiques (chunks de **10 000**), **JSON-LD** (`RealEstateListing` + `Offer` CAD), vrais `404`/`410`. | |
| 41 | −- **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`). | |
| 42 | −- **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`. | |
| 43 | −- **Comptes & SSO KA** — « **Se connecter avec KA** » via le hub **groupe-ka.com** (JWT HS256, audience `lou-ka`, **`ka_id`** émis par le hub) + **Google OAuth** direct ; favoris synchronisés vers « Mon univers Ka » ; pages gestionnaires réclamables (`/g/{source_id}`) ; profil public **opt-in** `/u/{ka_id}`. | |
| 44 | −- **Widget KA Agent** — bulle de chat IA du Groupe Ka intégrée au site. | |
| 45 | −- **PWA mobile-first** installable + **app iOS SwiftUI 100 % native** (iOS 17+, TestFlight, dépôt séparé `git.spboucher.ai/lou-ka-ios`) avec moteur de recommandation **on-device**. | |
| 46 | −- **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. | |
| 47 | − | |
| 48 | −### Visite guidée | |
| 49 | − | |
| 50 | −| | | | |
| 51 | −|:---:|:---:| | |
| 52 | −| **Recherche filtrée** | **Vue carte Lou-Ka Maps** | | |
| 53 | −| <img src="docs/screenshots/annonces.jpg" alt="Grille d'annonces" width="440"> | <img src="docs/screenshots/carte.jpg" alt="Vue carte Lou-Ka Maps" width="440"> | | |
| 54 | −| **Fiche complète** | **Pages villes (SEO)** | | |
| 55 | −| <img src="docs/screenshots/fiche-logement.jpg" alt="Fiche d'un logement" width="440"> | <img src="docs/screenshots/ville-quebec.jpg" alt="Page ville Québec" width="440"> | | |
| 56 | −| **Observatoire du marché** | **Registre des sources** | | |
| 57 | −| <img src="docs/screenshots/stats.png" alt="Page stats" width="440"> | <img src="docs/screenshots/sources.png" alt="Registre des sources" width="440"> | | |
| 58 | − | |
| 59 | −## Stack technique | |
| 60 | − | |
| 61 | −| Couche | Technologies | Fichiers | | |
| 62 | −|---|---|---| | |
| 63 | −| **Backend** | **Python 3.14**, **FastAPI**, uvicorn, **SQLite** (migrations auto, upsert par hash), reportlab/**fpdf2** (PDF) — **8 dépendances** | `louka/` | | |
| 64 | −| **Connecteurs** | **205 modules auto-découverts** (`pkgutil.iter_modules`) : HTML, API JSON internes (Building Stack, RealVuu, Planpoint, Rentsync, source.immo, WordPress REST…), **Firecrawl** (Cloudflare), **Scrapfly** (anti-bot) | `louka/connectors/*.py` | | |
| 65 | −| **Text mining** | digest déterministe des descriptions — regex FR, **< 5 ms/annonce**, **aucun LLM** | `louka/textmine.py` | | |
| 66 | −| **Géocodage** | **Nominatim** (1 req/s) + **Adresses Québec** (MERN ArcGIS, mode **EN LOT** de 200) validé par bounding box provinciale | `louka/geocode.py` | | |
| 67 | −| **Frontend** | **React 18 + Vite + TypeScript**, design « éditorial sharp » Groupe Ka (Space Grotesk, accent), **PWA** | `frontend/` | | |
| 68 | −| **Cartographie** | **`@groupe-ka/ka-maps`** — framework partagé du Groupe Ka, **Mapbox GL JS** style Standard **3D**, monté en `React.lazy` | `frontend/src/kamaps/` | | |
| 69 | −| **SEO** | SSR léger FastAPI, sitemaps dynamiques, JSON-LD, hreflang, GZip, `/assets` immuable 1 an | `louka/seo.py` | | |
| 70 | −| **iOS** | **SwiftUI natif** (iOS 17+, zéro dépendance externe), TestFlight | dépôt séparé | | |
| 71 | −| **Prod** | **PM2** (3 processus) + **ngrok** sur le nœud **M3U96b** | — | | |
| 72 | − | |
| 73 | −## Structure du dépôt | |
| 56 | +| Processus | Rôle | | |
| 57 | +|---|---| | |
| 58 | +| `lou-ka-web` | serveur FastAPI/Uvicorn (API + frontend + SSR) sur le port **8095** | | |
| 59 | +| `lou-ka-sync` | boucle de resynchronisation des connecteurs (`run.py watch`) | | |
| 60 | +| `lou-ka-ngrok` | tunnel ngrok vers **www.lou-ka.com** | | |
| 61 | + | |
| 62 | +## Structure du repo | |
| 74 | 63 | |
| 75 | 64 | ``` |
| 76 | 65 | lou-ka/ |
| 77 | −├── run.py # point d'entrée CLI (sync / watch / serve / geocode / poi / quartier / record) | |
| 78 | −├── requirements.txt # 8 dépendances backend (FastAPI, uvicorn, bs4, reportlab, fpdf2…) | |
| 79 | −├── louka/ # paquet backend (Python 3.14) | |
| 80 | −│ ├── web.py # app FastAPI : API JSON + service du build Vite | |
| 81 | −│ ├── seo.py # SSR léger, pages programmatiques, sitemaps, robots, JSON-LD | |
| 82 | −│ ├── db.py # SQLite : migrations auto, upsert par hash, anti-dérive | |
| 83 | −│ ├── schema.py # dataclass Listing | |
| 84 | −│ ├── normalize.py # normalisation (prix, dates ISO, types d'unités, adresses) | |
| 85 | −│ ├── textmine.py # digest déterministe des descriptions (regex FR) | |
| 86 | −│ ├── ingest.py # pipeline sync / watch | |
| 87 | −│ ├── auth.py # SSO KA + Google OAuth, sessions HMAC-SHA256 (cookie httpOnly 30 j) | |
| 88 | −│ ├── accounts.py # rôles, favoris, réclamation de page gestionnaire | |
| 89 | −│ ├── profile.py / hubprofile.py / hubfav.py # profils & intégration hub Groupe Ka | |
| 90 | −│ ├── geocode.py # Nominatim + Adresses Québec (mode EN LOT) | |
| 91 | −│ ├── poi.py / quartier.py # commodités OSM, stats de quartier | |
| 92 | −│ ├── marketstats.py # agrégats du marché (source unique stats/API/PDF) | |
| 93 | −│ ├── pdfgen.py # fiches PDF + rapport de marché (QR code) | |
| 94 | −│ ├── fixtures.py # enregistrement/rejeu HTTP pour tests hors-ligne | |
| 95 | −│ └── connectors/ # 212 connecteurs + base.py (auto-découverte) | |
| 96 | −├── frontend/ # React 18 + Vite + TypeScript (pages, composants, kamaps/) | |
| 97 | −├── data/ | |
| 98 | −│ ├── sources.json # registre des 265 sources (statut + raison si non connectable) | |
| 99 | −│ ├── louka.db # base de production (gitignorée) | |
| 100 | −│ └── quartier.db # base statique de quartier (gitignorée) | |
| 101 | −├── scripts/ # build_recensement / build_contexte / build_environnement / merge_quartier / screenshots.mjs | |
| 102 | −├── tests/ # pytest + fixtures HTTP rejouables hors-ligne | |
| 103 | −├── reports/ # audits : fiches connecteurs, expansion par région, quartier… | |
| 104 | −└── docs/ # screenshot.png, screenshots/, ka-maps-lou-ka.md | |
| 66 | +├── run.py # point d'entrée CLI (sync / watch / serve / geocode / poi / quartier / record) | |
| 67 | +├── louka/ # paquet backend : web, seo, db, ingest, normalize, textmine, auth, kascores… + connectors/ (212) | |
| 68 | +├── frontend/ # React 18 + Vite + TypeScript (pages, composants, kamaps/) | |
| 69 | +├── data/ # sources.json (registre) + bases SQLite de prod (gitignorées) | |
| 70 | +├── scripts/ # build recensement/contexte/environnement, screenshots, check-order | |
| 71 | +├── tests/ # pytest + fixtures HTTP rejouables hors-ligne | |
| 72 | +├── actors/ # acteurs Apify d'appoint | |
| 73 | +├── reports/ # audits (fiches connecteurs, expansion par région, quartier…) | |
| 74 | +└── docs/ # captures d'écran + docs connecteurs + ka-maps | |
| 105 | 75 | ``` |
| 106 | 76 | |
| 107 | −## Démarrage local | |
| 77 | +## Développement (remote-first) | |
| 108 | 78 | |
| 109 | −```bash | |
| 110 | −git clone https://git.spboucher.ai/lou-ka.git && cd lou-ka | |
| 79 | +**La source de vérité est le repo git sur le nœud M3U96b** (`~/apps/lou-ka`) — on n'édite jamais les copies laptop. Toute modification se fait sur le nœud via SSH : édition, build, `pm2 restart`, puis commit/push depuis le nœud. | |
| 111 | 80 | |
| 81 | +- Remote `origin` = **spbgit** (git perso [git.spboucher.ai](https://git.spboucher.ai), bare repos sur M3U96a). **Pas GitHub.** | |
| 82 | +- L'agent forwarding SSH est actif : le `git push origin main` fonctionne pendant une session SSH depuis le laptop. | |
| 83 | + | |
| 84 | +```bash | |
| 112 | 85 | # Backend |
| 113 | 86 | python3 -m venv .venv && .venv/bin/pip install -r requirements.txt |
| 114 | 87 | |
| 115 | 88 | # Frontend (nécessite le framework ka-maps bâti à côté : ../ka-maps) |
| 116 | 89 | cd frontend && npm install && npm run build && cd .. |
| 117 | 90 | |
| 118 | −# (optionnel) sites JavaScript / anti-bot | |
| 119 | −cat > .env <<EOF | |
| 120 | −FIRECRAWL_API_KEY=fc-votre-cle | |
| 121 | −SCRAPFLY_KEY=votre-cle | |
| 122 | −EOF | |
| 91 | +.venv/bin/python run.py sync # ingestion (toutes les sources ou une liste) | |
| 92 | +.venv/bin/python run.py serve 8095 # API + frontend | |
| 93 | +.venv/bin/python run.py watch 60 # resynchronisation en boucle (minutes) | |
| 123 | 94 | |
| 124 | −# Ingestion puis service | |
| 125 | −.venv/bin/python run.py sync # toutes les sources (ou : run.py sync logisco msi) | |
| 126 | −.venv/bin/python run.py serve 8080 # → http://localhost:8080 | |
| 127 | −.venv/bin/python run.py watch 60 # resynchronisation en boucle (minutes) | |
| 95 | +pm2 restart lou-ka-web # après un changement en production | |
| 128 | 96 | ``` |
| 129 | 97 | |
| 130 | −En développement frontend : `cd frontend && npm run dev` (**Vite sur `:5173`**, proxy `/api` → `:8080`). | |
| 131 | − | |
| 132 | −### CLI `run.py` | |
| 133 | − | |
| 134 | −| Commande | Rôle | | |
| 135 | −|---|---| | |
| 136 | −| **`run.py sync [source ...]`** | ingestion — toutes les sources ou une liste | | |
| 137 | −| **`run.py watch [minutes]`** | boucle de resynchronisation (défaut **60**) | | |
| 138 | −| **`run.py serve [port]`** | uvicorn `louka.web:app` (défaut **8080**) | | |
| 139 | −| **`run.py geocode [n]`** | géocodage **en lot** (Adresses Québec, lots de 200) | | |
| 140 | −| **`run.py geocode1 [n]`** | géocodage un-par-un (Nominatim, 1 req/s) | | |
| 141 | −| **`run.py poi [n]`** | commodités OSM à proximité (Overpass) | | |
| 142 | −| **`run.py quartier [n]`** | enrichissement quartier (recensement, INSPQ, SPVM) | | |
| 143 | −| **`run.py record <source>`** | (ré)enregistre les fixtures HTTP d'un connecteur | | |
| 144 | − | |
| 145 | −### Variables d'environnement | |
| 146 | − | |
| 147 | −`run.py` charge **`.env`** à la racine (parsing maison, aucune dépendance). | |
| 148 | − | |
| 149 | −| Variable | Rôle | | |
| 150 | −|---|---| | |
| 151 | −| **`FIRECRAWL_API_KEY`** | rendu JavaScript / contournement Cloudflare (optionnel) | | |
| 152 | −| **`SCRAPFLY_KEY`** | scraping anti-bot ASP (optionnel) | | |
| 153 | −| **`SESSION_SECRET`** | signature HMAC des sessions | | |
| 154 | −| **`GOOGLE_CLIENT_ID`** / **`GOOGLE_CLIENT_SECRET`** | connexion Google OAuth | | |
| 155 | −| **`KA_SSO_SECRET`** | secret partagé du SSO KA (JWT HS256) | | |
| 156 | −| **`KA_HUB_URL`** | hub Groupe Ka (défaut `https://www.groupe-ka.com`) | | |
| 157 | −| **`LOUKA_BASE_URL`** | URL publique (derrière ngrok/proxy) | | |
| 158 | −| `LOUKA_*_DETAIL_LIMIT` / `LOUKA_*_MAX_PAGES` | limites par portail (Kijiji, LesPAC, RE/MAX…) | | |
| 159 | −| **`VITE_MAPBOX_TOKEN`** | jeton Mapbox du frontend (repli public codé en dur) | | |
| 160 | − | |
| 161 | −### Tests | |
| 162 | − | |
| 163 | −```bash | |
| 164 | −.venv/bin/python -m pytest | |
| 165 | −``` | |
| 166 | − | |
| 167 | −Chaque connecteur est rejoué **hors-ligne** contre ses fixtures HTTP enregistrées (`tests/fixtures/<source>/` + `expected.json`) ; la normalisation et le text mining ont leurs suites dédiées. | |
| 168 | − | |
| 169 | −## API (aperçu) | |
| 170 | − | |
| 171 | −| Endpoint | Description | | |
| 172 | −|---|---| | |
| 173 | −| **`GET /api/listings`** | recherche filtrée : `city, sector, unit_type, source, price_min/max, pets, furnished, available_by, area_min, q, limit, offset` | | |
| 174 | −| **`GET /api/listings.geojson?bbox=O,S,E,N`** | FeatureCollection pour la carte (+ `totalGeocoded`, `totalMatching`) | | |
| 175 | −| **`GET /api/listings/{uid}`** | fiche complète : images, POI, quartier, digest, historique de prix | | |
| 176 | −| **`GET /api/listings/{uid}/pdf`** | fiche de propriété PDF (QR code) | | |
| 177 | −| **`GET /api/facets`** | villes, quartiers, types, sources — pour construire les filtres | | |
| 178 | −| **`GET /api/stats`** / **`/api/stats/detailed`** / **`/api/stats/rapport.pdf`** | agrégats du marché + rapport PDF | | |
| 179 | −| **`GET /api/sources`** | registre des **265 sources** + compteurs + dernière synchro | | |
| 180 | −| **`POST /api/sync`** | synchronisation en arrière-plan (`?source=`) | | |
| 181 | −| **`GET /api/auth/ka/login`** / **`/api/auth/google/login`** | SSO KA & Google OAuth | | |
| 182 | −| `GET /api/me` · `/api/favorites` · `/api/org/*` · `/api/users/{ka_id}` | session, favoris, pages gestionnaires, profils publics | | |
| 183 | − | |
| 184 | −Pages HTML servies par le SSR (`louka/seo.py`) : `/` · `/villes` · `/ville/{slug}[/{type}]` · `/logement/{uid}` (**410** si retirée) · `/g/{source}` · `/stats` · `/sources` · `/robots.txt` · `/sitemap*.xml` | |
| 98 | +En développement frontend : `cd frontend && npm run dev` (Vite sur `:5173`, proxy `/api`). | |
| 185 | 99 | |
| 186 | 100 | ## Déploiement |
| 187 | 101 | |
| 188 | −En production sur le nœud **M3U96b** (Mac Studio, cluster MacLustr), dans **`~/apps/lou-ka`**, sous **PM2** (**3 processus**) derrière **ngrok** : | |
| 189 | − | |
| 190 | −| Processus PM2 | Commande | Rôle | | |
| 191 | −|---|---|---| | |
| 192 | −| **`lou-ka-web`** | `.venv/bin/python run.py serve 8095` | API + SSR + frontend sur le **port 8095** | | |
| 193 | −| **`lou-ka-sync`** | `.venv/bin/python run.py watch 60` | resynchronisation **horaire** des sources | | |
| 194 | −| **`lou-ka-ngrok`** | `ngrok http --url=www.lou-ka.com 8095` | tunnel → **https://www.lou-ka.com** | | |
| 195 | − | |
| 196 | −Philosophie d'exploitation : **on ne pousse que le code — le serveur maintient ses données lui-même** (`data/*.db`, `frontend/dist` et `.env` ne sont **jamais versionnés**). | |
| 197 | − | |
| 198 | −## Développement remote-first (IMPORTANT) | |
| 199 | − | |
| 200 | −La **source de vérité est le repo git sur le nœud M3U96b** (`~/apps/lou-ka`), **pas** une copie locale sur le laptop. Toute modification se fait **sur le nœud via SSH** : édition, build frontend, `pm2 restart lou-ka-web`, puis commit/push **depuis le nœud**. | |
| 201 | − | |
| 202 | −- Remote **`origin` = spbgit** — le serveur git personnel **git.spboucher.ai** (bare repo `~/srv/git/lou-ka.git` sur M3U96a, alias SSH `gitsrv`). **Pas GitHub.** | |
| 203 | −- Le push fonctionne grâce à l'**agent forwarding SSH** actif pendant une session depuis le laptop. | |
| 204 | − | |
| 205 | −## Principes | |
| 206 | − | |
| 207 | −1. **Politesse** — délai **≥ 0,5 s** entre requêtes, garde-fous de crawl, User-Agent identifié (**`LouKaBot`**, page de transparence `/bot`). | |
| 208 | −2. **Fidélité** — **aucun prix inventé** (`price = null` si absent), **aucune coordonnée devinée** (géocodage validé ou rien). | |
| 209 | −3. **Traçabilité** — chaque fiche renvoie vers l'annonce originale via **`/passerelle/{uid}`**. | |
| 210 | −4. **Robustesse** — un connecteur qui casse n'affecte jamais les autres ; le **garde-fou anti-dérive** suspend les retraits quand une source déraille. | |
| 211 | −5. **Vie privée** — **aucun traceur tiers**, consentement honnête, profil public strictement **opt-in**. | |
| 212 | − | |
| 213 | −## Écosystème Groupe Ka | |
| 214 | − | |
| 215 | −Lou-Ka fait partie des plateformes du **[Groupe Ka](https://www.groupe-ka.com)**, aux côtés d'**Immo-Ka** (propriétés à vendre), **Vrai-Prix** et les autres univers ·Ka — avec en partage : le **SSO KA** (`ka_id` émis par le hub), le framework cartographique **Ka Maps**, le design system « **éditorial sharp** » et le géocodage **Adresses Québec**. | |
| 102 | +- **Nœud** : M3U96b (Mac Studio, cluster MacLustr) — répertoire `~/apps/lou-ka` | |
| 103 | +- **Port** : **8095** (local, exposé uniquement via le tunnel) | |
| 104 | +- **Processus PM2** : `lou-ka-web` (serveur) + `lou-ka-sync` (synchro) + `lou-ka-ngrok` (tunnel) | |
| 105 | +- **Domaine** : **https://www.lou-ka.com** (tunnel ngrok) | |
| 106 | + | |
| 107 | +## Écosystème Groupe KA | |
| 108 | + | |
| 109 | +- [groupe-ka.com](https://www.groupe-ka.com) — portail du groupe et compte unique KA ID | |
| 110 | +- [lou-ka.com](https://www.lou-ka.com) — logements à louer *(ce repo)* | |
| 111 | +- [immo-ka.com](https://www.immo-ka.com) — propriétés à vendre | |
| 112 | +- [vrai-prix.com](https://www.vrai-prix.com) — estimation immobilière | |
| 113 | +- [auto-ka.com](https://www.auto-ka.com) — véhicules | |
| 114 | +- [fabri-ka.com](https://www.fabri-ka.com) — produits québécois | |
| 115 | +- [food-ka.com](https://www.food-ka.com) — épicerie et alimentation | |
| 116 | +- [resto-ka.com](https://www.resto-ka.com) — restaurants | |
| 117 | +- [sorti-ka.com](https://www.sorti-ka.com) — sorties et événements | |
| 118 | +- [job-ka.com](https://www.job-ka.com) — emplois | |
| 119 | +- [crea-ka.com](https://www.crea-ka.com) — créateurs de contenu | |
| 120 | +- [trouve-ka.com](https://www.trouve-ka.com) — petites annonces | |
| 121 | +- [api-ka.com](https://www.api-ka.com) — API de données | |
| 216 | 122 | |
| 217 | 123 | --- |
| 218 | 124 | |
| 219 | −<div align="center"> | |
| 220 | − | |
| 221 | −**Simon-Pierre Boucher** — [contact@spboucher.ai](mailto:contact@spboucher.ai) · [git.spboucher.ai](https://git.spboucher.ai) | |
| 222 | − | |
| 223 | −© 2026 — tous droits réservés. | |
| 224 | − | |
| 225 | −Un service **Groupe Ka** | |
| 226 | − | |
| 227 | −</div> | |
| 125 | +© Groupe KA — Simon-Pierre Boucher · contact@spboucher.ai | |
| 126 | +Ce repo vit sur **spbgit** ([git.spboucher.ai](https://git.spboucher.ai)). | |
added
docs/screenshots/lou-ka-desktop.png
+0 −0
Binary file not shown.
added
docs/screenshots/lou-ka-mobile.png
+0 −0
Binary file not shown.