SPB Git forge

spb/toit-ka

Public

Toit-Ka — louer ou acheter un toit au Québec, un seul endroit (fusion Lou-Ka × Immo-Ka) — www.toit-ka.com

4commits 1branches 0releases
2.0 MBsize
maindefault branch
25 days agolast push
Python 40.2% TypeScript 39% CSS 20.2% HTML 0.7%
ZIP tar.gz
NameLast commitUpdated
docs chore: repo toit-ka raccroché à spbgit + README ultra détaillé (FR) +... 1 mo ago
frontend chore: repo toit-ka raccroché à spbgit + README ultra détaillé (FR) +... 1 mo ago
toitka Toit-Ka v1 — fusion Lou-Ka × Immo-Ka : plateforme unifiée louer +... 1 mo ago
.gitignore chore: repo toit-ka raccroché à spbgit + README ultra détaillé (FR) +... 1 mo ago
README.md chore(retrait cluster): synchro copie du nœud M3U96a + README « URL... 25 days ago
requirements.txt Toit-Ka v1 — fusion Lou-Ka × Immo-Ka : plateforme unifiée louer +... 1 mo ago
run.py Toit-Ka v1 — fusion Lou-Ka × Immo-Ka : plateforme unifiée louer +... 1 mo ago
README.md source

⚠️ URL live hors fonction pour le moment. L'application a été retirée du cluster MacLustr le 2026-09-04 (processus arrêtés, copie du nœud supprimée). Ce dépôt spbgit est désormais la seule source de vérité du projet. Ancienne URL : https://www.toit-ka.com

# Toit-Ka — louer ou acheter un toit au Québec, au même endroit

Annonces À louer À vendre Sources Loyer moyen Prix moyen Backend Frontend Cartes Langue

Toit-Ka (www.toit-ka.com) est la fusion de deux agrégateurs immobiliers québécois en une seule plateforme : on y cherche un logement à louer OU une propriété à vendre, au même endroit, avec la même recherche, les mêmes cartes et le même vocabulaire :

  • Lou-Ka — locatif : ~69 000 annonces de logements agrégées depuis 400+ gestionnaires immobiliers, courtiers et plateformes ;
  • Immo-Ka — vente : ~157 000 propriétés agrégées depuis les grands réseaux (RE/MAX, Via Capitale, Sutton, Proprio Direct, flux Centris…).

Point capital : Toit-Ka ne scrape rien lui-même. Il consomme des réplicas en lecture seule des deux bases de données de production et les unifie via un ETL de normalisation. Les deux sites d'origine continuent de tourner sans être touchés, et chaque fiche renvoie vers l'annonce originale chez la source.

Chiffres au 2026-08-28 (/api/stats) : 226 094 annonces publiées (68 925 à louer · 157 169 à vendre), ~500 sources héritées, loyer moyen 1 834 $/mois, prix affiché moyen ≈ 904 000 $.


# Identité : le design bi-accent

Toit-Ka réunit deux univers qui avaient chacun leur couleur. Plutôt que d'en choisir une, le site adopte un système bi-accent piloté par un unique attribut html[data-mode] :

Accent Couleur Rôle
Lime électrique héritée de Lou-Ka mode Louer : boutons, pastilles de carte, chips, stats
Rouge hérité d'Immo-Ka mode Acheter : mêmes composants, autre univers
Terracotta propre à Toit-Ka la marque elle-même (logo, badges, éléments neutres)

Le toggle central Louer / Acheter de la page d'accueil est le cœur de l'expérience : il bascule instantanément les filtres, les paliers de prix, les chips rapides, les statistiques et l'accent visuel de tout le site. Le socle graphique est le style « éditorial tranché » du Groupe Ka : Space Grotesk / Inter / JetBrains Mono, bordures encre, ombres décalées, mobile-first, français (Québec).


# Visite guidée (10 captures)

Captures du 2026-08-28 sur www.toit-ka.com (desktop 1440×900 · mobile 390×844).

# 1. Accueil — un toit, deux univers

