Toit-Ka — rent or buy a roof in Québec, one place
Toit-Ka (www.toit-ka.com) is the merger of two Québec real-estate aggregators into a single platform where users search for rent OR for sale in one place:
- Lou-Ka — ~23,000 rental listings aggregated from 200+ property managers, brokers and platforms;
- Immo-Ka — ~63,000 for-sale properties aggregated from 29 networks (RE/MAX, Via Capitale, Sutton, Proprio Direct, Centris feeds…).
Toit-Ka does not scrape anything itself: it consumes read-only replicas of both production databases and unifies them through a normalization ETL. The two original sites keep running untouched. Every listing card links back to the original ad at the source.
Architecture
M3U96b (prod) M4M64a (prod)
lou-ka louka.db immo-ka immoka.db
│ sqlite3 .backup + rsync (LAN) │ ← read-only, every 30 min
▼ ▼
M3U96a ~/apps/toit-ka
data/replicas/{louka,immoka}.db
│ ETL (toitka/etl.py)
│ · inherited visibility rules (Centris dedup, plausible prices)
│ · canonical city mapping (toitka/villes.py — 3,300+ raw variants)
│ · unified type vocabulary + HTML-entity repair
▼
data/toitka.db — one `listings` table, `transaction_type ∈ {louer, acheter}`
│
FastAPI (toitka/web.py) ── JSON API + server-side SEO rendering (seo.py)
│
React 18 SPA (frontend/) ── Louer/Acheter toggle drives the site accent
│
ngrok ── https://www.toit-ka.com The city-normalization engine (toitka/villes.py)
The two corpora carried ~3,300 distinct raw city strings for roughly 1,000
real municipalities. Deterministic rules + a slug-grouping election pass fix,
among others: orphan parentheses (Brossard )), never-closed parentheses
(Gatineau (Hôpital), duplicated names (Gatineau (Gatineau)), boroughs
glued in both orders (Montréal (Ville-Marie) vs Ville-Marie (…)), merged
municipalities (Saint-Hubert (Longueuil)), English variants (Québec City,
Montreal Downtown, City Of Montréal), lost accents/hyphens
(Trois Rivieres, Mont Tremblant), mojibake (Montrã©al) and marketing
labels (Longueuil / South Shore). The full raw→canonical mapping is persisted
in the city_map table for auditing (python3 run.py villes).
Dual-accent design system
Single "sharp editorial" design system (Space Grotesk / Inter / JetBrains Mono,
ink borders, offset shadows) with an accent that follows the universe:
Lou-Ka electric lime in Louer mode, Immo-Ka red in Acheter mode, terracotta
for the Toit-Ka brand itself. The switch is one html[data-mode] attribute.
Features
- Home page with a central Louer / Acheter toggle — filters, price steps, quick chips and stats all adapt to the selected universe.
- Search by city (canonical), price, type (3½…6½+, Studio, Condo, Maison, Plex, Terrain…), bedrooms/bathrooms, area, pets, furnished, free text.
- List + 3D map view (Ka Maps / Mapbox GL) with per-universe markers (lime rent pills, ink sale pills), "search this area", React previews.
- Full listing page: gallery + lightbox, specs, description, walkability rings mini-map, link to the original ad.
- Programmatic SEO rendered server-side:
/louer/{ville},/acheter/{ville},/{tx}/{ville}/{type},/{tx}/type/{type}with average and median rent/price, breadcrumbs, JSON-LD, sitemaps, 301 canonical slugs, 410 for withdrawn listings. - KA ID single sign-on (groupe-ka.com identity hub) + favorites stored centrally in "Mon univers Ka".
- Mobile-first, French (Québec).
Repository layout
run.py CLI: serve | etl | watch | replicate | villes
toitka/
db.py unified schema (toitka.db) + read-only source connections
villes.py canonical city mapping engine
typologie.py unified type vocabulary (rent + sale)
etl.py replicas -> toitka.db (visibility rules, lifecycle)
replicate.py LAN pull of production snapshots (sqlite .backup + rsync)
web.py FastAPI JSON API + SPA serving
seo.py server-side SEO rendering, robots.txt, sitemaps
auth.py KA ID SSO (JWT HS256, stdlib only)
hubprofile.py member profile read from the Groupe KA hub
hubfav.py favorites.py central favorites ("Mon univers Ka")
frontend/ React 18 + Vite + TypeScript SPA (dual-accent theme)Running locally
# point the ETL at local copies of the source DBs (.env)
python3 run.py etl # build data/toitka.db
python3 run.py serve 8097 # http://localhost:8097
cd frontend && npm install && npm run build # SPA served by the backendProduction (MacLustr cluster)
- Node M3U96a,
~/apps/toit-ka, PM2:toit-ka-web(port 8097),toit-ka-etl(replicate + ETL every 30 min),toit-ka-ngrok(ngrok http --url=www.toit-ka.com 8097). - Health:
GET /api/health.
Author
Simon-Pierre Boucher — contact@spboucher.ai
Toit-Ka is a Groupe-Ka application (groupe-ka.com). Listing data belongs to its respective sources; every card links to the original ad.