Python 68.8%
TypeScript 18.6%
CSS 8.7%
JavaScript 3.3%
HTML 0.6%
1# SPEC — Transformation lou-ka → Rent-Ka (LOCKED DECISIONS)23Rent-Ka = English rental-listings aggregator for ALL of Canada EXCEPT Québec4(Ontario first — 5,861 ON listings already seeded in the node DB; national5expansion via platform client registries comes right after launch).6Sister sites: Lou-Ka (QC rentals), House-Ka (ROC homes for sale).78## Identity9- Site name: **Rent-Ka** · wordmark **Rent·Ka** · domain **www.rent-ka.com**10- `BASE_URL = "https://www.rent-ka.com"`, `SITE_NAME = "Rent-Ka"`11- FastAPI: title "Rent-Ka API", description "Rental listings aggregator — Canada (outside Québec)"12- Tagline (frontend + SEO): **"Apartments and homes for rent across Canada."**13- UA: `RentKaBot/1.0 (+https://www.rent-ka.com/bot; contact@spboucher.ai)` (replaces every LouKaBot)14- Language: en-CA everywhere (backend SEO strings, frontend copy, `<html lang="en-CA">`)15- Python package: rename `louka/` → `rentka/` (all imports, `uvicorn.run("rentka.web:app", ...)`)16- DB path: `data/rentka.db` (db.py DB_PATH)17- Env prefix: `LOUKA_*` → `RENTKA_*` everywhere. `LOUKA_ONTARIO` gate is DELETED (not renamed).18 `LOUKA_BASE_URL` → `RENTKA_BASE_URL`.19- kaid site id: `kaid.init("rent-ka")`; hubfav URL `https://www.rent-ka.com/listing/{uid}`; KA_CLIENT_ID default "rent-ka".20- ecosystem.json (frontend/src/ka/ecosystem.json): ADD entry (backend web.py:940/983 looks it up — required):21 `{"id":"rent-ka","wordmark":"Rent·Ka","domain":"www.rent-ka.com","accent":"#2456e6","accentSoft":"#e9efff","accentDeep":"#1738a8","onAccent":"#ffffff","tagline":"Rentals across Canada"}`2223## Routes (English — backend seo.py/web.py AND frontend App.tsx/KAID_CONF must match)24- Listing page: **`/listing/{uid}`** (was `/logement/{uid}`)25- Cities index: **`/cities`** (was `/villes`); city page: **`/city/{slug}`** and **`/city/{slug}/{type_slug}`**26- Keep: `/stats`, `/sources`, `/contact`, `/bot`, `/g/{sourceId}`27- `/confidentialite` → **`/privacy`**, `/conditions` → **`/terms`**28- `/profil` → `/profile`, `/favoris` → `/favorites`, `/bienvenue` → `/welcome`,29 `/gestion` → `/manage`, `/passerelle/:uid` → `/gateway/:uid`,30 `/juste-valeur` → `/fair-value`, `/ka-scores` stays `/ka-scores`31- DELETED routes/pages: `/court-terme*` (short-term subsystem), `/demenageurs` (movers, QC dataset)32- web.py `_CLIENT_ROUTES = {"profile","favorites","manage","welcome","bot","contact","fair-value","ka-scores"}`,33 `_CLIENT_PREFIXES = ("u/","gateway/")`34- Sitemaps: `sitemap-pages.xml`, `sitemap-cities.xml`, `sitemap-listings-{n}.xml` (drop sitemap-ct-*)35- index.html KAID_CONF: `{card:"a[href^='/listing/']",detail:"^/listing/(.+)$",entity:"listing"}`3637## Canonical unit types (English enum — replaces the QC "n½" system)38`Studio | 1 bedroom | 2 bedrooms | 3 bedrooms | 4 bedrooms | 5+ bedrooms | Loft | Penthouse | Condo | Townhouse | House | Room`39- normalize.normalize_unit_type: map French AND English input INTO this enum40 (reverse of today: `3½` → "1 bedroom", `4½` → "2 bedrooms", `n½` → `(n-2) bedrooms`, `6½+` → "4 bedrooms";41 "bachelor" → Studio; "maison de ville|townhouse|mdv" → Townhouse; "chambre|room" → Room)42- bedrooms_from_unit_type: Studio/Loft→0, Room→1, "n bedroom(s)"→n, "5+ bedrooms"→5, Penthouse/Condo/Townhouse/House→None43- Slugs (seo.slugify): "1-bedroom", "2-bedrooms", "5-plus-bedrooms", "studio", "room", … (kill the `½ → -1-2` special case)44- quality.py rule 5: `unit != "Room"` (was "Chambre")4546## Geography / scope47- Scope = Canada minus QC. quality.evaluate: DELETE `pause-ontario` rule; ADD48 `if d.get("province") == "QC": reasons.append("outside-scope-quebec")`.49- schema.Listing default province: `"ON"` (connectors should set explicitly; platform50 registries gain an optional per-client `"province"` key, default "ON").51- schema.finalize + geocode: per-province bbox dict for all 12 (BC,AB,SK,MB,ON,NB,NS,PE,NL,YT,NT,NU),52 fallback = Canada bbox (41.6–83.2 N, −141.0…−52.5 E).53- geocode.py: REMOVE all Adresses Québec (MERN) code, `_BBOX_QUEBEC`, `_VILLES_QUEBEC`;54 keep Nominatim (1 r/s) as primary; `run_batch()` becomes a loop over Nominatim `resolve()`55 (keep the batch CLI signature working). state= full province name from a PROVINCE_NAMES dict.56 Cache keys: prefix `"{prov.lower()}|"` for every province.57- web.py `/api/stats`: replace the `_VILLES_GM` Montréal buckets with per-province counts:58 response gains `"provinces": {"ON": n, "BC": n, ...}` (keep "total"/existing top-level keys59 the frontend Ticker needs — frontend Ticker will read `provinces`).60- web.py: expose `province` in listing JSON (list + detail + geojson props) and as a61 filter param `province=` on /api/listings & /api/search; add it to /api/facets.6263## Features KEPT (translate UI strings to English where user-facing)64core pipeline (schema/db/ingest/normalize/dedup/quality/seo/web), fairvalue,65kascores + environment + poi (pure OSM, national), building ("Building passport"),66recycled ("Re-listed units"), history, imgcheck, managers (+serpapi_client),67marketstats, statsdash, statsfiche (prune deleted-layer panels), kapdf (shared, keep verbatim),68hiver.py → keep, rename user-facing label to **"Winter Score"** (works Canada-wide),69KA ID/accounts/auth/profile/hubfav/hubprofile (site id rent-ka), fixtures.py,70textmine.py → KEEP and make BILINGUAL: keep French regexes, add English equivalents for the71high-value facts (heat/hydro/electricity/water included, parking, pets, furnished, laundry,72A/C, elevator, balcony, dishwasher, no smoking, lease length, available date).7374## Features DELETED (backend module + web.py route + pdfgen section + statsextra block + frontend component)75- hydro.py (/api/hydro, HydroEstimation.tsx) — Hydro-Québec76- rdl.py (/api/rdl, RegistreLoyers.tsx) — QC rent registry77- tal.py (/api/tal, HistoriqueTAL.tsx) — QC tribunal78- gaz.py (/api/gaz, EssenceProche.tsx) — gazquebec79- air.py (/api/air, QualiteAir.tsx) — RSQAQ (maybe AQHI later)80- inondation.py (/api/inondation, RisqueInondation.tsx) — BDZI81- quartier.py (quartier block in /api/listings/{uid}, QuartierBlock.tsx) — QC census DB (rebuild later)82- commerces.py (/api/commerces, CommercesProches.tsx) + transit.db — QC banners/transit83- coutreel.py (/api/listings/{uid}/cout-reel, CoutReel.tsx) — backbone was Hydro-Québec84- demenageurs.py (+ /demenageurs SSR + Demenageurs.tsx + data/demenageurs.json)85- shortterm/ ENTIRELY (+ data/sources_ct.json, data/hotels_engines.json, ct_web router,86 seo ctdb import + /court-terme SSR + sitemap-ct, frontend Ct*.tsx, CourtTerme*.tsx, ctapi.ts, kamaps/ctAdapter.ts)87- MetroLignes.tsx usage in MapView.tsx + MapSearch.tsx (Montréal métro overlay)88- ingest.watch: remove hydro.precompute and tal.precompute steps (keep the rest incl. quartier→REMOVE too since module deleted)8990## Connectors91- KEEP the 65 ON connectors: remove the `_ONTARIO = ...` line and every `disabled = not _ONTARIO`92 / `"disabled": not _ONTARIO` (connector simply enabled). Platform generators93 (rentcafe/appfolio/rentsyncgw/buildium/liftsystem) keep reading their data/*.json registries;94 add support for optional per-client `"province"` (default "ON").95- KEEP + WIDEN the 11 national connectors (akelius, boardwalk, capreit, centurion, cogir,96 hazelview, interrent, metcap, minto, morguard, realstar): invert the gate — ROC is the default,97 DELETE the QC branches/city lists entirely; cover every non-QC province the landlord operates in98 (their sites list cities — keep existing ON lists, extend with the connector's own city discovery99 when it has one; set province per city).100- KEEP national portals (not gated): apartments_com, rentals_ca, zumper, kijiji, fb_marketplace +101 actors/. Change their default regions/cities env fallbacks from QC to ROC metros:102 Toronto, Ottawa, Mississauga, Hamilton, London, Kitchener-Waterloo, Windsor, Vancouver, Victoria,103 Surrey, Burnaby, Calgary, Edmonton, Winnipeg, Saskatoon, Regina, Halifax, Moncton, Fredericton,104 Charlottetown, St. John's. (env names now RENTKA_*)105- DELETE all other (~300) QC-only connector modules AND their data/sources.json entries.106 sources.json keeps: the 65 ON entries (status back to "actif", note_pause removed),107 the national/portal entries, minus all QC ones. Update `_comment`.108- KEEP helpers: base.py, _resilient.py, _detailutil.py; DELETE _livya.py/_planpoint.py if only109 QC connectors import them (check first).110- tests/: keep test_{normalize,quality,search,fairvalue,kascores,textmine}.py UPDATED to the new111 enum/rules; delete test fixtures + recorded cassettes of deleted connectors (tests/fixtures is 842 MB —112 purge everything belonging to deleted sources).113114## Frontend design (DIFFERENT from Lou-Ka orange and House-Ka pine/Fraunces)115- Keep the shared KA token system (frontend/src/ka/tokens.css UNTOUCHED — shared asset).116- styles.css overrides: accent = **cobalt** `--accent:#2456e6; --accent-soft:#e9efff; --accent-deep:#1738a8; --on-accent:#ffffff`117- Display font: **"Bricolage Grotesque"** (Google Fonts, weights 400..800) replaces Space Grotesk118 in index.html + `--font-display` override in styles.css. Body stays Inter.119- Header wordmark `Rent·Ka` (the ·Ka styled with accent), tagline "Apartments and homes for rent across Canada."120- The frontend should feel like its OWN site, not a translated Lou-Ka: new Home hero121 (search + "Browse by province" section with the province counts from /api/stats.provinces,122 featured cities grid), reordered nav, English MobileTabBar (Search/Map/Saved/Profile).123 Keep the detail-page section ORDER standard (gallery → price/address → description →124 amenities → practical details → analyses → map → KA Scores → footer; DOM order = visual125 order on ALL breakpoints, NEVER `order:`/column-reverse — Groupe KA standard 2026-08-19).126- Listing page keeps (in order): gallery, price+FairValueBadge, description, amenities,127 practical details, PriceAnalysis, HistoriqueLouka→"Listing history", ImmeubleBloc→"Building128 passport", GestionnaireBloc→"Property manager", recycled block, ListingMap3D, KaScoresBlock,129 HiverScore→"Winter Score". All QC blocks removed (list above).130- Ticker: per-province counts (ON · BC · AB · …) from /api/stats.provinces.131- Footer: keep KaFooter with siteId="rent-ka" (entry added to ecosystem.json).132- ALL user-facing text in English (en-CA). Currency format `$1,495`. Dates en-CA.133134## Deployment (for reference — done on node M4M36 afterwards)135- pm2: rent-ka-web (`run.py serve 8125`), rent-ka-sync (`run.py watch 60`),136 rent-ka-ngrok (`ngrok http --url=www.rent-ka.com 8125`)137- git origin gitsrv:srv/git/rent-ka.git138