CLAUDE.md — Resto·Ka
Agrégateur exhaustif de tous les restaurants du Québec, avec leurs menus complets et leurs prix. Chaque resto, chaque plat, chaque prix — dans les 17 régions, au même endroit, comparable et cherchable.
Ce fichier est la source de vérité pour tout agent Claude (ou humain) qui travaille sur ce dépôt. Lis-le en entier avant d'écrire une seule ligne de code.
0. À LIRE EN PREMIER — Règles non négociables
-
En-tête d'auteur obligatoire. Chaque fichier du dépôt (code, config, doc, script) doit commencer par un en-tête mentionnant l'auteur :
Simon-Pierre Boucher <contact@spboucher.ai>. Voir la section 17 pour le format exact selon le type de fichier. Aucun fichier ne doit être commité sans cet en-tête. -
Inspire-toi du dépôt Lou·Ka. Avant de concevoir ou d'écrire le moindre connecteur, va lire le dépôt de Lou·Ka (le site jumeau, agrégateur de logements locatifs). Ses connecteurs sont le patron de référence : structure des modules, extraction (Firecrawl / Scrapfly), normalisation, déduplication, gestion des mises à jour, planification des tâches. Ne réinvente rien : reprends les mêmes conventions, la même architecture de connecteur, les mêmes utilitaires partagés. Resto·Ka doit être cohérent avec l'écosystème
·Ka(Lou·Ka, Immo·Ka, Auto·Ka, Food·Ka, Fabri·Ka, Sorti·Ka). Voir section 3. -
Travail de moine. L'agrégation de menus est un travail minutieux, source par source, plat par plat, sans rien précipiter. Un menu mal parsé (mauvais prix, plat manquant, option ignorée) détruit la confiance dans toute la base. Mieux vaut un connecteur robuste de plus que dix fragiles.
-
Vérifie l'existant avant d'ajouter. Avant d'intégrer un resto ou une source, confirme qu'il/elle n'est pas déjà couvert(e) (voir le registre des sources et l'index des restaurants, sections 9 et 12). Ne duplique jamais un connecteur ni une fiche resto. Un restaurant = une fiche canonique, quelles que soient les sources qui l'alimentent.
-
Chaque source a son connecteur sur mesure, mais les sources qui partagent une même plateforme (livraison, commande en ligne, POS, réservation) doivent être couvertes par un connecteur générique templatisé réutilisable. Voir section 8.
-
La provenance du prix est sacrée. Un prix de livraison (Uber Eats, DoorDash, Skip) est majoré de 25-30 % par rapport à la salle à manger. Ne jamais présenter un prix sans son contexte (
price_context). Voir sections 5 et 11.
1. Mission
Rendre visible, en un seul endroit, tous les restaurants du Québec avec leurs menus et leurs prix réels, dans les 17 régions — pour que quiconque puisse répondre à « qu'est-ce que je mange, où, et combien ça coûte ? » sans ouvrir quinze applis.
Ce qui nous distingue
Les plateformes existantes sont soit des apps de livraison (Uber Eats, Skip, DoorDash — menus complets mais prix majorés, périmètre limité aux restos inscrits et payants), soit des annuaires (Google, Yelp, TripAdvisor — avis et coordonnées, mais pas de menus structurés ni de prix comparables), soit des médias food (Tastet, RestoMontréal — éditorial, pas exhaustif).
Personne n'offre le menu complet + les prix de tous les restos, comparables entre eux, partout au Québec. C'est le créneau de Resto·Ka.
2. Périmètre — TOUS les établissements où l'on mange
Périmètre maximaliste. Si on peut y commander à manger, ça doit finir dans Resto·Ka :
- Restaurants (tous services : gastronomique, décontracté, familial).
- Fast-food & chaînes (menus standardisés, multi-succursales).
- Cafés & salons de thé (avec offre alimentaire).
- Bars & pubs avec cuisine.
- Comptoirs pour emporter, cantines, casse-croûtes, food trucks.
- Pizzérias, sushis, poulet, burgers, shawarma, etc.
- Boulangeries-pâtisseries et traiteurs avec menu et prix.
- Microbrasseries et établissements avec menu de bouffe.
- Restaurants d'hôtel, cuisines fantômes (ghost kitchens).
Règle d'or : en cas de doute sur l'inclusion, on inclut et on catégorise par type d'établissement. Le périmètre est large par conception.
3. Dépôts de référence — étudier Lou·Ka AVANT de coder
Resto·Ka fait partie de la famille ·Ka. Le dépôt de Lou·Ka est la référence
canonique pour l'architecture des connecteurs. Avant tout développement, l'agent
Claude doit :
- Ouvrir le dépôt de Lou·Ka et localiser le dossier des connecteurs
(typiquement
connectors/,scrapers/ousources/). - Lire 2 ou 3 connecteurs complets de bout en bout pour comprendre :
- la structure d'un module connecteur (interface commune, méthodes attendues) ;
- l'extraction (Firecrawl / Scrapfly, endpoints JSON, sitemaps) ;
- la normalisation vers le schéma commun ;
- la déduplication (annonces publiées sur plusieurs plateformes) ;
- la gestion des mises à jour (nouveautés, changements, retraits) ;
- la planification (cadence, files, retries, backoff), les erreurs et le logging.
- Réutiliser les utilitaires partagés de Lou·Ka (client Firecrawl/Scrapfly, helpers de normalisation, déduplication, géocodage) plutôt que d'en réécrire.
- Calquer les conventions de nommage, la structure des dossiers et le style de code de Lou·Ka. Un dev qui connaît Lou·Ka doit se retrouver immédiatement.
Adaptation propre à Resto·Ka : là où Lou·Ka normalise une annonce, Resto·Ka normalise un restaurant + un menu imbriqué (catégories → plats → prix → options). Le schéma est plus profond ; le reste du patron s'applique tel quel.
Si tu ne trouves pas le dépôt Lou·Ka ou l'accès aux connecteurs, arrête-toi et demande plutôt que d'inventer une architecture divergente.
Écosystème complet, pour contexte :
| Site | Domaine | Agrège |
|---|---|---|
| Lou·Ka | lou-ka.com | Logements à louer |
| Immo·Ka | immo-ka.com | Propriétés à vendre |
| Auto·Ka | auto-ka.com | Véhicules usagés |
| Food·Ka | food-ka.com | Prix d'épicerie & circulaires |
| Fabri·Ka | fabri-ka.com | Produits québécois |
| Sorti·Ka | sorti-ka.com | Sorties & événements |
| Resto·Ka | resto-ka.com | Restaurants, menus & prix (ce dépôt) |
4. Architecture
Pipeline standard de la famille ·Ka, adapté aux restaurants et menus :
┌─────────────┐ ┌──────────────┐ ┌────────────────┐ ┌──────────────┐ ┌──────────┐
│ CONNECTEUR │──▶│ EXTRACTION │──▶│ NORMALISATION │──▶│ DÉDUPLICATION │──▶│ STOCKAGE │
│ (par source)│ │ FC / Scrapfly│ │ resto + menu │ │ identité resto│ │ (DB) │
│ │ │ + parse PDF │ │ (schéma commun)│ │ + items │ │ │
└─────────────┘ └──────────────┘ └────────────────┘ └──────────────┘ └────┬─────┘
│
┌──────────▼──────────┐
│ API / RECHERCHE / │
│ UI (menus & prix) │
└─────────────────────┘Composants :
- Connecteurs : un module par source (ou par plateforme), interface commune.
- Orchestrateur : planifie et exécute (cadence, retries, backoff).
- Extraction : Firecrawl & Scrapfly + clients d'API + parsing de menus PDF / images (OCR) pour les menus non structurés.
- Normalisation : mappe le brut vers le schéma Restaurant + Menu (section 5).
- Déduplication : fusionne les restos et les items en double inter-sources.
- Stockage : base restos + menus + historique des prix (suivi des hausses).
- API / UI : recherche géolocalisée, filtres (cuisine, prix, diète), comparaison.
5. Modèle de données — schéma Restaurant + Menu
5.1 Restaurant
{
"id": "string", // * id interne canonique (post-déduplication)
"source_ids": ["ubereats:abc"], // * id(s) d'origine par source (préfixés)
"name": "string", // * nom normalisé
"chain": "string|null", // marque/chaîne si applicable
"cuisines": ["italien", "pizza"], // * taxonomie cuisine (section 6)
"establishment_type": "restaurant",// restaurant|fast-food|cafe|bar|food-truck|traiteur...
"price_range": "$$", // $ à $$$$ (estimé à partir des prix)
"address": "string", // *
"city": "string", // *
"region": "string", // * une des 17 régions (section 7)
"postal_code": "string",
"lat": 0.0, // * géolocalisation
"lng": 0.0, // *
"phone": "string",
"website": "string",
"hours": { /* horaires par jour */ },
"services": ["salle", "emporter", "livraison"], // dine-in|takeout|delivery
"dietary_options": ["vegan", "sans-gluten", "halal"],
"languages": ["fr", "en"],
"menu": { /* voir 5.2 */ },
"status": "open", // open|temporarily_closed|closed
"first_seen": "ISO-8601", // *
"last_seen": "ISO-8601", // *
"updated_at": "ISO-8601" // *
}5.2 Menu (imbriqué)
"menu": {
"currency": "CAD",
"price_context": "delivery", // * dine-in | takeout | delivery (voir §6)
"price_source": "ubereats", // * source du prix (traçabilité)
"captured_at": "ISO-8601", // * quand ce menu/prix a été capté
"sections": [
{
"name": "Pizzas",
"items": [
{
"id": "string",
"name": "Margherita", // *
"description": "string",
"price": 16.50, // * prix de l'item (dans price_context)
"currency": "CAD",
"tags": ["vegetarien"],
"options": [ // modificateurs / variantes
{
"group": "Format",
"required": true,
"choices": [
{ "name": "10 pouces", "price_delta": 0.00 },
{ "name": "14 pouces", "price_delta": 6.00 }
]
}
]
}
]
}
]
}Règles :
price_contextetprice_sourcesont obligatoires : un prix sans contexte est inutilisable (livraison ≠ salle).lat/lngobligatoires → géocoder l'adresse si absente.- Capturer les options/modificateurs (formats, suppléments, choix) : ils changent le prix réel.
- Conserver la devise partout (CAD). Au QC, TPS/TVQ s'ajoutent ; ne pas les
inclure dans
pricesauf si la source le fait, et alors le documenter.
6. Taxonomies
6.1 Cuisines (multi-valué)
quebecois · francais · italien · pizza · burgers · poulet ·
bbq-grillades · fruits-de-mer · sushi-japonais · chinois · thai ·
vietnamien · coreen · indien · libanais-moyen-orient · mexicain ·
grec · mediterraneen · dejeuner-brunch · cafe-dessert · vegetarien-vegan ·
fast-food · autre
6.2 Contexte de prix (price_context) — CRITIQUE
dine-in— prix en salle (référence idéale).takeout— prix pour emporter (souvent = salle).delivery— prix sur plateforme de livraison, majoré de 25-30 %.
Toujours privilégier
dine-in/takeout(menu du resto lui-même ou sa plateforme de commande en ligne) plutôt quedeliveryquand les deux existent. Si on n'a quedelivery, on l'affiche clairement étiqueté.
6.3 Diètes / tags
vegan · vegetarien · sans-gluten · halal · casher · sans-noix · epice
7. Régions du Québec (obligatoire pour chaque restaurant)
Bas-Saint-Laurent · Saguenay–Lac-Saint-Jean · Capitale-Nationale · Mauricie · Estrie · Montréal · Outaouais · Abitibi-Témiscamingue · Côte-Nord · Nord-du-Québec · Gaspésie–Îles-de-la-Madeleine · Chaudière-Appalaches · Laval · Lanaudière · Laurentides · Montérégie · Centre-du-Québec.
Rattacher chaque resto à sa région via la ville/adresse (table de correspondance ville → région, comme dans Lou·Ka).
8. Philosophie des connecteurs
- Un connecteur par source, taillé sur mesure.
- Connecteurs templatisés par plateforme : c'est le levier d'échelle nº 1. Une plateforme de commande en ligne ou de livraison couvre des milliers de restos avec la même structure → un seul connecteur paramétré les couvre tous (exactement comme les connecteurs par plateforme d'Auto·Ka et Fabri·Ka).
- Deux types de sources à combiner :
- Découverte (liste des restos + métadonnées) : annuaires, cartes, tourisme.
- Menus + prix (le cœur) : commande en ligne, livraison, sites de restos, PDF.
- Interface commune (à calquer sur Lou·Ka) :
fetch()→normalize()→emit(). Idempotent et incrémental quand c'est possible. - Robustesse : timeouts, retries + backoff, tolérance aux changements mineurs, alerte si le nombre d'items d'un menu chute anormalement (connecteur cassé).
9. Catalogue des sources à connecter (priorisé)
⚠️ Vérifie le registre des sources et l'index des restos avant d'ajouter.
Palier 1 — Plateformes de commande en ligne des restos (MEILLEUR prix + volume)
Ces plateformes propulsent les sites/apps des restos eux-mêmes → menus complets à des prix réels (dine-in/takeout, non majorés). À templatiser par plateforme :
- UEAT (foodtech de Québec, marque blanche, très répandue au QC).
- Square Online Ordering, Toast, Clover, GloriaFood (Oracle), Flipdish, Foodiv, ChowNow, Bite (DoorDash).
Palier 2 — Plateformes de livraison (menus complets, prix MAJORÉS)
Menus riches et structurés, mais prix delivery (+25-30 %), anti-bot fort et CGU
restrictives (voir section 15 — risque légal réel) :
- Uber Eats, SkipTheDishes, DoorDash.
- Plateformes québécoises : RestoLoco et autres services locaux régionaux.
Politique : utiliser la livraison surtout pour la découverte et pour les restos qu'on ne trouve nulle part ailleurs. Toujours étiqueter
price_context: delivery. Préférer une sourcedine-indès qu'elle existe.
Palier 3 — Sites web des restaurants (menus « maison »)
- Menus en HTML (parse direct) ou en PDF / image (→ parsing PDF + OCR, voir section 10). Détecter la plateforme de commande embarquée (souvent Palier 1).
Palier 4 — Découverte & métadonnées (liste des restos)
- Google Places / Maps, Yelp, TripAdvisor (coordonnées, horaires, type de cuisine, fourchette de prix — rarement les menus ; respecter les CGU/API).
- Associations touristiques régionales (ATR), Tourisme Québec.
- Médias food : Tastet, RestoMontréal et annuaires régionaux (découverte).
Palier 5 — Réservation (métadonnées + parfois menus)
- OpenTable, LibroReserve (Québec), Resy, Zenchef — horaires, services, parfois menus.
Palier 6 — Chaînes (menus standardisés)
- Sites des grandes chaînes : menus et prix souvent uniformes par bannière et parfois par région → un connecteur par chaîne couvre toutes les succursales.
10. Extraction — Firecrawl, Scrapfly & parsing de menus
Les connecteurs s'appuient souvent sur Firecrawl et Scrapfly (comme tout
l'écosystème ·Ka). Règle de choix :
- API / endpoint JSON de la plateforme → toujours privilégié (données structurées, stables). Beaucoup de plateformes de commande chargent leur menu via un appel JSON interne : le trouver et le consommer directement.
- Firecrawl → crawl et extraction en volume de sites relativement ouverts (sites de restos, annuaires), extraction structurée (markdown/JSON).
- Scrapfly → sites protégés, JavaScript lourd, anti-bot, rendu navigateur, rotation d'IP. Requis pour les plateformes de livraison (Uber Eats, Skip, DoorDash) qui bloquent agressivement.
- Parsing de menus PDF / images : de nombreux restos publient un menu en PDF ou
en photo. Prévoir extraction de texte PDF + OCR + un post-traitement (LLM) qui
transforme le texte brut en structure
sections → items → price → options. Valider systématiquement (un prix mal OCR-isé est pire que pas de prix).
Chaque connecteur doit documenter en tête de fichier son mode d'extraction et pourquoi. Réutiliser les clients partagés de Lou·Ka.
11. Normalisation
- Nettoyer noms de restos, sections et plats (HTML résiduel, majuscules, doublons).
- Mapper vers le schéma Restaurant + Menu (section 5) intégralement.
- Cuisines et type d'établissement classés dès la normalisation (section 6).
- Géocoder (lat/lng obligatoires) et rattacher la région (section 7).
- Prix : renseigner obligatoirement
price_contextetprice_source; capturer les options/modificateurs. Ne jamais mélanger des prix de contextes différents dans un même menu. - Devise CAD ; documenter le traitement des taxes (TPS/TVQ hors prix au QC).
- Conserver les
source_idspréfixés (ex.ueat:1234,ubereats:abcd).
12. Déduplication — restaurants ET items
Un même resto apparaît sur Uber Eats + DoorDash + Skip + son propre site + Google.
12.1 Identité du restaurant
- Clé : nom normalisé + adresse (géoloc arrondie) + téléphone → empreinte.
- Approché : noms proches + même adresse → fusion candidate (journaliser).
- Fusion : un enregistrement canonique, agréger les
source_ids, choisir la meilleure source par champ. - Multi-succursales / chaînes : chaque adresse est une fiche resto
distincte, reliée par
chain. Ne pas fusionner deux succursales.
12.2 Menus & prix
- Ne pas écraser un menu
dine-inpar un menudelivery: conserver les deux contextes et présenter le meilleur (dine-in prioritaire), en gardant delivery étiqueté. - Dédupliquer les items au sein d'un même contexte (même plat listé deux fois).
- Historiser les prix : à chaque capture, si le prix d'un item change, garder la série temporelle (utile pour détecter les hausses et pour la crédibilité).
S'inspirer de la déduplication de Lou·Ka (multi-plateformes) et d'Auto·Ka (identité forte par clé).
13. Fraîcheur des menus & états
- Menus changeants : prix et plats évoluent (saisonnier, table d'hôte,
spéciaux). Rafraîchir régulièrement et horodater chaque capture (
captured_at). - Fermetures : resto fermé temporairement / définitivement →
statusmis à jour plutôt que suppression brutale (politique de grâce vialast_seen, comme Lou·Ka). - Items retirés : disparition d'un plat → le marquer inactif, conserver l'historique.
- Spéciaux / table d'hôte : capturer si structurés, avec leur période de validité.
14. Cadence de rafraîchissement
- Grandes plateformes (commande en ligne, livraison, chaînes) : hebdomadaire au minimum ; quotidien pour les prix sur les gros volumes urbains.
- Sites de restos indépendants : hebdomadaire à mensuel (menus stables).
- Découverte (annuaires) : mensuel pour repérer nouveaux restos / fermetures.
- Toujours mettre à jour
last_seenetcaptured_atà chaque passage réussi.
15. Conformité & aspects légaux — À PRENDRE AU SÉRIEUX
C'est le point le plus sensible de ce projet. Les plateformes de livraison protègent activement leurs données (menus/prix) et l'interdisent dans leurs CGU. Ne pas traiter ça à la légère.
- Respecter les CGU et
robots.txtde chaque source. Les plateformes de livraison sont explicitement restrictives : minimiser, privilégier d'autres sources pour les mêmes restos, et demander en cas de doute avant d'industrialiser. - Privilégier les sources de première partie : le site du resto et sa plateforme de commande (UEAT, etc.) sont la voie la plus légitime pour le menu et le prix réel.
- Rate-limiting raisonnable, identification honnête, pas de surcharge.
- Utiliser les API officielles quand elles existent (Google Places, Yelp) et en respecter les quotas et conditions d'affichage/attribution.
- Ne republier que ce qui est nécessaire à la découverte (nom, plats, prix, infos pratiques, lien vers la source). Attribuer les sources requises.
- Consigner par source la base légale/mode d'accès retenu (API vs scraping) en tête de connecteur.
16. Conventions de code
- Suivre les mêmes conventions que Lou·Ka (langage, structure de dossiers, nommage, linting, formatage). Cohérence > préférences personnelles.
- Un connecteur = un module isolé, testable indépendamment.
- Secrets (clés Firecrawl/Scrapfly, API Google/Yelp) via variables d'environnement / gestionnaire de secrets. Jamais en clair.
- Logging structuré (source, nb de restos, nb d'items, erreurs, durée).
- Commits atomiques, messages clairs.
17. En-tête d'auteur — OBLIGATOIRE dans chaque fichier
Tout fichier du dépôt doit débuter par un en-tête d'auteur. L'auteur est toujours Simon-Pierre Boucher <contact@spboucher.ai>.
Python / Shell / YAML / TOML / Dockerfile :
# ==============================================================================
# Author: Simon-Pierre Boucher <contact@spboucher.ai>
# File: <nom_du_fichier>
# Desc: <brève description>
# ==============================================================================JavaScript / TypeScript / Go / Rust / Java / C :
// ==============================================================================
// Author: Simon-Pierre Boucher <contact@spboucher.ai>
// File: <nom_du_fichier>
// Desc: <brève description>
// ==============================================================================Markdown / HTML / XML :
<!--
Author: Simon-Pierre Boucher <contact@spboucher.ai>
File: <nom_du_fichier>
Desc: <brève description>
-->CSS / SCSS :
/*
Author: Simon-Pierre Boucher <contact@spboucher.ai>
File: <nom_du_fichier>
*/Règles :
- Aucun fichier commité sans cet en-tête.
- Pour un connecteur, indiquer dans
Desc:la source/plateforme couverte, le mode d'extraction (API / Firecrawl / Scrapfly / PDF-OCR) et le contexte de prix produit (dine-in / takeout / delivery). - Vérifier la présence de l'en-tête en revue de code (idéalement hook de pré-commit).
18. Tests & qualité
- Chaque connecteur : tests unitaires de normalisation sur des fixtures réelles (réponses JSON, HTML, PDF de menus figés).
- Tests de parsing de menus : vérifier prix, options et sections sur des échantillons connus (les prix sont l'actif le plus critique).
- Tests de déduplication resto + items multi-sources.
- Validation de schéma : tout resto/menu émis doit passer la validation avant
stockage ; rejeter un menu sans
price_context/price_source. - Monitoring : alerte si le nb d'items d'un resto ou le volume d'une source chute anormalement (connecteur probablement cassé).
19. Checklist — ajouter un nouveau connecteur / restaurant
- Lire les connecteurs de référence dans le dépôt Lou·Ka (section 3).
- Vérifier que la source/le resto n'est pas déjà couvert (registres).
- Identifier la plateforme : peut-on templatiser/réutiliser un connecteur ?
- Choisir le mode d'extraction : API > site du resto > Firecrawl > Scrapfly ; PDF/OCR si menu non structuré (section 10).
- Déterminer le
price_contextproduit et le documenter. - Implémenter
fetch()→normalize()→emit()(interface commune). - Mapper tout le schéma resto + menu, géocoder, région, cuisines, options.
- Brancher la déduplication resto + items (section 12).
- Gérer fraîcheur, fermetures, items retirés, historique des prix (§13).
- Vérifier la conformité CGU/robots et consigner la base d'accès (§15).
- Ajouter l'en-tête d'auteur (section 17).
- Écrire les tests + fixtures, dont le parsing de prix (section 18).
- Enregistrer la source dans le registre avec sa cadence.
- Valider volume et qualité sur un premier run, journaliser.
20. Roadmap / MVP
MVP : templatiser un connecteur pour la plateforme de commande en ligne la
plus répandue au QC (UEAT) → menus complets à prix réels (dine-in/takeout)
pour des milliers de restos d'un coup. Ajouter la découverte via Google Places/Yelp
pour la liste et les métadonnées, et le parsing des menus PDF des sites de restos.
UI de recherche géolocalisée avec filtres (cuisine, prix, diète, service) et
affichage clair du contexte de prix.
Ensuite : plateformes de livraison (avec étiquetage strict), chaînes,
réservation, régions moins couvertes. Puis historique des prix, comparaison entre
restos, et cross-linking avec les autres sites ·Ka.
Nord stratégique : être le seul à offrir menus et prix comparables de tous les restos du Québec — là où la livraison est chère et partielle, les annuaires sans menus, et les médias food non exhaustifs.
Fin de CLAUDE.md — Resto·Ka. Auteur : Simon-Pierre Boucher <contact@spboucher.ai>.