 Accueil — recherche par resto ou par plat (desktop) |
 Accueil — version mobile |
 Étape 1 · Cherchez un resto ou un plat depuis l'accueil |
 Étape 2 · Parcourez les restos d'une ville |
 Étape 3 · Ouvrez la fiche d'un restaurant |
 Étape 4 · Comparez le marché sur /stats |
 Accueil — variante pleine page |
 Fiche restaurant — menu structuré et prix contextualisés |
 Recherche par plat — 79 159 items, groupés par marque |
 Tableau de bord /stats — le marché resto en chiffres |
## 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 79 159 items, groupée par marque (pour ne pas répéter 76 fois la même poutine de chaîne).
- **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`) à 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é.
- **Déduplication inter-sources** (les succursales ne sont jamais fusionnées) et **géocodage à 99 %** (Nominatim + Adresses Québec, cache persistant).
- **Découverte OpenStreetMap** (API Overpass) : 13 500+ établissements nommés — restos, fast-foods, cafés, bars, crèmeries, boulangeries — dans les 17 régions ; **connecteur UEAT templatisé** (API GraphQL) pour les menus takeout réels de 29 intégrations de chaînes (Sushi Shop, Valentine, Normandin, Thaïzone, Chez Ashton…).
- **Connexion KA ID** (SSO Groupe KA), favoris unifiés « Mon univers Ka », tableau de bord `/stats` + rapports PDF (catalogue + ReportBuilder), widget **KA Agent** (chat IA).
- **Registre des sources** — `data/sources.json`, à consulter avant tout ajout (statut et raison des sources non connectables).
## API (endpoints principaux)
Servis par `restoka/web.py` (FastAPI) sur le port 8115.
| Endpoint | Rôle |
|---|---|
| `GET /api/restaurants` | recherche de restos (ville, région, cuisine, texte libre, pagination) |
| `GET /api/restaurants/{uid}` | fiche complète : menu structuré par contexte de prix, photos, coordonnées |
| `GET /api/restaurants/{uid}/prices` | historique des prix des items du resto |
| `GET /api/restaurants/{uid}/inspections` | inspections/permis (enrichissements MAPAQ) |
| `GET /api/dishes` | recherche par plat dans les 79 159 items, groupée par marque |
| `GET /api/facets` · `GET /api/sources` | facettes de filtres, registre des sources |
| `GET /api/stats` · `/api/stats/dashboard` · `/report` · `/catalog` · `POST /api/stats/report/custom` | tableau de bord + rapports PDF (catalogue et personnalisés) |
| `GET /api/favorites` · `POST /api/favorites/toggle` | favoris « Mon univers Ka » (session KA ID) |
| `POST /api/sync` | déclenchement d'une synchronisation |
| `GET /healthz` | santé du service |
| `GET /doc/` | guide d'utilisation en ligne |
## Connecteurs
Auto-enregistrés dans `restoka/connectors/` (requests direct / Firecrawl / Scrapfly + cache détail dans `base.py`, résilience `_resilient.py`) :
| Connecteur | Rôle |
|---|---|
| `osm` | découverte OpenStreetMap (Overpass) — 13 500+ établissements nommés, 17/17 régions |
| `ueat` | connecteur templatisé UEAT (API GraphQL) — menus takeout réels de 29 intégrations de chaînes |
| `siteresto` | menus publiés sur le site des restos indépendants |
| `sitefinder` | découverte du site web / de la plateforme de commande d'un resto |
| `ubereats` | complément livraison (prix marqués `delivery`, jamais prioritaires sur un menu salle) |
| `yelp` · `yelp_scrape` | enrichissement annuaire via yelp.ca (notes, nombre d'avis, gamme de prix, catégories, fermetures) |
## 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.
- **SQLite** (`restoka/db.py`) : restos, **menus par contexte de prix**, historique de prix.
- **Connecteurs auto-enregistrés** (`restoka/connectors/`) : requests direct / Firecrawl / Scrapfly + cache détail (`base.py`), UEAT templatisé (`ueat.py`), découverte Overpass/OSM.
- **Ingestion** (`restoka/ingest.py`) : sync → geocode → dedup, délai de grâce et alertes de dérive ; enrichissements inspections/permis/heures.
- **Frontend React 18 + Vite + TypeScript** (`frontend/`), design « éditorial sharp » Groupe KA.
- **45 tests pytest** avec fixtures réelles hors ligne.
Processus PM2 sur le nœud :
| Processus | Rôle | Cadence |
|---|---|---|
| `resto-ka` | serveur FastAPI (API + frontend) sur le port **8115** | continu |
| `resto-ka-sync` | boucle de synchronisation (`run.py watch 168`) | cycle hebdomadaire (168 h) |
| `resto-ka-ngrok` | tunnel ngrok vers **www.resto-ka.com** | continu |
Points de configuration notables (variables d'environnement, sans secrets dans le repo) : clés Scrapfly/Firecrawl des connecteurs, secret SSO partagé avec le hub KA ID. Le registre des sources vit dans `data/sources.json` ; la base SQLite de prod est gitignorée.
## 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… + connectors/
├── frontend/ # React 18 + Vite + TypeScript — design éditorial sharp Groupe KA + public/doc/ (guide)
├── data/ # sources.json (registre) + base SQLite de prod (gitignorée)
├── scripts/ # scripts d'appoint (captures, déploiement)
├── tests/ # 45 tests pytest (fixtures réelles hors ligne)
└── docs/ # captures d'écran + docs connecteurs
```
## 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.
- 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
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
cd frontend && npm install && npm run build && cd ..
.venv/bin/python run.py sync # synchronise (+ géocode + dédup)
.venv/bin/python run.py serve 8115 # API + frontend
.venv/bin/python run.py watch 168 # boucle hebdomadaire (heures)
.venv/bin/python -m pytest tests/ # 45 tests
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)
## É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)).