Accueil

La page d'accueil avec le toggle central Louer / Acheter, la barre de recherche par ville et les compteurs live des deux univers. L'accent de la page suit le mode sélectionné.

# 2. Fiche d'annonce — propriété à vendre

Fiche annonce achat

Une fiche complète en mode Acheter (5334, rue Waverly, Montréal) : galerie photo, prix, caractéristiques, description, carte — et le lien vers l'annonce originale chez la source. L'URL canonique /annonce/{uid}/{slug} est rendue côté serveur pour le SEO.

# 3. Accueil en mode Louer — l'accent lime

Accueil mode Louer

La même page d'accueil après bascule du toggle (?tx=louer) : filtres, paliers de prix et chips s'adaptent à l'univers locatif et tout le site passe à l'accent lime hérité de Lou-Ka.

# 4. Statistiques de marché

Statistiques

La page /stats : volumes par univers, loyers et prix moyens, top villes et top typologies, calculés en direct sur la base unifiée toitka.db.

# 5. Profil — KA ID

Profil

Le profil membre via KA ID, l'identité unique du Groupe Ka (groupe-ka.com) : connexion partagée et favoris centralisés dans « Mon univers Ka », communs aux 12 sites de l'écosystème.

# 6. Conditions d'utilisation

Conditions

La page /conditions : cadre d'utilisation, statut d'agrégateur et renvoi systématique aux annonces originales.

# 7. Politique de confidentialité

Confidentialité

La page /confidentialite : données collectées, cookies, droits des membres KA ID.

# 8. Accueil — sections thématiques (1/2)

Accueil section 1

En défilant l'accueil : sélections d'annonces par univers et raccourcis vers les grandes villes, chaque bloc portant l'accent de son univers.

# 9. Accueil — sections thématiques (2/2)

Accueil section 2

Suite de l'accueil : typologies populaires (3½, 4½, condo, maison, plex…), statistiques et maillage interne vers les pages SEO par ville et par type.

# 10. Accueil mobile

Accueil mobile

L'accueil sur téléphone (390×844) : toggle, recherche et compteurs au-dessus du pli, navigation plein écran (KA Nav v2), conforme au socle mobile du Groupe Ka (zones tactiles, safe-area, anti-zoom).

# Galerie complémentaire (2026-08-25)

Accueil mobile
Accueil mobile
Résultats mobile
Résultats à Montréal
Fiche mobile
Fiche annonce
Stats mobile
Statistiques
Menu mobile
Menu plein écran
Accueil desktop
Accueil desktop
Résultats desktop
Résultats — design bi-accent
Stats desktop
Stats desktop

# Fonctionnalités

  • Deux univers, une plateforme : toggle central Louer / Acheter ; filtres, paliers de prix, chips rapides et stats adaptés à l'univers actif.
  • Recherche unifiée : par ville (canonique), prix, type (3½…6½+, Studio, Chambre, Condo, Maison, Plex, Terrain…), chambres/salles de bain, superficie, animaux, meublé, texte libre.
  • Vue liste + carte 3D (Ka Maps / Mapbox GL) : marqueurs par univers (pastilles lime pour le locatif, encre pour la vente), « chercher dans cette zone », aperçus React au clic.
  • Fiche complète : galerie + lightbox, caractéristiques, description, mini-carte avec anneaux de marchabilité, lien vers l'annonce originale.
  • SEO programmatique rendu côté serveur : /louer/{ville}, /acheter/{ville}, /{tx}/{ville}/{type}, /{tx}/type/{type} avec loyers et prix moyens/médians, fils d'Ariane, JSON-LD, sitemaps, slugs canoniques 301, 410 pour les annonces retirées.
  • KA ID (SSO Groupe Ka) + favoris centralisés « Mon univers Ka ».
  • Page /stats live sur la base unifiée.
  • Mobile-first, 100 % français (Québec).

# Architecture — un agrégateur d'agrégateurs, sans scraping

