 Accueil — héros typographique « Chaque resto, chaque plat, chaque prix », recherche par resto ou par plat, bande « signes vitaux » live (restos, plats, menus, régions) sur fond encre. |
 Répertoire des villes (/villes) — les villes du Québec classées par région administrative, avec le compte de restos ; pages SEO indexables. |
 Statistiques (/stats) — tableau de bord complet : volumes par région, contextes de prix, chaînes, inspections, sources ; rapports PDF (catalogue + ReportBuilder personnalisé). |
 Sources (/sources) — le registre public des 17 sources de données : rôle, statut, cadence et dernières synchronisations, en toute transparence. |
 Contact (/contact) — coordonnées du Groupe KA, formulaire, et liens vers les autres plateformes de l'écosystème. |
 Page ville — Montréal (/ville/montreal) — près de 12 000 restos montréalais, filtres par cuisine et type, cartes à filets d'encre avec ombre safran au survol. |
 Fiche restaurant (/resto/<uid>) — panneau héros (nom, cuisine, adresse), coordonnées et horaires structurés, menu par contexte de prix, inspections MAPAQ et permis d'alcool, carte. |
 Favoris (/favoris) — « Mon univers Ka » : les restos sauvegardés avec le compte unique KA ID, partagés entre les 12 plateformes du groupe. |
 Documentation (/doc/) — guide d'utilisation illustré en 4 étapes + version PDF téléchargeable. |
 Accueil mobile (390×844) — recherche plein pouce, signes vitaux compacts et KA Tabbar (barre de navigation mobile commune Groupe KA). |
