SPB Git forge

spb/food-ka

Public

Food-Ka — agrégateur de produits d'épicerie du Québec — www.food-ka.com

55commits 1branches 0releases
10.2 MBsize
maindefault branch
9 days agolast push
Python 53.9% TypeScript 24% CSS 14.9% JavaScript 5.8% HTML 1.4%
ZIP tar.gz
NameLast commitUpdated
data [ka4] fix connecteur euro_marche: Euro Marché a quitté Flipp (plus de... 9 days ago
docs docs: README ultra détaillé + visite guidée en 10 captures 29 days ago
foodka [ka4] fix connecteur euro_marche: Euro Marché a quitté Flipp (plus de... 9 days ago
frontend [ka4] snapshot pré-mission costco_flyer 19 days ago
scripts docs: historique Vague 3 (2e52f7c) + fiches regenerees 1 mo ago
tests Connecteurs Flipp : socle + 19 bannières de circulaires (~2 760... 1 mo ago
.gitignore Enrichissement connecteurs + robustesse DB (audit 2026-08-18) 1 mo ago
README.md docs: README ultra détaillé + visite guidée en 10 captures 29 days ago
requirements.txt Stats : tableau de bord analytique commun Groupe KA + export PDF 1 mo ago
run.py Food-Ka — agrégateur de produits d'épicerie du Québec 1 mo ago
README.md source

Food·Ka — Les prix d'épicerie, suivis à la source

Food·Ka

Les prix d'épicerie, suivis à la source

Site Documentation PDF Nœud Port PM2

Produits Sources En solde Catégories

Python FastAPI React Vite SQLite PWA PM2 ngrok Groupe KA spbgit

Les pastilles de la deuxième rangée sont dynamiques : elles interrogent /api/stats en 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

Accueil Food-Ka

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

Page aubaines

/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

Page statistiques

/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

Page sources

/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

Page 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é

Page 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

Accueil filtré par catégorie

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

Fiche produit Adonis

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

Page profil 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

Page documentation

/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 mobile
Accueil — recherche ligne fine, KA Tabbar
Aubaines mobile
Aubaines de la semaine
Fiche produit mobile
Fiche produit — prix comparés par bannière
Carte mobile
Carte des épiceries
Stats mobile
Bandeau stats en chiffres
Menu mobile
Menu vert profond plein écran

# Desktop

Accueil desktop
Accueil — onglets rayons soulignés, packshots 12px
Aubaines
Aubaines — échelle de prix à filets
Fiche produit
Fiche produit — comparaison multi-bannières
Carte
Carte des épiceries du Québec
Épiceries
Répertoire des bannières
Stats
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 dans data/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 = null si absent), prix régulier incohérent rejeté, throttle entre requêtes, User-Agent identifié, journal sync_log.

# Démarrage rapide

bash
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 h

run.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/)
PDF 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

  1. Chaque produit normalisé reçoit un hash de contenu ; l'upsert dans SQLite (mode WAL) classe le produit nouveau / modifié / disparu.
  2. 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é).
  3. Le prix unitaire $/100 g est calculé à la normalisation pour rendre les formats comparables entre bannières.
  4. 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).
  5. 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-sync reparcourt les 57 sources en continu, cycle complet ≈ 6 heures ; chaque passage est journalisé dans sync_log (fraîcheur visible sur /sources et via ?syncs_since_h).
  • Fidélité — aucun prix inventé (price = null si 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.

bash
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 main

# Dé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.