SPB Git

spb/lou-ka Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

HTML 99.7%
8.1 KB · 180 lines markdown
Rendered Raw Blame History
1<div align="center">23# Lou·Ka45### Tous les logements à louer du Québec. Un seul endroit.67**[www.lou-ka.com](https://www.lou-ka.com)**89![Python](https://img.shields.io/badge/Python-3.14-141814?style=for-the-badge&logo=python&logoColor=d9f26b)10![FastAPI](https://img.shields.io/badge/FastAPI-API-141814?style=for-the-badge&logo=fastapi&logoColor=d9f26b)11![React](https://img.shields.io/badge/React_18-Vite_+_TS-141814?style=for-the-badge&logo=react&logoColor=d9f26b)12![SQLite](https://img.shields.io/badge/SQLite-storage-141814?style=for-the-badge&logo=sqlite&logoColor=d9f26b)13![PWA](https://img.shields.io/badge/PWA-mobile_ready-141814?style=for-the-badge&logoColor=d9f26b)1415![Sources](https://img.shields.io/badge/sources_recens%C3%A9es-255-1c5c41?style=flat-square)16![Connecteurs](https://img.shields.io/badge/connecteurs_actifs-194-1c5c41?style=flat-square)17![Annonces](https://img.shields.io/badge/annonces_agr%C3%A9g%C3%A9es-8000%2B-1c5c41?style=flat-square)18![Couverture](https://img.shields.io/badge/couverture-tout_le_Qu%C3%A9bec-1c5c41?style=flat-square)1920*Agrégateur indépendant de logements locatifs — chaque annonce avec toutes ses photos,21ses détails standardisés, et un lien direct vers l'annonce originale du gestionnaire.22Toujours à jour, automatiquement.*2324</div>2526---2728## Pourquoi Lou-Ka ?2930Chercher un appartement au Québec, c'est ouvrir 70 sites web différents — chacun avec sa31propre navigation, ses propres filtres, son propre format. **Lou-Ka retourne le problème** :32un connecteur dédié par gestionnaire immobilier visite chaque site, normalise chaque annonce33vers un schéma unique, et détecte les changements en continu.3435> Les sites d'agences n'offrent pas de webhooks. Lou-Ka reproduit l'équivalent :36> **synchronisation périodique + hash de contenu** → ajouts, mises à jour et retraits37> détectés automatiquement. Une annonce qui disparaît du site source disparaît de Lou-Ka.3839## L'architecture en 30 secondes4041```mermaid42flowchart LR43    subgraph Sources["74 gestionnaires immobiliers"]44        S1["Logisco · Cogir · CAPREIT<br/>Immostar · DMA · Laberge<br/>Akelius · Devimco · Mondev<br/>… 68 connecteurs actifs"]45    end46    subgraph LouKa["Lou-Ka"]47        C["Connecteurs<br/><i>1 adaptateur / site</i>"] --> N["Normalisation<br/><i>schéma Listing unique</i>"]48        N --> D[("SQLite<br/>hash + diff")]49        D --> A["API FastAPI<br/>/api/listings · /api/facets"]50        A --> F["React 18 + Vite<br/>PWA mobile · thème clair"]51    end52    W["⏱ Watcher horaire<br/>(PM2)"] -.-> C53    S1 --> C54    F --> U["🔑 Locataire"]55```5657| Couche | Rôle | Fichiers |58|---|---|---|59| **Connecteurs** | 1 module Python par gestionnaire : HTML rendu serveur, API JSON internes (Building Stack, RealVuu, Planpoint, Rentsync, source.immo, JetEngine…), ou Firecrawl pour les sites derrière Cloudflare | `louka/connectors/*.py` |60| **Schéma** | `Listing` standardisé : adresse, secteur, ville, type (3½…), prix, disponibilité, commodités, **toutes les images** | `louka/schema.py` |61| **Diff engine** | Upsert par hash de contenu — nouvelle / modifiée / disparue (désactivée) | `louka/db.py` |62| **API** | Filtres ville / secteur / taille / prix / gestionnaire / recherche, facettes, stats, déclencheur de sync | `louka/web.py` |63| **Frontend** | Design « éditorial sharp » : Space Grotesk, ombres décalées, accent lime, ticker temps réel, bottom sheet mobile, galeries photos, PWA installable | `frontend/` |6465## Démarrage rapide6667```bash68git clone https://github.com/spboucher-ai/lou-ka.git && cd lou-ka6970# Backend71python3 -m venv .venv && .venv/bin/pip install -r requirements.txt7273# Frontend74cd frontend && npm install && npm run build && cd ..7576# (optionnel) sites JavaScript/anti-bot77echo "FIRECRAWL_API_KEY=fc-votre-cle" > .env7879# Ingestion puis service80.venv/bin/python run.py sync            # toutes les sources (ou: run.py sync logisco msi)81.venv/bin/python run.py serve 8080      # → http://localhost:808082.venv/bin/python run.py watch 60        # resynchronisation en boucle (minutes)83```8485## Ajouter un gestionnaire (≈ 30 lignes)8687L'enregistrement est **auto-découvrant** : déposez un module dans `louka/connectors/`,88c'est tout — aucun fichier partagé à modifier.8990```python91# louka/connectors/mon_agence.py92from ..schema import Listing, infer_city, normalize_unit_type, parse_price93from .base import BaseConnector9495class MonAgenceConnector(BaseConnector):96    source_id = "mon_agence"9798    def fetch(self) -> list[Listing]:99        html = self.get("https://mon-agence.ca/logements").text   # throttlé, poli100        # ... parser les cartes, les fiches, les photos ...101        return [Listing(102            source=self.source_id, external_id="123",103            url="https://mon-agence.ca/logement/123",104            title="555, avenue Exemple", sector="Limoilou",105            city=infer_city("Limoilou"), unit_type=normalize_unit_type("4 1/2"),106            price=parse_price("1 250 $ / mois"), images=[...],107        )]108```109110Puis : `.venv/bin/python run.py sync mon_agence` — et l'annonce apparaît sur le site,111avec sa fiche, sa galerie et son lien source. Ajoutez l'entrée correspondante dans112`data/sources.json` pour la page **Sources**.113114## API115116| Endpoint | Description |117|---|---|118| `GET /api/listings?city=&sector=&unit_type=&source=&price_min=&price_max=&q=` | Recherche filtrée, triée par prix |119| `GET /api/listings/{uid}` | Fiche complète (toutes les images, commodités, source) |120| `GET /api/facets` | Valeurs distinctes pour construire les filtres |121| `GET /api/sources` | Registre des 74 gestionnaires + compteurs + dernière sync |122| `GET /api/stats` | Totaux par région, loyer moyen, journal de synchronisation |123| `POST /api/sync` | Déclenche une synchronisation en arrière-plan |124125## Couverture126127**Ville de Québec & Lévis** — Logisco, Cogir, Groupe Laberge, Immostar, DMA/Locago,128Groupe Dallaire, Trudel, Immeubles Roussin, Immeubles Simard, MSI, Gestipro, Logisma,129Lafrance & Mathieu, SIB, SDG, SGIQ, GIM Côté, Logisbourg, Bribourg, Paul-E. Richard,130Headway, Contraste, Appartements Urbains, Picard, Brochu, GParadis, CAPREIT, Lokalia,131Immoappart, OK Louer, et une douzaine de complexes (Huma, Le Clif, Terra, La Klé,132Sentinelle, Rivero, Viridi, Quartier les Éléments…).133134**Grand Montréal** — Akelius, InterRent, Boardwalk, Minto, MetCap, Realstar, Hazelview,135Groupe Copley, Cromwell, Lynk/Olymbec, Trylon, Plan A, Lofts MTL, Axia, Mondev, Devimco,136Collection Équinoxe (Batimo/EMD), Progim, Rentalys, UTILE, Werkliv, 1 Square Phillips,137Firma, Le Domaine, Beaudoin, Denux, Gestion Montréal, Nid d'Amour, SHDM…138139Chaque source non-connectable est **documentée avec sa raison** dans `data/sources.json`140(ex. : aucun prix affiché, inventaire vide, site placeholder).141142## Production143144Déployé sous **PM2** (3 processus) derrière **ngrok** :145146```147lou-ka-web    .venv/bin/python run.py serve 8095     # API + frontend148lou-ka-sync   .venv/bin/python run.py watch 60       # resync horaire149lou-ka-ngrok  ngrok http --url=www.lou-ka.com 8095   # tunnel150```151152Philosophie d'exploitation : **on ne pousse que le code — le serveur maintient ses153données lui-même.**154155## Principes1561571. **Politesse** — délai ≥ 0,5 s entre requêtes, garde-fous de crawl, User-Agent identifié.1582. **Fidélité** — aucun prix inventé : si la source n'affiche pas de prix, `price = null`.1593. **Traçabilité** — chaque fiche renvoie vers l'annonce originale du gestionnaire.1604. **Robustesse** — un connecteur qui casse n'affecte jamais les autres (auto-découverte161   tolérante, try/except par annonce, journal `sync_log`).162163---164165<div align="center">166167## Auteur168169**Simon-Pierre Boucher**170171[![Email](https://img.shields.io/badge/contact@spboucher.ai-141814?style=for-the-badge&logo=minutemailer&logoColor=d9f26b)](mailto:contact@spboucher.ai)172[![GitHub](https://img.shields.io/badge/spboucher--ai-141814?style=for-the-badge&logo=github&logoColor=d9f26b)](https://github.com/spboucher-ai)173174*Conçu, construit et déployé en une journée — de la recherche de marché175(74 gestionnaires recensés et vérifiés) au produit en production.*176177© 2026 Simon-Pierre Boucher — tous droits réservés.178179</div>180