> 🗄️ Les captures du front-end v2 du 2026-08-25 (webp) restent dans [`docs/screenshots/mobile/`](docs/screenshots/mobile/) et [`docs/screenshots/desktop/`](docs/screenshots/desktop/) ; les captures d'époque sont conservées dans [`docs/archive/`](docs/archive/).
### Nouveautés front-end (2026-08-25)
- **Front-end v2 « éditorial premium »** — bande signes vitaux pleine largeur (chiffres géants tabulaires sur fond encre), nav soulignée, héros typographique agrandi, cartes/plats/menus/filtres allégés (filets d'encre au lieu de boîtes), ombre safran signature au survol.
- **KA Tabbar v1** — barre de navigation mobile commune Groupe KA.
- **7 nouvelles sources** — mtl-alim, Tastet, ChowNow, GloriaFood, Square, DoorDash, Skip + hub de découverte multi-plateformes.
- **Widget ka-agent v4** — cartes de restos cliquables et choix en boutons.
## Fonctionnalités
- **Prix réels et contextualisés** — un prix n'est jamais présenté sans son contexte (`dine-in` / `takeout` / `delivery`) ; un menu sans `price_context`/`price_source` est rejeté à l'ingestion, et un menu salle n'est jamais écrasé par un menu livraison.
- **Recherche par plat** dans les 163 677 items (au 2026-08-28), groupée par marque (pour ne pas répéter la même poutine de chaîne des dizaines de fois).
- **Options & formats capturés** avec leurs suppléments (« Mini +3,70 $ ») — ils changent le prix réel.
- **Historique des prix par item** (`item_price_log`, 155 000+ entrées) à chaque changement.
- **Alerte de dérive** — chute anormale du volume d'une source ou du nombre d'items d'un menu → retraits suspendus / ancien menu conservé (visible dans les syncs récents : les runs partiels de Tastet sont signalés et les retraits suspendus).
- **Déduplication inter-sources** (les succursales ne sont jamais fusionnées) et **géocodage à 100 %** (Nominatim + Adresses Québec, cache persistant).
- **Découverte OpenStreetMap** (API Overpass) : 14 008 établissements nommés au dernier passage — restos, fast-foods, cafés, bars, crèmeries, boulangeries — dans les 17 régions, complétée par le **registre alimentaire de la Ville de Montréal** (`mtl-alim`, 7 574 établissements, données ouvertes) et le média resto **Tastet** ; **connecteur UEAT templatisé** (API GraphQL) pour les menus takeout réels de **116+ intégrations de chaînes découvertes** (Sushi Shop, Valentine, Normandin, Thaïzone, Chez Ashton…).
- **Découverte des sites web** des restos (connecteur `site-finder`, Serper /maps — sites, téléphones, liens de réservation) et **extraction des menus + photos** depuis les sites des restos (`site-resto`).
- **Hub multi-plateformes de commande** : connecteurs templatisés ChowNow, GloriaFood et Square Online (menus takeout réels, activés dès qu'une intégration est découverte par `site-finder`).
- **Enrichissements officiels** : inspections MAPAQ (3 001 importées, 661 appariées à 443 restos) et permis d'alcool RACJ (3 001 restos).
- **Avis & notes** : Yelp par scraping quotidien (220 restos notés) et croisement des plateformes de livraison Uber Eats, DoorDash et Skip (prix marqués `delivery`, jamais prioritaires).
- **Connexion KA ID** (SSO Groupe KA), favoris unifiés « Mon univers Ka », recommandations personnalisées (moteur `kaid` v2, filtrage collaboratif ALS), tableau de bord `/stats` + rapports PDF (catalogue + ReportBuilder), widget **KA Agent v4** (chat IA, cartes de restos cliquables).
- **Registre des sources** — `data/sources.json` (**17 sources**), exposé publiquement sur [/sources](https://www.resto-ka.com/sources), à consulter avant tout ajout (statut et raison des sources non connectables).
## Démarrage rapide
```bash
# Backend
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
# Frontend (build servi par FastAPI)
cd frontend && npm install && npm run build && cd ..
# ou en dev : cd frontend && npm run dev
# Lancer
.venv/bin/python run.py sync # synchronise (+ géocode + dédup)
.venv/bin/python run.py serve 8115 # API + frontend sur :8115
.venv/bin/python run.py watch 168 # boucle hebdomadaire (heures)
# Tests (110 tests pytest, fixtures réelles hors ligne)
.venv/bin/python -m pytest tests/
```
## API (endpoints)
Servis par `restoka/web.py` (FastAPI) sur le port 8115.
| Méthode | Endpoint | Description |
|---|---|---|
| `GET` | `/api/restaurants` | recherche de restos (ville, région, cuisine, texte libre, `uids=`, pagination) |
| `GET` | `/api/restaurants/{uid}` | fiche complète : menu structuré par contexte de prix, photos, coordonnées, horaires |
| `GET` | `/api/restaurants/{uid}/prices` | historique des prix des items du resto (`item_price_log`) |
| `GET` | `/api/restaurants/{uid}/inspections` | inspections/permis (enrichissements MAPAQ + RACJ) |
| `GET` | `/api/dishes` | recherche par plat dans les 163 677 items, groupée par marque |
| `GET` | `/api/facets` | facettes de filtres (régions, villes, cuisines, types) |
| `GET` | `/api/sources` | registre des sources (statuts, cadences) — alimente la page `/sources` |
| `GET` | `/api/stats` | statistiques publiques JSON (alimente les pastilles ci-dessus) |
| `GET` | `/api/stats/dashboard` | données du tableau de bord `/stats` |
| `GET` | `/api/stats/report` | rapport PDF principal |
| `GET` | `/api/stats/catalog` | catalogue des rapports disponibles |
| `POST` | `/api/stats/report/custom` | rapport PDF personnalisé (ReportBuilder) |
| `GET` | `/api/favorites` | favoris « Mon univers Ka » (session KA ID) |
| `POST` | `/api/favorites/toggle` | ajout/retrait d'un favori |
| `POST` | `/api/sync` | déclenchement d'une synchronisation |
| `GET` | `/healthz` | santé du service (`{"status":"ok"}`) |
| `GET` | `/doc/` | guide d'utilisation en ligne |
| `GET` | `/{full_path}` | SPA + pages SSR légères (accueil, fiches JSON-LD, /villes, /ville/:slug) |
## Connecteurs
Auto-enregistrés dans `restoka/connectors/` (requests direct / Firecrawl / Scrapfly + cache détail dans `base.py`, résilience `_resilient.py`, chaîne anti-bot Oxylabs → Scrapfly → Bright Data) :
| Connecteur | Famille | Rôle | Cadence |
|---|---|---|---|
| `osm` | découverte | OpenStreetMap (Overpass, miroirs fiabilisés) — 14 008 établissements nommés, 17/17 régions | mensuelle |
| `mtl-alim` | découverte | registre des établissements alimentaires de la Ville de Montréal (données ouvertes) — 7 574 établissements | mensuelle |
| `tastet` | découverte / éditorial | restos recensés par le média Tastet (sélections montréalaises) | hebdomadaire |
| `sitefinder` | découverte | sites web / téléphones / liens de réservation / plateformes de commande des restos (Serper /maps) | hebdo par lots (3 000 req.), échecs re-sondés 180 j |
| `ueat` | menus takeout (tier 1) | connecteur templatisé UEAT (API GraphQL) — menus takeout réels de 116+ intégrations découvertes | hebdomadaire |
| `siteresto` | menus salle | menus + photos publiés sur le site des restos indépendants | hebdo (batch incrémental), re-crawl mensuel |
| `chownow` | menus takeout | connecteur templatisé ChowNow — dormant (activé dès qu'une intégration est découverte) | hebdomadaire |
| `gloriafood` | menus takeout | connecteur templatisé GloriaFood — dormant (activé dès qu'une intégration est découverte) | hebdomadaire |
| `squareonline` | menus takeout | connecteur templatisé Square Online — 1 intégration active | hebdomadaire |
| `ubereats` | livraison | complément livraison (prix `delivery`, jamais prioritaires sur un menu salle) | quotidienne par petits lots (60 pages), re-vérif 30 j |
| `doordash` | livraison | croisement DoorDash (menus `delivery`) | quotidienne par petits lots |
| `skip` | livraison | croisement SkipTheDishes (menus `delivery`) | quotidienne par petits lots |
| `yelp` | annuaire | enrichissement via l'API Yelp Fusion (clé requise — SkipSource sans `YELP_API_KEY`) | hebdo, re-vérification 30 j |
| `yelp_scrape` | annuaire | notes, nombre d'avis, gamme de prix, catégories, fermetures via yelp.ca | quotidienne par petits lots (80 pages), re-vérif 30 j |
S'y ajoutent deux **enrichissements officiels** exécutés par `ingest.enrich` (garde-fou 6 jours) : `mapaq` (inspections) et `racj` (permis d'alcool), tous deux hebdomadaires.
## Données & conformité
- **Registre des sources** : `data/sources.json` — **17 sources** au 2026-08-28 (**12 actives**, 3 dormantes en attente d'intégrations découvertes : chownow, gloriafood, square, 1 « clé requise » : yelp, 1 « à faire » : sthubert). À consulter **avant** tout ajout de source (CLAUDE.md §0.4) : chaque entrée documente l'accès légal, l'extraction et la cadence. Version publique : [/sources](https://www.resto-ka.com/sources).
- **Prix de première partie** : les menus takeout viennent de la plateforme de commande des restos eux-mêmes (UEAT — la même API GraphQL que le widget officiel, auth anonyme publique ; ChowNow/GloriaFood/Square Online templatisés) ou de leur propre site — **prix réels non majorés**. Les menus salle (`site-resto`) et takeout passent toujours avant les plateformes de livraison.
- **Scraping poli** : throttling (0,35 s sur UEAT), User-Agent identifiable `RestoKaBot`, budgets par passage (Yelp 450 req/j, site-finder 3 000 req, Uber Eats 60 pages/j, DoorDash/Skip par petits lots).
- **Données publiques officielles** : inspections MAPAQ, permis d'alcool RACJ et registre alimentaire de la Ville de Montréal (jeux de données gouvernementaux/municipaux ouverts).
- **Cadence de resync** : boucle `run.py watch 168` (cycle hebdomadaire) ; les sources quotidiennes (yelp-scrape, ubereats, doordash, skip) avancent par petits lots à chaque passage ; alertes de dérive + délai de grâce avant tout retrait.
- La base SQLite de prod (`data/restoka.db`) est **gitignorée** ; aucun secret dans le repo (`.env` local, gabarit `.env.example`).
## Architecture
Pipeline (patron Lou·Ka) : **connecteurs → normalisation → déduplication → SQLite → API/frontend**.
- **Backend Python 3.14 / FastAPI / Uvicorn** (`restoka/web.py`) : API + service du build Vite + SSR léger SEO (JSON-LD Restaurant, sitemaps chunkés, pages /villes).
- **SQLite** (`restoka/db.py`) : restos, **menus par contexte de prix**, historique de prix (`item_price_log`), inspections, favoris, caches détail/géocodage.
- **Connecteurs auto-enregistrés** (`restoka/connectors/`) : requests direct / Firecrawl / Scrapfly + cache détail (`base.py`), UEAT templatisé (`ueat.py`), hub multi-plateformes (chownow/gloriafood/squareonline), découverte Overpass/OSM + mtl-alim + Tastet.
- **Ingestion** (`restoka/ingest.py`) : sync → geocode → dedup, délai de grâce et alertes de dérive ; enrichissements inspections/permis/heures.
- **Structuration LLM** (`restoka/menullm.py`) : menus maison structurés par Claude (API Anthropic).
- **Frontend React 18 + Vite + TypeScript** (`frontend/`), design « éditorial premium » Groupe KA (v2 2026-08-25).
- **110 tests pytest** avec fixtures réelles hors ligne (connecteurs, normalisation, schéma, horaires, permis…).
Processus PM2 sur le nœud (commandes de start réelles) :
| Processus | Rôle | Commande | Cadence |
|---|---|---|---|
| `resto-ka` | serveur FastAPI (API + frontend) sur le port **8115** | `.venv/bin/python run.py serve 8115` | continu |
| `resto-ka-sync` | boucle de synchronisation | `.venv/bin/python run.py watch 168` | cycle hebdomadaire (168 h) |
| `resto-ka-ngrok` | tunnel vers **www.resto-ka.com** | `ngrok http --url=www.resto-ka.com 8115` | continu |
## Variables d'environnement
Gabarit : `.env.example` (copier vers `.env`, jamais commité). **Noms seulement — aucune valeur dans le repo.**
| Variable | Rôle |
|---|---|
| `SCRAPFLY_KEY` | rendu JS + bypass anti-bot (plateformes de livraison) |
| `ANTHROPIC_API_KEY` | structuration des menus maison par Claude (`restoka/menullm.py`) |
| `FIRECRAWL_API_KEY` | rendu JS de secours pour les sites de restos SPA (`site-resto`) |
| `YELP_API_KEY` | API Yelp Fusion (sans clé : source sautée proprement) |
| `YELP_BUDGET` | budget de requêtes Yelp par passage (quota quotidien 500) |
| `SERPER_API_KEY` | Google Maps via Serper — découverte des sites web (`site-finder`) |
| `SITE_FINDER_BUDGET` | budget de requêtes Serper par passage (défaut 3 000) |
| `KA_SSO_SECRET` | SSO Groupe KA (« Se connecter avec KA ») |
| `SESSION_SECRET` | sessions signées |
| `RESTOKA_BASE_URL` | URL publique du site (défaut `https://www.resto-ka.com`) |
## Structure du repo
```
resto-ka/
├── run.py # point d'entrée CLI (sync / watch / serve)
├── restoka/ # cœur Python : web, db, ingest, dedup, geocode, regions, schema, normalize, auth, stats, menullm… + connectors/
├── frontend/ # React 18 + Vite + TypeScript — design éditorial premium Groupe KA + public/doc/ (guide)
├── data/ # sources.json (registre), ueat-discovered.json (intégrations), base SQLite de prod (gitignorée)
├── scripts/ # scripts d'appoint (captures, déploiement)
├── tests/ # 110 tests pytest (fixtures réelles hors ligne)
└── docs/ # screenshots/ (visite guidée + v2 webp), archive/, connecteurs/ (docs par source)
```
## Documentation
- **Guide en ligne** : [www.resto-ka.com/doc/](https://www.resto-ka.com/doc/) — à quoi sert le site, le parcours en 4 étapes (recherche → restos d'une ville → fiche → /stats), d'où viennent les données, FAQ.
- **Guide PDF** : [resto-ka-documentation.pdf](https://www.resto-ka.com/doc/resto-ka-documentation.pdf) — la même documentation, téléchargeable.
- **Docs des connecteurs** : [`docs/connecteurs/`](docs/connecteurs/) — une fiche par source (accès, extraction, cadence, gotchas), index dans `INDEX.md`.
- Les captures du guide sont versionnées dans `frontend/public/doc/img/` (etape1 → etape4).
## Développement (remote-first)
**La source de vérité est le repo git sur le nœud M3U96b** (`~/apps/resto-ka`) — on n'édite jamais les copies laptop. Toute modification se fait sur le nœud via SSH : édition, build, `pm2 restart`, puis commit/push depuis le nœud.
- Remote `origin` = **spbgit** (git perso [git.spboucher.ai](https://git.spboucher.ai), bare repos sur M3U96a). **Pas GitHub.**
- L'agent forwarding SSH est actif : le `git push origin main` fonctionne pendant une session SSH depuis le laptop.
- `CLAUDE.md` est la source de vérité du projet (règles d'ingestion, en-têtes d'auteur obligatoires).
```bash
pm2 restart resto-ka # après un changement en production
```
## Déploiement
- **Nœud** : M3U96b (Mac Studio, cluster MacLustr) — répertoire `~/apps/resto-ka`
- **Port** : **8115** (local, exposé uniquement via le tunnel)
- **Processus PM2** : `resto-ka` (serveur) + `resto-ka-sync` (synchro) + `resto-ka-ngrok` (tunnel)
- **Domaine** : **https://www.resto-ka.com** (tunnel ngrok)
## Historique
Jalons tirés du `git log` :
- **2026-08-17** — naissance : pipeline connecteurs→SQLite→API (patron Lou·Ka), assets Groupe KA, tableau de bord `/stats` + rapport PDF, câblage du widget KA Agent.
- **2026-08-18** — vagues 2-3 d'enrichissement : inspections MAPAQ, horaires structurés, Yelp (API + scraping), avis/notes sans clé, menus livraison, permis d'alcool ; documentation standardisée des sources.
- **2026-08-19** — Stats v2 (dashboard complet + 5 rapports PDF), campagne mobile (menus tactiles, tabbar), KA Agent v2 plein écran, standard « panneau héro premier dans le DOM ».
- **2026-08-22** — SEO : SSR léger (JSON-LD Restaurant), sitemaps chunkés, robots.txt ; chaîne de fetch anti-bot résiliente (Oxylabs → Scrapfly → Bright Data) ; section « Récemment consultés ».
- **2026-08-23** — connecteur `site-finder` (Serper /maps), photos extraites des sites des restos, Stats v3 (rapports PDF personnalisés, ReportBuilder), favoris unifiés « Mon univers Ka », pages SEO /villes ; 32 → 116 intégrations UEAT découvertes.
- **2026-08-24** — page documentation `/doc` (guide + captures + PDF), refonte du README (v2 puis v3), mise à jour du répertoire UEAT.
- **2026-08-25** — front-end v2 « éditorial premium », KA Tabbar v1, **7 nouvelles sources** (mtl-alim, Tastet, ChowNow, GloriaFood, Square, DoorDash, Skip) + hub de découverte multi-plateformes, widget ka-agent v4 ; le volume passe de ~14,7 k à 21 k+ restos.
- **2026-08-26/27** — KA ID v2 : recommandations personnalisées (`kaid.py`, filtrage collaboratif ALS, pilules « Sauvegarder cette recherche »/« Pas pour moi »), alignées sur `ka-ui.git`.
- **2026-08-28** — README v4 : visite guidée en 10 captures live (`docs/screenshots/`), chiffres et registre des sources à jour.
## Écosystème Groupe KA
| Plateforme | Vocation |
|---|---|
| [groupe-ka.com](https://www.groupe-ka.com) | portail du groupe et compte unique KA ID |
| [lou-ka.com](https://www.lou-ka.com) | logements à louer |
| [immo-ka.com](https://www.immo-ka.com) | propriétés à vendre |
| [vrai-prix.com](https://www.vrai-prix.com) | estimation immobilière |
| [auto-ka.com](https://www.auto-ka.com) | véhicules |
| [fabri-ka.com](https://www.fabri-ka.com) | produits québécois |
| [food-ka.com](https://www.food-ka.com) | épicerie et alimentation |
| [resto-ka.com](https://www.resto-ka.com) | restaurants *(ce repo)* |
| [sorti-ka.com](https://www.sorti-ka.com) | sorties et événements |
| [job-ka.com](https://www.job-ka.com) | emplois |
| [crea-ka.com](https://www.crea-ka.com) | créateurs de contenu |
| [trouve-ka.com](https://www.trouve-ka.com) | petites annonces |
| [api-ka.com](https://www.api-ka.com) | API de données |
## Contact
**Simon-Pierre Boucher** — fondateur, Groupe KA
📧 [contact@spboucher.ai](mailto:contact@spboucher.ai)
---
© Groupe KA — Simon-Pierre Boucher · contact@spboucher.ai
Ce repo vit sur **spbgit** ([git.spboucher.ai](https://git.spboucher.ai)).