Food·Ka
Les prix d'épicerie, suivis à la source
Les pastilles de la deuxième rangée sont dynamiques : elles interrogent
/api/statsen direct.
Food-Ka est un agrégateur et comparateur indépendant de produits d'épicerie couvrant tout le Québec. Comparer les prix d'épicerie, c'est normalement ouvrir Metro, IGA, Maxi, Super C, Provigo, Walmart… chacun avec sa propre navigation, son panier, son format. Food-Ka retourne le problème : un connecteur dédié par bannière visite chaque site, normalise chaque produit vers un schéma unique (avec prix unitaire comparable en $/100 g) et détecte les changements de prix en continu.
Les épiceries n'offrent pas de webhooks ; Food-Ka en reproduit l'équivalent : synchronisation périodique + hash de contenu → nouveaux produits, changements de prix et retraits détectés automatiquement, chaque variation étant historisée (price_log). Au 2026-08-28, le catalogue compte 50 778 produits provenant de 57 sources dans 18 catégories canoniques, dont 9 078 produits en solde — grandes bannières (Metro, Super C, IGA/Voilà, Maxi, Provigo, Walmart…) comme spécialisées et indépendantes (Mayrand, Avril, PA, Tau, Giant Tiger, SAQ…).
Visite guidée
Le site en 10 écrans — captures de production du 2026-08-28 sur www.food-ka.com.
1. Accueil — le catalogue en un coup d'œil

La page d'accueil (food-ka.com) : recherche texte libre, onglets de rayons (18 catégories canoniques), barre de filtres compacte (bannière, marque, prix, format, mentions bio/local/sans gluten…) et grille de cartes produits avec prix, prix unitaire $/100 g et badge de solde. Le ticker temps réel défile en tête de page.
2. Aubaines — les rabais de la semaine

/aubaines : tous les produits en solde (9 078 au moment de la capture), triés par rabais, avec prix courant vs prix régulier et pourcentage d'économie — alimenté par le diff engine et price_log.
3. Statistiques — le tableau de bord public

/stats : tuiles de synthèse (produits, sources, catégories, soldes, prix moyen), distributions par bannière et par catégorie, fraîcheur des synchronisations — le même module stats v3 qui produit les rapports PDF personnalisés.
4. Sources — le registre des bannières

/sources : les 57 bannières connectées avec leur volume et leur dernière synchronisation, plus les bannières non connectables documentées avec leur raison — la transparence plutôt que l'omission silencieuse.
5. Contact

/contact : formulaire de contact aux couleurs du Groupe KA, pour signaler une erreur de prix, proposer une bannière ou joindre l'équipe.
6. Confidentialité

/confidentialite : politique de confidentialité — ce qui est collecté (compte KA ID, favoris), ce qui ne l'est pas, et l'avertissement sur la nature indicative des prix.
7. Accueil filtré — navigation par rayon

Le catalogue filtré par catégorie (/?category=Autres) : chaque rayon est une URL partageable ; les facettes (/api/facets) recalculent les compteurs de bannières et de marques pour le rayon actif.
8. Fiche produit — la comparaison inter-bannières

Une fiche produit (/produit/adonis:111033792) : prix courant, prix régulier, prix unitaire $/100 g, historique des variations (price_log) et tableau des équivalents chez les autres bannières (/api/products/{uid}/compare, moteur foodka/matching.py). Fiches rendues côté serveur pour le SEO.
9. Profil — le compte KA ID

/profil : le compte KA ID (SSO du Groupe KA — courriel + Google), favoris synchronisés au hub central et valables sur les 12 plateformes ·Ka, recommandations personnalisées « Recommandé pour vous » (moteur ka-id v2).
10. Documentation — le guide en ligne

