chore: repo toit-ka raccroché à spbgit + README ultra détaillé (FR) + visite guidée en 10 captures
13 changed files +321 −122
modified
.gitignore
+17 −2
@@ -1,8 +1,23 @@ | ||
| 1 | 1 | # Author: Simon-Pierre Boucher — Contact: contact@spboucher.ai — Project: Toit-Ka |
| 2 | −.env | |
| 2 | +# Données (répliques prod + BD unifiée = plusieurs Go) — jamais dans git | |
| 3 | 3 | data/ |
| 4 | +*.db | |
| 5 | +*.db-shm | |
| 6 | +*.db-wal | |
| 7 | +*.sqlite* | |
| 8 | +# Secrets | |
| 9 | +.env | |
| 10 | +.env.* | |
| 11 | +# Dépendances / environnements | |
| 4 | 12 | frontend/node_modules/ |
| 5 | −frontend/dist/ | |
| 13 | +node_modules/ | |
| 14 | +.venv/ | |
| 15 | +venv/ | |
| 6 | 16 | __pycache__/ |
| 7 | 17 | *.pyc |
| 18 | +# Build & artefacts | |
| 19 | +frontend/dist/ | |
| 20 | +frontend/tsconfig.tsbuildinfo | |
| 21 | +*.log | |
| 8 | 22 | .DS_Store |
| 23 | +.claude/ | |
modified
README.md
+304 −119
@@ -4,163 +4,348 @@ | ||
| 4 | 4 | Project: Toit-Ka |
| 5 | 5 | --> |
| 6 | 6 | |
| 7 | −# Toit-Ka — rent or buy a roof in Québec, one place | |
| 8 | − | |
| 9 | − | |
| 10 | − | |
| 11 | − | |
| 12 | − | |
| 13 | − | |
| 14 | − | |
| 7 | +# Toit-Ka — louer ou acheter un toit au Québec, au même endroit | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | 15 |  |
| 16 | 16 |  |
| 17 | −-4264fb?style=flat-square) | |
| 18 | −-blue?style=flat-square) | |
| 17 | +-4264fb?style=flat-square) | |
| 18 | +-blue?style=flat-square) | |
| 19 | 19 | |
| 20 | −**Toit-Ka** ([www.toit-ka.com](https://www.toit-ka.com)) is the merger of two | |
| 21 | −Québec real-estate aggregators into a single platform where users search **for | |
| 22 | −rent OR for sale** in one place: | |
| 20 | +**Toit-Ka** ([www.toit-ka.com](https://www.toit-ka.com)) est la **fusion de deux | |
| 21 | +agrégateurs immobiliers québécois en une seule plateforme** : on y cherche un | |
| 22 | +logement **à louer OU une propriété à vendre**, au même endroit, avec la même | |
| 23 | +recherche, les mêmes cartes et le même vocabulaire : | |
| 23 | 24 | |
| 24 | −- **[Lou-Ka](https://www.lou-ka.com)** — ~23,000 rental listings aggregated from | |
| 25 | − 200+ property managers, brokers and platforms; | |
| 26 | −- **[Immo-Ka](https://www.immo-ka.com)** — ~63,000 for-sale properties aggregated | |
| 27 | − from 29 networks (RE/MAX, Via Capitale, Sutton, Proprio Direct, Centris feeds…). | |
| 25 | +- **[Lou-Ka](https://www.lou-ka.com)** — locatif : ~69 000 annonces de logements | |
| 26 | + agrégées depuis 400+ gestionnaires immobiliers, courtiers et plateformes ; | |
| 27 | +- **[Immo-Ka](https://www.immo-ka.com)** — vente : ~157 000 propriétés agrégées | |
| 28 | + depuis les grands réseaux (RE/MAX, Via Capitale, Sutton, Proprio Direct, | |
| 29 | + flux Centris…). | |
| 28 | 30 | |
| 29 | −Toit-Ka **does not scrape anything itself**: it consumes read-only replicas of | |
| 30 | −both production databases and unifies them through a normalization ETL. The two | |
| 31 | −original sites keep running untouched. Every listing card links back to the | |
| 32 | −original ad at the source. | |
| 31 | +Point capital : **Toit-Ka ne scrape rien lui-même**. Il consomme des | |
| 32 | +**réplicas en lecture seule** des deux bases de données de production et les | |
| 33 | +unifie via un ETL de normalisation. Les deux sites d'origine continuent de | |
| 34 | +tourner sans être touchés, et chaque fiche renvoie vers l'annonce originale | |
| 35 | +chez la source. | |
| 33 | 36 | |
| 34 | −## Screenshots | |
| 37 | +> Chiffres au 2026-08-28 (`/api/stats`) : **226 094 annonces publiées** | |
| 38 | +> (68 925 à louer · 157 169 à vendre), ~500 sources héritées, loyer moyen | |
| 39 | +> 1 834 $/mois, prix affiché moyen ≈ 904 000 $. | |
| 35 | 40 | |
| 36 | −*Captured 2026-08-25 (mobile 390×844 · desktop 1440×900).* | |
| 41 | +--- | |
| 37 | 42 | |
| 38 | −### Mobile | |
| 43 | +## Identité : le design bi-accent | |
| 39 | 44 | |
| 40 | −<table> | |
| 41 | − <tr> | |
| 42 | − <td align="center"><img src="docs/screenshots/mobile/home.webp" width="240" alt="Home mobile"><br><sub><b>Home — rent OR buy, one search</b></sub></td> | |
| 43 | − <td align="center"><img src="docs/screenshots/mobile/resultats.webp" width="240" alt="Results mobile"><br><sub><b>Listings in Montréal</b></sub></td> | |
| 44 | − <td align="center"><img src="docs/screenshots/mobile/annonce.webp" width="240" alt="Listing mobile"><br><sub><b>Listing page — links back to the source ad</b></sub></td> | |
| 45 | − </tr> | |
| 46 | − <tr> | |
| 47 | − <td align="center"><img src="docs/screenshots/mobile/stats.webp" width="240" alt="Stats mobile"><br><sub><b>Market statistics</b></sub></td> | |
| 48 | − <td align="center" colspan="2"><img src="docs/screenshots/mobile/menu-mobile.webp" width="240" alt="Mobile menu"><br><sub><b>Full-screen mobile nav (KA Nav v2)</b></sub></td> | |
| 49 | − </tr> | |
| 50 | −</table> | |
| 45 | +Toit-Ka réunit deux univers qui avaient chacun leur couleur. Plutôt que d'en | |
| 46 | +choisir une, le site adopte un **système bi-accent** piloté par un unique | |
| 47 | +attribut `html[data-mode]` : | |
| 48 | + | |
| 49 | +| Accent | Couleur | Rôle | | |
| 50 | +|---|---|---| | |
| 51 | +| **Lime électrique** | héritée de Lou-Ka | mode **Louer** : boutons, pastilles de carte, chips, stats | | |
| 52 | +| **Rouge** | hérité d'Immo-Ka | mode **Acheter** : mêmes composants, autre univers | | |
| 53 | +| **Terracotta** | propre à Toit-Ka | la marque elle-même (logo, badges, éléments neutres) | | |
| 54 | + | |
| 55 | +Le **toggle central Louer / Acheter** de la page d'accueil est le cœur de | |
| 56 | +l'expérience : il bascule instantanément les filtres, les paliers de prix, les | |
| 57 | +chips rapides, les statistiques et l'accent visuel de tout le site. Le socle | |
| 58 | +graphique est le style « éditorial tranché » du Groupe Ka : Space Grotesk / | |
| 59 | +Inter / JetBrains Mono, bordures encre, ombres décalées, mobile-first, | |
| 60 | +français (Québec). | |
| 61 | + | |
| 62 | +--- | |
| 63 | + | |
| 64 | +## Visite guidée (10 captures) | |
| 65 | + | |
| 66 | +*Captures du 2026-08-28 sur www.toit-ka.com (desktop 1440×900 · mobile 390×844).* | |
| 67 | + | |
| 68 | +### 1. Accueil — un toit, deux univers | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | +La page d'accueil avec le **toggle central Louer / Acheter**, la barre de | |
| 73 | +recherche par ville et les compteurs live des deux univers. L'accent de la | |
| 74 | +page suit le mode sélectionné. | |
| 75 | + | |
| 76 | +### 2. Fiche d'annonce — propriété à vendre | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | +Une fiche complète en mode *Acheter* (5334, rue Waverly, Montréal) : galerie | |
| 81 | +photo, prix, caractéristiques, description, carte — et le **lien vers | |
| 82 | +l'annonce originale** chez la source. L'URL canonique | |
| 83 | +`/annonce/{uid}/{slug}` est rendue côté serveur pour le SEO. | |
| 84 | + | |
| 85 | +### 3. Accueil en mode Louer — l'accent lime | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | +La même page d'accueil après bascule du toggle (`?tx=louer`) : filtres, | |
| 90 | +paliers de prix et chips s'adaptent à l'univers locatif et tout le site passe | |
| 91 | +à l'accent lime hérité de Lou-Ka. | |
| 92 | + | |
| 93 | +### 4. Statistiques de marché | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | +La page `/stats` : volumes par univers, loyers et prix moyens, top villes et | |
| 98 | +top typologies, calculés en direct sur la base unifiée `toitka.db`. | |
| 99 | + | |
| 100 | +### 5. Profil — KA ID | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | +Le profil membre via **KA ID**, l'identité unique du Groupe Ka | |
| 105 | +(groupe-ka.com) : connexion partagée et favoris centralisés dans | |
| 106 | +« Mon univers Ka », communs aux 12 sites de l'écosystème. | |
| 107 | + | |
| 108 | +### 6. Conditions d'utilisation | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | +La page `/conditions` : cadre d'utilisation, statut d'agrégateur et renvoi | |
| 113 | +systématique aux annonces originales. | |
| 114 | + | |
| 115 | +### 7. Politique de confidentialité | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | +La page `/confidentialite` : données collectées, cookies, droits des membres | |
| 120 | +KA ID. | |
| 121 | + | |
| 122 | +### 8. Accueil — sections thématiques (1/2) | |
| 51 | 123 | |
| 52 | −### Desktop | |
| 124 | + | |
| 125 | + | |
| 126 | +En défilant l'accueil : sélections d'annonces par univers et raccourcis vers | |
| 127 | +les grandes villes, chaque bloc portant l'accent de son univers. | |
| 128 | + | |
| 129 | +### 9. Accueil — sections thématiques (2/2) | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | +Suite de l'accueil : typologies populaires (3½, 4½, condo, maison, plex…), | |
| 134 | +statistiques et maillage interne vers les pages SEO par ville et par type. | |
| 135 | + | |
| 136 | +### 10. Accueil mobile | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | +L'accueil sur téléphone (390×844) : toggle, recherche et compteurs au-dessus | |
| 141 | +du pli, navigation plein écran (KA Nav v2), conforme au socle mobile du | |
| 142 | +Groupe Ka (zones tactiles, safe-area, anti-zoom). | |
| 143 | + | |
| 144 | +### Galerie complémentaire (2026-08-25) | |
| 53 | 145 | |
| 54 | 146 | <table> |
| 55 | 147 | <tr> |
| 56 | − <td align="center"><img src="docs/screenshots/desktop/home.webp" width="420" alt="Home desktop"><br><sub><b>Home — 136,000+ listings, rent + sale unified</b></sub></td> | |
| 57 | − <td align="center"><img src="docs/screenshots/desktop/resultats.webp" width="420" alt="Results desktop"><br><sub><b>City results — dual-accent design (rent/sale)</b></sub></td> | |
| 148 | + <td align="center"><img src="docs/screenshots/mobile/home.webp" width="200" alt="Accueil mobile"><br><sub><b>Accueil mobile</b></sub></td> | |
| 149 | + <td align="center"><img src="docs/screenshots/mobile/resultats.webp" width="200" alt="Résultats mobile"><br><sub><b>Résultats à Montréal</b></sub></td> | |
| 150 | + <td align="center"><img src="docs/screenshots/mobile/annonce.webp" width="200" alt="Fiche mobile"><br><sub><b>Fiche annonce</b></sub></td> | |
| 151 | + <td align="center"><img src="docs/screenshots/mobile/stats.webp" width="200" alt="Stats mobile"><br><sub><b>Statistiques</b></sub></td> | |
| 152 | + <td align="center"><img src="docs/screenshots/mobile/menu-mobile.webp" width="200" alt="Menu mobile"><br><sub><b>Menu plein écran</b></sub></td> | |
| 58 | 153 | </tr> |
| 59 | 154 | <tr> |
| 60 | − <td align="center"><img src="docs/screenshots/desktop/annonce.webp" width="420" alt="Listing desktop"><br><sub><b>Listing page</b></sub></td> | |
| 61 | − <td align="center"><img src="docs/screenshots/desktop/stats.webp" width="420" alt="Stats desktop"><br><sub><b>Statistics</b></sub></td> | |
| 155 | + <td align="center" colspan="2"><img src="docs/screenshots/desktop/home.webp" width="420" alt="Accueil desktop"><br><sub><b>Accueil desktop</b></sub></td> | |
| 156 | + <td align="center" colspan="2"><img src="docs/screenshots/desktop/resultats.webp" width="420" alt="Résultats desktop"><br><sub><b>Résultats — design bi-accent</b></sub></td> | |
| 157 | + <td align="center"><img src="docs/screenshots/desktop/stats.webp" width="220" alt="Stats desktop"><br><sub><b>Stats desktop</b></sub></td> | |
| 62 | 158 | </tr> |
| 63 | 159 | </table> |
| 64 | 160 | |
| 65 | −## Architecture | |
| 161 | +--- | |
| 162 | + | |
| 163 | +## Fonctionnalités | |
| 164 | + | |
| 165 | +- **Deux univers, une plateforme** : toggle central **Louer / Acheter** ; | |
| 166 | + filtres, paliers de prix, chips rapides et stats adaptés à l'univers actif. | |
| 167 | +- **Recherche unifiée** : par ville (canonique), prix, type (3½…6½+, Studio, | |
| 168 | + Chambre, Condo, Maison, Plex, Terrain…), chambres/salles de bain, | |
| 169 | + superficie, animaux, meublé, texte libre. | |
| 170 | +- **Vue liste + carte 3D** (Ka Maps / Mapbox GL) : marqueurs par univers | |
| 171 | + (pastilles lime pour le locatif, encre pour la vente), « chercher dans | |
| 172 | + cette zone », aperçus React au clic. | |
| 173 | +- **Fiche complète** : galerie + lightbox, caractéristiques, description, | |
| 174 | + mini-carte avec anneaux de marchabilité, **lien vers l'annonce originale**. | |
| 175 | +- **SEO programmatique rendu côté serveur** : `/louer/{ville}`, | |
| 176 | + `/acheter/{ville}`, `/{tx}/{ville}/{type}`, `/{tx}/type/{type}` avec loyers | |
| 177 | + et prix moyens/médians, fils d'Ariane, JSON-LD, sitemaps, slugs canoniques | |
| 178 | + 301, 410 pour les annonces retirées. | |
| 179 | +- **KA ID (SSO Groupe Ka)** + favoris centralisés « Mon univers Ka ». | |
| 180 | +- **Page /stats** live sur la base unifiée. | |
| 181 | +- Mobile-first, 100 % français (Québec). | |
| 182 | + | |
| 183 | +--- | |
| 184 | + | |
| 185 | +## Architecture — un agrégateur d'agrégateurs, sans scraping | |
| 66 | 186 | |
| 67 | 187 | ``` |
| 68 | −M3U96b (prod) M4M64a (prod) | |
| 69 | − lou-ka louka.db immo-ka immoka.db | |
| 70 | − │ sqlite3 .backup + rsync (LAN) │ ← read-only, every 30 min | |
| 71 | − ▼ ▼ | |
| 72 | − M3U96a ~/apps/toit-ka | |
| 73 | − data/replicas/{louka,immoka}.db | |
| 188 | +M3U96b (prod) M4M64a (prod) | |
| 189 | + lou-ka louka.db immo-ka immoka.db | |
| 190 | + │ sqlite3 .backup + rsync (LAN 192.168.2.x) │ ← lecture seule, toutes les 30 min | |
| 191 | + ▼ ▼ | |
| 192 | + M3U96a ~/apps/toit-ka | |
| 193 | + data/replicas/{louka,immoka}.db (toitka/replicate.py) | |
| 74 | 194 | │ ETL (toitka/etl.py) |
| 75 | − │ · inherited visibility rules (Centris dedup, plausible prices) | |
| 76 | − │ · canonical city mapping (toitka/villes.py — 3,300+ raw variants) | |
| 77 | − │ · unified type vocabulary + HTML-entity repair | |
| 195 | + │ · règles de visibilité héritées (dédup Centris, prix plausibles) | |
| 196 | + │ · villes canoniques (toitka/villes.py — ~3 300 variantes brutes) | |
| 197 | + │ · typologie unifiée + réparation des entités HTML | |
| 78 | 198 | ▼ |
| 79 | − data/toitka.db — one `listings` table, `transaction_type ∈ {louer, acheter}` | |
| 199 | + data/toitka.db — une seule table `listings`, `transaction_type ∈ {louer, acheter}` | |
| 80 | 200 | │ |
| 81 | − FastAPI (toitka/web.py) ── JSON API + server-side SEO rendering (seo.py) | |
| 201 | + FastAPI (toitka/web.py) ── API JSON + rendu SEO côté serveur (toitka/seo.py) | |
| 82 | 202 | │ |
| 83 | − React 18 SPA (frontend/) ── Louer/Acheter toggle drives the site accent | |
| 203 | + SPA React 18 (frontend/) ── toggle Louer/Acheter → accent du site | |
| 84 | 204 | │ |
| 85 | − ngrok ── https://www.toit-ka.com | |
| 205 | + ngrok ── https://www.toit-ka.com (port local 8097) | |
| 86 | 206 | ``` |
| 87 | 207 | |
| 88 | −### The city-normalization engine (`toitka/villes.py`) | |
| 89 | − | |
| 90 | −The two corpora carried **~3,300 distinct raw city strings** for roughly 1,000 | |
| 91 | −real municipalities. Deterministic rules + a slug-grouping election pass fix, | |
| 92 | −among others: orphan parentheses (`Brossard )`), never-closed parentheses | |
| 93 | −(`Gatineau (Hôpital`), duplicated names (`Gatineau (Gatineau)`), boroughs | |
| 94 | −glued in both orders (`Montréal (Ville-Marie)` vs `Ville-Marie (…)`), merged | |
| 95 | −municipalities (`Saint-Hubert (Longueuil)`), English variants (`Québec City`, | |
| 96 | −`Montreal Downtown`, `City Of Montréal`), lost accents/hyphens | |
| 97 | −(`Trois Rivieres`, `Mont Tremblant`), mojibake (`Montrã©al`) and marketing | |
| 98 | −labels (`Longueuil / South Shore`). The full raw→canonical mapping is persisted | |
| 99 | −in the `city_map` table for auditing (`python3 run.py villes`). | |
| 100 | − | |
| 101 | −### Dual-accent design system | |
| 102 | − | |
| 103 | −Single "sharp editorial" design system (Space Grotesk / Inter / JetBrains Mono, | |
| 104 | −ink borders, offset shadows) with an accent that **follows the universe**: | |
| 105 | −Lou-Ka electric lime in *Louer* mode, Immo-Ka red in *Acheter* mode, terracotta | |
| 106 | −for the Toit-Ka brand itself. The switch is one `html[data-mode]` attribute. | |
| 107 | − | |
| 108 | −## Features | |
| 109 | − | |
| 110 | −- Home page with a central **Louer / Acheter toggle** — filters, price steps, | |
| 111 | − quick chips and stats all adapt to the selected universe. | |
| 112 | −- Search by city (canonical), price, type (3½…6½+, Studio, Condo, Maison, | |
| 113 | − Plex, Terrain…), bedrooms/bathrooms, area, pets, furnished, free text. | |
| 114 | −- List + **3D map view** (Ka Maps / Mapbox GL) with per-universe markers | |
| 115 | − (lime rent pills, ink sale pills), "search this area", React previews. | |
| 116 | −- Full listing page: gallery + lightbox, specs, description, walkability rings | |
| 117 | − mini-map, link to the original ad. | |
| 118 | −- **Programmatic SEO** rendered server-side: `/louer/{ville}`, | |
| 119 | − `/acheter/{ville}`, `/{tx}/{ville}/{type}`, `/{tx}/type/{type}` with average | |
| 120 | − and median rent/price, breadcrumbs, JSON-LD, sitemaps, 301 canonical slugs, | |
| 121 | − 410 for withdrawn listings. | |
| 122 | −- **KA ID single sign-on** (groupe-ka.com identity hub) + favorites stored | |
| 123 | − centrally in "Mon univers Ka". | |
| 124 | −- Mobile-first, French (Québec). | |
| 125 | − | |
| 126 | −## Repository layout | |
| 208 | +### Pourquoi zéro scraping ? | |
| 209 | + | |
| 210 | +Lou-Ka et Immo-Ka font déjà le travail dur (des centaines de connecteurs, | |
| 211 | +files de quarantaine, audits d'images, dédup). Toit-Ka **hérite** de ce | |
| 212 | +travail : `toitka/replicate.py` tire, toutes les 30 minutes, un snapshot | |
| 213 | +cohérent de chaque BD de prod (`sqlite3 .backup` côté source puis `rsync` via | |
| 214 | +le LAN du cluster), en **lecture seule** — aucune écriture, aucun verrou, | |
| 215 | +aucune charge sur les sites de prod. Le pipeline est idempotent : chaque passe | |
| 216 | +reconstruit l'état publié et gère le cycle de vie (nouvelles annonces, | |
| 217 | +retraits → 410). | |
| 218 | + | |
| 219 | +### Le moteur de normalisation des villes (`toitka/villes.py`) | |
| 220 | + | |
| 221 | +Les deux corpus totalisaient **~3 300 chaînes de villes brutes distinctes** | |
| 222 | +pour environ 1 000 municipalités réelles. Des règles déterministes plus une | |
| 223 | +passe d'élection par regroupement de slugs corrigent, entre autres : | |
| 224 | +parenthèses orphelines (`Brossard )`), parenthèses jamais fermées | |
| 225 | +(`Gatineau (Hôpital`), noms dupliqués (`Gatineau (Gatineau)`), arrondissements | |
| 226 | +collés dans les deux sens (`Montréal (Ville-Marie)` vs `Ville-Marie (…)`), | |
| 227 | +municipalités fusionnées (`Saint-Hubert (Longueuil)`), variantes anglaises | |
| 228 | +(`Québec City`, `Montreal Downtown`, `City Of Montréal`), accents/traits | |
| 229 | +d'union perdus (`Trois Rivieres`, `Mont Tremblant`), mojibake (`Montrã©al`) et | |
| 230 | +libellés marketing (`Longueuil / South Shore`). Le mapping complet | |
| 231 | +brut → canonique est persisté dans la table `city_map` pour audit | |
| 232 | +(`python3 run.py villes`). | |
| 233 | + | |
| 234 | +### La typologie unifiée (`toitka/typologie.py`) | |
| 235 | + | |
| 236 | +Le locatif parle en « pièces et demie » (3½, 4½…), la vente en catégories | |
| 237 | +(condo, maison, plex, terrain…). `typologie.py` fond les deux vocabulaires en | |
| 238 | +un seul référentiel de types, utilisé par les filtres, les stats et les pages | |
| 239 | +SEO par type — pour que « 4½ à Montréal » et « condo à Québec » vivent dans le | |
| 240 | +même moteur de recherche. | |
| 241 | + | |
| 242 | +--- | |
| 243 | + | |
| 244 | +## API & routes | |
| 245 | + | |
| 246 | +### API JSON (FastAPI — `toitka/web.py`) | |
| 247 | + | |
| 248 | +| Route | Description | | |
| 249 | +|---|---| | |
| 250 | +| `GET /api/listings` | recherche paginée (tx, ville, prix, type, chambres, sdb, superficie, animaux, meublé, texte…) | | |
| 251 | +| `GET /api/listings/{uid}` | détail d'une annonce (uid préfixé `lou:` / `immo:` selon l'origine) | | |
| 252 | +| `GET /api/listings.geojson` | flux GeoJSON pour la carte (bbox, filtres) | | |
| 253 | +| `GET /api/facets` | facettes live (villes, types, paliers de prix) selon l'univers | | |
| 254 | +| `GET /api/stats` | statistiques agrégées par univers + journal des passes ETL | | |
| 255 | +| `GET /api/health` | santé (`ok`, nb d'annonces, timestamp du dernier ETL) | | |
| 256 | +| `GET /api/seo/resolve` | résolution slug → entité pour le routage SPA | | |
| 257 | +| `GET /api/auth/*` | SSO KA ID (JWT HS256, stdlib uniquement) | | |
| 258 | +| `GET/POST/DELETE /api/favorites/*` | favoris centralisés « Mon univers Ka » | | |
| 259 | + | |
| 260 | +### Routes SEO rendues côté serveur (`toitka/seo.py`) | |
| 261 | + | |
| 262 | +| Route | Contenu | | |
| 263 | +|---|---| | |
| 264 | +| `/louer/{ville}` · `/acheter/{ville}` | page ville par univers (moyennes, médianes, annonces, JSON-LD) | | |
| 265 | +| `/{tx}/{ville}/{type}` | page ville × type | | |
| 266 | +| `/{tx}/type/{type}` | page type provinciale | | |
| 267 | +| `/annonce/{uid}/{slug}` | fiche annonce (canonique 301 si slug obsolète, **410** si retirée) | | |
| 268 | +| `/robots.txt` · `/sitemap.xml` · `/sitemaps/{name}` | indexation programmatique | | |
| 269 | + | |
| 270 | +Les autres chemins servent la SPA React (catch-all `/{full_path:path}`). | |
| 271 | + | |
| 272 | +--- | |
| 273 | + | |
| 274 | +## Structure du dépôt | |
| 127 | 275 | |
| 128 | 276 | ``` |
| 129 | −run.py CLI: serve | etl | watch | replicate | villes | |
| 277 | +run.py CLI unique : serve | etl | watch | replicate | villes | |
| 278 | +requirements.txt FastAPI + uvicorn (volontairement minimal) | |
| 130 | 279 | toitka/ |
| 131 | − db.py unified schema (toitka.db) + read-only source connections | |
| 132 | − villes.py canonical city mapping engine | |
| 133 | − typologie.py unified type vocabulary (rent + sale) | |
| 134 | − etl.py replicas -> toitka.db (visibility rules, lifecycle) | |
| 135 | − replicate.py LAN pull of production snapshots (sqlite .backup + rsync) | |
| 136 | − web.py FastAPI JSON API + SPA serving | |
| 137 | − seo.py server-side SEO rendering, robots.txt, sitemaps | |
| 138 | − auth.py KA ID SSO (JWT HS256, stdlib only) | |
| 139 | − hubprofile.py member profile read from the Groupe KA hub | |
| 140 | − hubfav.py favorites.py central favorites ("Mon univers Ka") | |
| 141 | −frontend/ React 18 + Vite + TypeScript SPA (dual-accent theme) | |
| 280 | + db.py schéma unifié (toitka.db) + connexions sources lecture seule | |
| 281 | + villes.py moteur de canonicalisation des villes (~3 300 variantes → city_map) | |
| 282 | + typologie.py vocabulaire de types unifié (locatif + vente) | |
| 283 | + etl.py répliques -> toitka.db (règles de visibilité, cycle de vie) | |
| 284 | + replicate.py tirage LAN des snapshots de prod (sqlite .backup + rsync) | |
| 285 | + web.py API JSON FastAPI + service de la SPA | |
| 286 | + seo.py rendu SEO côté serveur, robots.txt, sitemaps | |
| 287 | + auth.py SSO KA ID (JWT HS256, stdlib uniquement) | |
| 288 | + hubprofile.py profil membre lu depuis le hub Groupe KA | |
| 289 | + hubfav.py favorites.py favoris centralisés (« Mon univers Ka ») | |
| 290 | +frontend/ SPA React 18 + Vite + TypeScript (thème bi-accent) | |
| 291 | + src/pages/ Home, Category, Listing, Stats, Profil, Legal | |
| 292 | + src/components/ ListingCard, MapView, PropertyMap, Icons | |
| 293 | + src/kamaps/ adaptateur Ka Maps (Mapbox GL 3D) | |
| 294 | +docs/screenshots/ visite/ (10 JPG 2026-08-28) + mobile/ + desktop/ (webp 2026-08-25) | |
| 295 | +data/ (ignoré par git) réplicas + toitka.db — plusieurs Go | |
| 142 | 296 | ``` |
| 143 | 297 | |
| 144 | −## Running locally | |
| 298 | +> Le frontend dépend de `@groupe-ka/ka-maps` en `file:../../ka-maps` : le | |
| 299 | +> framework cartographique partagé du Groupe Ka doit être présent à côté du | |
| 300 | +> repo (`~/apps/ka-maps` sur le nœud) pour `npm install`. | |
| 301 | + | |
| 302 | +--- | |
| 303 | + | |
| 304 | +## Lancer en local | |
| 145 | 305 | |
| 146 | 306 | ```bash |
| 147 | −# point the ETL at local copies of the source DBs (.env) | |
| 148 | −python3 run.py etl # build data/toitka.db | |
| 149 | −python3 run.py serve 8097 # http://localhost:8097 | |
| 150 | −cd frontend && npm install && npm run build # SPA served by the backend | |
| 307 | +# 1. Config : .env pointe l'ETL vers des copies locales des BD sources | |
| 308 | +# (jamais commité — voir .gitignore) | |
| 309 | +# 2. Construire la base unifiée | |
| 310 | +python3 run.py etl # répliques -> data/toitka.db | |
| 311 | +# ou en continu : | |
| 312 | +python3 run.py watch 30 # replicate (si configuré) + etl toutes les 30 min | |
| 313 | + | |
| 314 | +# 3. Backend + SPA | |
| 315 | +python3 run.py serve 8097 # http://localhost:8097 | |
| 316 | +cd frontend && npm install && npm run build # la SPA est servie par le backend | |
| 151 | 317 | ``` |
| 152 | 318 | |
| 153 | −## Production (MacLustr cluster) | |
| 319 | +--- | |
| 320 | + | |
| 321 | +## Production (cluster MacLustr) | |
| 322 | + | |
| 323 | +| Élément | Valeur | | |
| 324 | +|---|---| | |
| 325 | +| Nœud | **M3U96a** — `~/apps/toit-ka` | | |
| 326 | +| Port | **8097** | | |
| 327 | +| PM2 | `toit-ka-web` (uvicorn :8097) · `toit-ka-etl` (`run.py watch` — replicate + ETL toutes les 30 min) · `toit-ka-ngrok` | | |
| 328 | +| Tunnel | `ngrok http --url=www.toit-ka.com 8097` | | |
| 329 | +| Santé | `GET /api/health` → `{"ok": true, "listings": …, "last_etl": …}` | | |
| 330 | +| Sources | lou-ka (M3U96b) et immo-ka (M4M64a), snapshots lecture seule via LAN | | |
| 331 | +| Dépôt | **spbgit** (git perso du cluster) — `~/srv/git/toit-ka.git` sur M3U96a | | |
| 332 | + | |
| 333 | +Développement **remote-first** comme toutes les apps Ka : la source de vérité | |
| 334 | +est le repo git sur le nœud, pas une copie laptop. | |
| 335 | + | |
| 336 | +--- | |
| 337 | + | |
| 338 | +## Écosystème Groupe Ka | |
| 154 | 339 | |
| 155 | −- Node **M3U96a**, `~/apps/toit-ka`, PM2: `toit-ka-web` (port 8097), | |
| 156 | − `toit-ka-etl` (replicate + ETL every 30 min), `toit-ka-ngrok` | |
| 157 | − (`ngrok http --url=www.toit-ka.com 8097`). | |
| 158 | −- Health: `GET /api/health`. | |
| 340 | +Toit-Ka est une application **[Groupe-Ka](https://www.groupe-ka.com)**, aux | |
| 341 | +côtés de Lou-Ka (location), Immo-Ka (vente), Vrai-Prix, Auto-Ka, Food-Ka, | |
| 342 | +Resto-Ka, Sorti-Ka, Job-Ka, Trouve-Ka, Créa-Ka, Fabri-Ka et des déclinaisons | |
| 343 | +canadiennes (House-Ka, Rent-Ka). Identité partagée **KA ID**, favoris | |
| 344 | +centralisés, design system ka-ui commun. | |
| 159 | 345 | |
| 160 | −## Author | |
| 346 | +## Auteur | |
| 161 | 347 | |
| 162 | 348 | **Simon-Pierre Boucher** — [contact@spboucher.ai](mailto:contact@spboucher.ai) |
| 163 | 349 | |
| 164 | −Toit-Ka is a **Groupe-Ka** application ([groupe-ka.com](https://www.groupe-ka.com)). | |
| 165 | −Listing data belongs to its respective sources; every card links to the | |
| 166 | −original ad. | |
| 350 | +Les données d'annonces appartiennent à leurs sources respectives ; chaque | |
| 351 | +fiche renvoie vers l'annonce originale. | |
added
docs/screenshots/visite/01-accueil.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/02-annonce-immo-3Aabbeyandolivier-3A11701844-5334-rue-waverly-m.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/03-accueil.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/04-stats.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/05-profil.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/06-conditions.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/07-confidentialite.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/08-accueil-section-1.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/09-accueil-section-2.jpg
+0 −0
Binary file not shown.
added
docs/screenshots/visite/10-accueil-mobile.jpg
+0 −0
Binary file not shown.
deleted
frontend/tsconfig.tsbuildinfo
+0 −1
@@ -1 +0,0 @@ | ||
| 1 | −{"root":["./src/app.tsx","./src/account.tsx","./src/api.ts","./src/main.tsx","./src/vite-env.d.ts","./src/components/icons.tsx","./src/components/listingcard.tsx","./src/components/mapview.tsx","./src/components/propertymap.tsx","./src/kamaps/adapter.ts","./src/kamaps/config.ts","./src/kamaps/theme.ts","./src/pages/category.tsx","./src/pages/home.tsx","./src/pages/legal.tsx","./src/pages/listing.tsx","./src/pages/profil.tsx","./src/pages/stats.tsx"],"version":"5.9.3"} | |
| \ No newline at end of file | ||
| 2 | ||