text
M3U96b (prod)                     M4M64a (prod)
  lou-ka   louka.db                 immo-ka   immoka.db
      │  sqlite3 .backup + rsync (LAN 192.168.2.x)  │   ← lecture seule, toutes les 30 min
      ▼                                             ▼
                 M3U96a   ~/apps/toit-ka
  data/replicas/{louka,immoka}.db          (toitka/replicate.py)
      │  ETL (toitka/etl.py)
      │    · règles de visibilité héritées (dédup Centris, prix plausibles)
      │    · villes canoniques (toitka/villes.py — ~3 300 variantes brutes)
      │    · typologie unifiée + réparation des entités HTML
      ▼
  data/toitka.db — une seule table `listings`, `transaction_type ∈ {louer, acheter}`
      │
  FastAPI (toitka/web.py) ── API JSON + rendu SEO côté serveur (toitka/seo.py)
      │
  SPA React 18 (frontend/) ── toggle Louer/Acheter → accent du site
      │
  ngrok ── https://www.toit-ka.com     (port local 8097)

# Pourquoi zéro scraping ?

Lou-Ka et Immo-Ka font déjà le travail dur (des centaines de connecteurs, files de quarantaine, audits d'images, dédup). Toit-Ka hérite de ce travail : toitka/replicate.py tire, toutes les 30 minutes, un snapshot cohérent de chaque BD de prod (sqlite3 .backup côté source puis rsync via le LAN du cluster), en lecture seule — aucune écriture, aucun verrou, aucune charge sur les sites de prod. Le pipeline est idempotent : chaque passe reconstruit l'état publié et gère le cycle de vie (nouvelles annonces, retraits → 410).

# Le moteur de normalisation des villes (toitka/villes.py)

Les deux corpus totalisaient ~3 300 chaînes de villes brutes distinctes pour environ 1 000 municipalités réelles. Des règles déterministes plus une passe d'élection par regroupement de slugs corrigent, entre autres : parenthèses orphelines (Brossard )), parenthèses jamais fermées (Gatineau (Hôpital), noms dupliqués (Gatineau (Gatineau)), arrondissements collés dans les deux sens (Montréal (Ville-Marie) vs Ville-Marie (…)), municipalités fusionnées (Saint-Hubert (Longueuil)), variantes anglaises (Québec City, Montreal Downtown, City Of Montréal), accents/traits d'union perdus (Trois Rivieres, Mont Tremblant), mojibake (Montrã©al) et libellés marketing (Longueuil / South Shore). Le mapping complet brut → canonique est persisté dans la table city_map pour audit (python3 run.py villes).

# La typologie unifiée (toitka/typologie.py)

Le locatif parle en « pièces et demie » (3½, 4½…), la vente en catégories (condo, maison, plex, terrain…). typologie.py fond les deux vocabulaires en un seul référentiel de types, utilisé par les filtres, les stats et les pages SEO par type — pour que « 4½ à Montréal » et « condo à Québec » vivent dans le même moteur de recherche.


# API & routes

# API JSON (FastAPI — toitka/web.py)

Route Description
GET /api/listings recherche paginée (tx, ville, prix, type, chambres, sdb, superficie, animaux, meublé, texte…)
GET /api/listings/{uid} détail d'une annonce (uid préfixé lou: / immo: selon l'origine)
GET /api/listings.geojson flux GeoJSON pour la carte (bbox, filtres)
GET /api/facets facettes live (villes, types, paliers de prix) selon l'univers
GET /api/stats statistiques agrégées par univers + journal des passes ETL
GET /api/health santé (ok, nb d'annonces, timestamp du dernier ETL)
GET /api/seo/resolve résolution slug → entité pour le routage SPA
GET /api/auth/* SSO KA ID (JWT HS256, stdlib uniquement)
GET/POST/DELETE /api/favorites/* favoris centralisés « Mon univers Ka »

# Routes SEO rendues côté serveur (toitka/seo.py)

Route Contenu
/louer/{ville} · /acheter/{ville} page ville par univers (moyennes, médianes, annonces, JSON-LD)
/{tx}/{ville}/{type} page ville × type
/{tx}/type/{type} page type provinciale
/annonce/{uid}/{slug} fiche annonce (canonique 301 si slug obsolète, 410 si retirée)
/robots.txt · /sitemap.xml · /sitemaps/{name} indexation programmatique

Les autres chemins servent la SPA React (catch-all /{full_path:path}).


# Structure du dépôt

text
run.py                  CLI unique : serve | etl | watch | replicate | villes
requirements.txt        FastAPI + uvicorn (volontairement minimal)
toitka/
  db.py                 schéma unifié (toitka.db) + connexions sources lecture seule
  villes.py             moteur de canonicalisation des villes (~3 300 variantes → city_map)
  typologie.py          vocabulaire de types unifié (locatif + vente)
  etl.py                répliques -> toitka.db (règles de visibilité, cycle de vie)
  replicate.py          tirage LAN des snapshots de prod (sqlite .backup + rsync)
  web.py                API JSON FastAPI + service de la SPA
  seo.py                rendu SEO côté serveur, robots.txt, sitemaps
  auth.py               SSO KA ID (JWT HS256, stdlib uniquement)
  hubprofile.py         profil membre lu depuis le hub Groupe KA
  hubfav.py favorites.py  favoris centralisés (« Mon univers Ka »)
frontend/               SPA React 18 + Vite + TypeScript (thème bi-accent)
  src/pages/            Home, Category, Listing, Stats, Profil, Legal
  src/components/       ListingCard, MapView, PropertyMap, Icons
  src/kamaps/           adaptateur Ka Maps (Mapbox GL 3D)
docs/screenshots/       visite/ (10 JPG 2026-08-28) + mobile/ + desktop/ (webp 2026-08-25)
data/                   (ignoré par git) réplicas + toitka.db — plusieurs Go

Le frontend dépend de @groupe-ka/ka-maps en file:../../ka-maps : le framework cartographique partagé du Groupe Ka doit être présent à côté du repo (~/apps/ka-maps sur le nœud) pour npm install.


# Lancer en local

bash
# 1. Config : .env pointe l'ETL vers des copies locales des BD sources
#    (jamais commité — voir .gitignore)
# 2. Construire la base unifiée
python3 run.py etl          # répliques -> data/toitka.db
# ou en continu :
python3 run.py watch 30     # replicate (si configuré) + etl toutes les 30 min

# 3. Backend + SPA
python3 run.py serve 8097   # http://localhost:8097
cd frontend && npm install && npm run build   # la SPA est servie par le backend

# Production (cluster MacLustr)

Élément Valeur
Nœud M3U96a — ~/apps/toit-ka
Port 8097
PM2 toit-ka-web (uvicorn :8097) · toit-ka-etl (run.py watch — replicate + ETL toutes les 30 min) · toit-ka-ngrok
Tunnel ngrok http --url=www.toit-ka.com 8097
Santé GET /api/health → {"ok": true, "listings": …, "last_etl": …}
Sources lou-ka (M3U96b) et immo-ka (M4M64a), snapshots lecture seule via LAN
Dépôt spbgit (git perso du cluster) — ~/srv/git/toit-ka.git sur M3U96a

Développement remote-first comme toutes les apps Ka : la source de vérité est le repo git sur le nœud, pas une copie laptop.


# Écosystème Groupe Ka

Toit-Ka est une application Groupe-Ka, aux côtés de Lou-Ka (location), Immo-Ka (vente), Vrai-Prix, Auto-Ka, Food-Ka, Resto-Ka, Sorti-Ka, Job-Ka, Trouve-Ka, Créa-Ka, Fabri-Ka et des déclinaisons canadiennes (House-Ka, Rent-Ka). Identité partagée KA ID, favoris centralisés, design system ka-ui commun.

# Auteur

Simon-Pierre Boucher — contact@spboucher.ai

Les données d'annonces appartiennent à leurs sources respectives ; chaque fiche renvoie vers l'annonce originale.