/doc : guide d'utilisation illustré pas à pas (recherche, fiche comparée, aubaines) avec PDF téléchargeable — aussi lié depuis le pied de page du site.
Galerie DA v3 (2026-08-25) — mobile & desktop
Captures d'époque de la DA v3 « data-épicerie » (mobile 390×844 · desktop 1440×900) — cliquer pour dérouler.
Mobile
![]() Accueil — recherche ligne fine, KA Tabbar |
![]() Aubaines de la semaine |
![]() Fiche produit — prix comparés par bannière |
![]() Carte des épiceries |
![]() Bandeau stats en chiffres |
![]() Menu vert profond plein écran |
Desktop
![]() Accueil — onglets rayons soulignés, packshots 12px |
![]() Aubaines — échelle de prix à filets |
![]() Fiche produit — comparaison multi-bannières |
![]() Carte des épiceries du Québec |
![]() Répertoire des bannières |
![]() Statistiques — 52 700+ produits, 57 bannières |
Nouveautés front-end (2026-08-25)
- DA v3 « data-épicerie » — filtres pupitre sans boîte, onglets rayons soulignés, cartes produits sans cadre (packshot 12px + prix display), échelle de prix à filets, tuiles stats à filets, menu mobile vert profond.
- Refonte UX des filtres épicerie — barre compacte sticky, bottom sheet mobile / modal desktop, presets prix, filtres format (poids/volume/unité) et mentions (bio, local, sans gluten, végane, sans lactose), chips actifs supprimables — API
tags/fmt+ compteurs facets. - Recherche mobile — ligne fine au lieu d'une zone de 260 px.
- KA Tabbar v1 — barre de navigation mobile commune Groupe KA.
- Widget ka-agent v4 — cartes produits cliquables et choix en boutons.
🗄️ Les captures d'époque sont conservées dans
docs/archive/.
Fonctionnalités
- Agrégation multi-bannières — un connecteur auto-découvert par bannière (
foodka/connectors/), grandes chaînes et épiceries spécialisées, couvrant tout le Québec ; chaque bannière non-connectable est documentée avec sa raison dansdata/sources.json. - Prix unitaire comparable — chaque produit ramené en $/100 g pour comparer l'incomparable.
- Détection des soldes — prix courant vs prix régulier, tri par rabais, historique complet des variations de prix.
- Comparaison inter-bannières — chaque fiche produit montre les équivalents chez les autres bannières (
foodka/matching.py). - Recherche et filtres — catégorie, bannière, marque, fourchette de prix, soldes, texte libre ; tris prix / prix unitaire / rabais / récents.
- Données nutritionnelles — enrichissement des fiches (
foodka/nutrition.py). - Compte KA ID — SSO du Groupe KA (courriel + Google) : un seul compte (
ka_id) valable sur toutes les plateformes ·Ka (foodka/auth.py,hubprofile.py), favoris synchronisés au hub central (foodka/hubfav.py). - Stats Groupe KA — tableau de bord analytique commun avec rapports PDF personnalisés (stats v3 : catalogue, rendu au choix, ReportBuilder —
statsdash.py,kapdf.py,pdfgen.py), fenêtre de sync paramétrable pour la supervision api-ka. - SEO — rendu serveur des fiches et pages (
foodka/seo.py). - PWA installable — design « éditorial sharp » (Space Grotesk, accent lime, ticker temps réel), mobile-first, design system ka-ui partagé, widget KA Agent (bulle de chat IA).
- Fidélité et politesse — aucun prix inventé (
price = nullsi absent), prix régulier incohérent rejeté, throttle entre requêtes, User-Agent identifié, journalsync_log.
Démarrage rapide
ssh M4M64b && cd ~/apps/food-ka # source de vérité : le nœud
# Backend
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python run.py sync # synchroniser toutes les bannières
.venv/bin/python run.py sync metro iga saq # ...ou seulement certaines (id du registre data/sources.json)
.venv/bin/python run.py serve 8080 # API + PWA + SSR en local
# Frontend (build servi ensuite par FastAPI)
cd frontend && npm install && npm run build && cd ..
cd frontend && npm run dev # ...ou serveur de dev Vite
# Tests (normalisation, connecteur Flipp)
.venv/bin/pip install pytest
.venv/bin/python -m pytest tests/ -q
# Validation d'ordre visuel des fiches (standard Groupe KA)
node frontend/scripts/check-order.mjs <uid>
# Boucle de synchronisation continue (ce que fait PM2 en prod)
.venv/bin/python run.py watch 360 # re-parcourt les sources, cycle ≈ 6 hrun.py est le seul point d'entrée : sync [source ...] · watch [minutes] (défaut 360) · serve [port] (défaut 8080).
Variables d'environnement
Noms seulement — les valeurs vivent dans .env sur le nœud (jamais versionnées).
| Variable | Rôle |
|---|---|
FOODKA_BASE_URL |
URL publique canonique (SEO, sitemaps, SSO) |
SESSION_SECRET |
Secret de session (cookies signés) |
KA_SSO_SECRET · KA_HUB_URL |
SSO KA ID via le hub groupe-ka.com |
FIRECRAWL_API_KEY · SCRAPFLY_API_KEY |
Escalade anti-bot des connecteurs (_resilient.py) |
FOODKA_SAQ_MAX_PRODUCTS |
Borne du connecteur SAQ (optionnelle) |
Architecture
| Composant | Technologie | Rôle |
|---|---|---|
| Backend | Python 3.14 · FastAPI · Uvicorn | API REST (/api/products, /api/facets, /api/stats…), auth KA ID, favoris, stats (foodka/web.py) |
| Base de données | SQLite (data/foodka.db, mode WAL) |
Produits, hash de contenu, price_log, sync_log — diff engine (upsert : nouveau / modifié / disparu) |
| Connecteurs | requests · BeautifulSoup · Scrapfly / Firecrawl (sites anti-bot) | 1 module par bannière : HTML rendu serveur, APIs JSON (Shopify products.json, WooCommerce Store API), __NEXT_DATA__… |
| Frontend | React 18 · Vite · TypeScript | PWA, react-router, ka-ui vendorisé, fiches avec comparaison inter-bannières (build → frontend/dist/) |
| reportlab · fpdf2 | Export des rapports statistiques |
Processus PM2
| Processus | Commande de démarrage | Rôle |
|---|---|---|
food-ka-web |
pm2 start .venv/bin/python --name food-ka-web -- run.py serve 8097 |
Sert l'API /api/*, la PWA buildée et le rendu SEO — le seul processus exposé (via ngrok) |
food-ka-sync |
pm2 start .venv/bin/python --name food-ka-sync -- run.py watch 360 |
Watcher de resynchronisation : reparcourt les 57 sources en boucle, cycle complet ≈ 6 h, alimente le diff engine et price_log |
food-ka-ngrok |
pm2 start ~/bin/ngrok --name food-ka-ngrok -- http --url=www.food-ka.com 8097 |
Tunnel public vers le domaine www.food-ka.com |
API principale
| Méthode | Endpoint | Rôle |
|---|---|---|
| GET | /api/products |
Recherche paginée : catégorie, bannière, marque, fourchette de prix, soldes, texte libre + tris (prix, $/100 g, rabais, récents) |
| GET | /api/products/{uid} |
Fiche complète d'un produit (prix, prix régulier, $/100 g, nutrition, historique price_log) |
| GET | /api/products/{uid}/compare |
Équivalents du produit chez les autres bannières (matching inter-bannières) |
| GET | /api/facets |
Facettes dynamiques (compteurs par catégorie, bannière, marque…) pour les filtres |
| GET | /api/sources |
Registre et état des bannières connectées |
| GET | /api/stats |
Tuiles de synthèse JSON (total, soldes, sources, catégories, prix moyen, répartitions) — alimente les pastilles dynamiques ci-dessus |
| GET | /api/stats/dashboard · /api/stats/detailed |
Tableau de bord analytique (distributions, soldes, fraîcheur, fenêtre ?syncs_since_h pour la supervision api-ka) |
| GET | /api/stats/catalog · /api/stats/report · /api/stats/rapport.pdf |
Catalogue stats v3 + rapports PDF |
| POST | /api/stats/report/custom |
Rapport PDF personnalisé (ReportBuilder) |
| GET/POST | /api/favorites · /api/favorites/toggle |
Favoris KA ID (synchronisés au hub) |
| POST | /api/sync |
Déclencher une synchronisation |
| GET | /ka/login · /ka/callback · /me · POST /logout |
SSO KA ID (hub groupe-ka.com) |
S'y ajoutent les routes SSR SEO (/produit/{uid}, sitemaps produits/pages, robots.txt) et les pages /aubaines, /stats, /sources, /doc, /contact, /confidentialite.
Connecteurs et sources
65 fichiers dans foodka/connectors/ : 57 connecteurs de source (un par bannière active — 1:1 avec les 57 sources actives du registre data/sources.json), 5 bases techniques partagées et le socle base.py / _resilient.py. Le registre compte 61 entrées au 2026-08-24 : 57 actives + 4 bannières non connectables documentées avec leur raison (Bulk Barn, Dollarama, Fermes Lufa, Frenco). Les bannières d'un même groupe partagent une base technique commune :
| Base partagée | Technique | Connecteurs servis |
|---|---|---|
_flipp.py |
Circulaires Flipp | 32 connecteurs : circulaires des grandes bannières (metro_flyer, iga_flyer, maxi_flyer, superc_flyer, provigo_flyer, walmart_flyer, costco_flyer, adonis_flyer, avril_flyer) + pharmacies (pharmaprix, jean_coutu, uniprix, brunet) + indépendantes et ethniques (kim_phat, fu_tai, euro_marche, rachelle_bery, tradition, bonichoix, axep, marche_ami, richelieu, pasquier, inter_marche, inter_marche_intl, marche_ct, marche_vegetarien, aures, bonanza, val_mont, pa_nature, aliments_mm) |
_shopify.py |
Shopify products.json |
5 connecteurs : giant_tiger, pa, epipresto, nuvo, boite_a_grains |
_loblaw.py |
API Loblaw | 3 connecteurs : maxi, provigo, club_entrepot |
_woocommerce.py |
WooCommerce Store API | 3 connecteurs : akhavan, aliments_merci, bocoboco |
_metro.py |
Site Metro & cie | 2 connecteurs : metro, superc |
base.py + _resilient.py |
Socle commun | normalisation, hash, throttle, retries/backoff, escalade anti-bot |
Connecteurs autonomes (site propre ou API dédiée — 12) : iga (Voilà), walmart, saq (API GraphQL), costco, adonis, avril, mayrand, aubut, tau, tt, loco, maturin.
Diff engine, price_log & matching inter-bannières
- Chaque produit normalisé reçoit un hash de contenu ; l'upsert dans SQLite (mode WAL) classe le produit nouveau / modifié / disparu.
- Chaque variation de prix est écrite dans
price_log→ historique complet affiché sur la fiche et moteur de la détection des soldes (prix courant vs prix régulier ; prix régulier incohérent rejeté). - Le prix unitaire $/100 g est calculé à la normalisation pour rendre les formats comparables entre bannières.
- Le matching inter-bannières (
foodka/matching.py) relie le même produit vendu chez plusieurs bannières — c'est lui qui alimente le tableau de comparaison de la fiche (/api/products/{uid}/compare). - Chaque passage de connecteur est journalisé dans
sync_log(supervision api-ka, fenêtre de sync paramétrable).
Données & conformité
- Provenance — chaque produit est lu à la source (site ou API publique de la bannière, circulaires Flipp) ; aucune donnée revendue par un tiers.
- Cadence — le watcher
food-ka-syncreparcourt les 57 sources en continu, cycle complet ≈ 6 heures ; chaque passage est journalisé danssync_log(fraîcheur visible sur/sourceset via?syncs_since_h). - Fidélité — aucun prix inventé (
price = nullsi absent), prix régulier incohérent rejeté ; les prix des circulaires sont valides pour la durée de la circulaire. - Politesse de crawl — throttle entre requêtes, retries avec backoff, User-Agent identifié ; l'escalade anti-bot (
_resilient.py) n'est utilisée que là où le site le rend nécessaire. - Avertissement — Food-Ka est un comparateur indépendant, sans affiliation avec les bannières référencées ; les prix sont indicatifs et peuvent varier selon le magasin — le prix en magasin fait foi. Les bannières non connectables restent listées avec leur raison dans le registre plutôt que silencieusement omises.
Structure du repo
| Répertoire / fichier | Rôle |
|---|---|
run.py |
Point d'entrée CLI : sync · watch · serve |
requirements.txt |
Dépendances backend (FastAPI, uvicorn, requests, bs4, reportlab, fpdf2, pillow) |
foodka/ |
Backend Python : schéma Product, normalisation, ingestion, db, web, seo, matching inter-bannières, nutrition, auth KA ID, favoris, stats, PDF + connectors/ |
frontend/ |
PWA React 18 + Vite + TypeScript (build servi par FastAPI) — inclut la page /doc (frontend/public/doc/) |
data/ |
foodka.db (SQLite) + sources.json (registre des 61 bannières, raisons des non-connectables incluses) |
docs/ |
Captures d'écran (screenshots/ : visite guidée 2026-08-28 + galeries mobile/desktop DA v3, archive/ : captures d'époque) + documentation générée des connecteurs |
scripts/ |
Outillage (gen_connector_docs.py) |
tests/ |
Tests pytest (test_normalize.py, test_flipp.py) |
Documentation
- Guide d'utilisation en ligne : www.food-ka.com/doc — visite guidée pas à pas (accueil, recherche, fiche comparée, aubaines) avec captures d'écran.
- Guide PDF téléchargeable : food-ka-documentation.pdf.
- Le guide est aussi lié depuis le pied de page du site ; ses captures vivent dans
frontend/public/doc/img/.
Historique
| Date | Commit | Jalon |
|---|---|---|
| 2026-08-12 | 59727c8 |
Naissance de Food-Ka — agrégateur de produits d'épicerie du Québec |
| 2026-08-16 | 44589f8 |
Connecteurs Flipp : socle + 19 bannières de circulaires (~2 760 produits) |
| 2026-08-17 | 7395f5f |
Harmonisation ka-ui : accent vert marché, footer Groupe KA, SSO KA ID actif |
| 2026-08-18 | 2e52f7c |
Vague 3 : SAQ (API GraphQL directe) + 6 circulaires Flipp (4 pharmacies, Adonis, Avril) + Metro allées prioritaires |
| 2026-08-18 | 114aa76 |
Matching inter-bannières : MAX_BLOCK 400 → 3000 (fenêtre triée, rebuild mesuré à 7 s) |
| 2026-08-23 | 8acf4c4 |
Stats v3 : rapports PDF personnalisés (catalogue, ReportBuilder) |
| 2026-08-24 | 3a264e7 |
Page documentation /doc (guide + captures) + PDF téléchargeable |
| 2026-08-25 | c740a48 |
Campagne visuelle : galerie WebP mobile + desktop (DA v3 « data-épicerie ») |
| 2026-08-26 | a4e75ac |
ka-id v2 : personnalisation Groupe KA (journal serveur, reranking, badge « Recommandé pour vous ») |
| 2026-08-28 | — | README ultra détaillé + visite guidée en 10 captures (docs/screenshots/) |
Développement (remote-first)
La source de vérité est le repo git sur le nœud M4M64b (~/apps/food-ka), pas une copie locale. Toute modification se fait sur le nœud via SSH ; le remote origin = spbgit (git perso https://git.spboucher.ai), via l'alias SSH gitsrv configuré sur le nœud → gitsrv:srv/git/food-ka.git (bare repos hébergés sur M3U96a). Pas GitHub.
ssh M4M64b
cd ~/apps/food-ka
# Backend
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
.venv/bin/python run.py sync # synchroniser toutes les bannières (ou : run.py sync metro iga)
.venv/bin/python run.py serve 8080 # servir en local
# Frontend
cd frontend && npm install && npm run build && cd ..
# Après un changement en production
pm2 restart food-ka-web # (ou food-ka-sync selon le changement)
# Versionner depuis le nœud (agent forwarding actif)
git add <fichiers> && git commit -m "..." && git push origin mainDéploiement
- Nœud : M4M64b (Mac Studio, cluster MacLustr) — répertoire
~/apps/food-ka - Port local : 8097
- Processus PM2 :
food-ka-web(API + frontend),food-ka-sync(watcher de synchronisation, cycle ≈ 6 h),food-ka-ngrok(tunnel) - Exposition publique : tunnel ngrok → https://www.food-ka.com
Philosophie d'exploitation : on ne pousse que le code — le serveur maintient ses données lui-même.
Écosystème Groupe KA
| Plateforme | Rôle |
|---|---|
| groupe-ka.com | Portail |
| lou-ka.com | Logements à louer |
| immo-ka.com | Propriétés à vendre |
| vrai-prix.com | Estimation immobilière |
| auto-ka.com | Véhicules |
| fabri-ka.com | Produits québécois |
| food-ka.com | Épicerie / alimentation |
| resto-ka.com | Restaurants |
| sorti-ka.com | Sorties et événements |
| job-ka.com | Emplois |
| crea-ka.com | Créateurs |
| trouve-ka.com | Petites annonces |
| api-ka.com | API de données |
Contact
Simon-Pierre Boucher — fondateur, Groupe KA 📧 contact@spboucher.ai
© Groupe KA — Simon-Pierre Boucher · contact@spboucher.ai
Ce repo vit sur spbgit (git.spboucher.ai) — la source de vérité est le clone sur le nœud M4M64b.












