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%

docs: README v2 — galerie multi-pages, style du site, documentation, contact

Simon-Pierre Boucher committed 1 mo ago (Aug 24, 2026) parent 3a264e7

1 changed file +87 −15

modified README.md +87 −15
@@ -1,8 +1,16 @@
1 −# Food·Ka
1 +<p align="center">
2 + <a href="https://www.food-ka.com"><img src="https://www.food-ka.com/og.png" width="760" alt="Food·Ka — Les prix d'épicerie, suivis à la source"></a>
3 +</p>
4 +
5 +<h1 align="center">Food·Ka</h1>
2 6
3 −**Tous les prix d'épicerie du Québec — comparés, historisés et toujours à jour, un seul endroit.**
7 +<p align="center"><b>Les prix d'épicerie, suivis à la source</b></p>
4 8
5 −[![Site](https://img.shields.io/website?url=https%3A%2F%2Fwww.food-ka.com&style=flat-square&label=www.food-ka.com)](https://www.food-ka.com)
9 +<div align="center">
10 +
11 +[![Site](https://img.shields.io/website?url=https%3A%2F%2Fwww.food-ka.com&style=flat-square&label=www.food-ka.com&up_color=1f9d55)](https://www.food-ka.com)
12 +[![Documentation](https://img.shields.io/badge/📖_documentation-%2Fdoc-1f9d55?style=flat-square)](https://www.food-ka.com/doc/)
13 +[![PDF](https://img.shields.io/badge/guide-PDF-1f9d55?style=flat-square)](https://www.food-ka.com/doc/food-ka-documentation.pdf)
6 14 ![Nœud](https://img.shields.io/badge/n%C5%93ud-M4M64b-1f6feb?style=flat-square)
7 15 ![Port](https://img.shields.io/badge/port-8097-555?style=flat-square)
8 16 ![PM2](https://img.shields.io/badge/process-PM2-2b037a?style=flat-square)
@@ -12,16 +20,28 @@
12 20 ![SQLite](https://img.shields.io/badge/SQLite-price__log-003b57?style=flat-square&logo=sqlite&logoColor=white)
13 21 ![Groupe KA](https://img.shields.io/badge/Groupe-KA-b7f000?style=flat-square)
14 22
23 +</div>
24 +
15 25 **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**.
16 26
17 27 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`). En date du 2026-08-24, le catalogue compte **50 892 produits** provenant de **57 sources** dans **18 catégories** canoniques, dont **8 777 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…).
18 28
19 −## Captures d'écran
20 −
21 −<p align="center">
22 − <img src="docs/screenshots/food-ka-desktop.png" width="640" alt="Accueil — desktop">
23 − <img src="docs/screenshots/food-ka-mobile.png" width="200" alt="Accueil — mobile">
24 −</p>
29 +## Visite guidée
30 +
31 +<table>
32 + <tr>
33 + <td align="center"><img src="frontend/public/doc/img/etape1.png" width="420"><br><sub><b>Accueil — PWA installable : ticker temps réel, catégories, aubaines du moment</b></sub></td>
34 + <td align="center"><img src="frontend/public/doc/img/etape2.png" width="420"><br><sub><b>Recherche « lait 2% » — résultats toutes bannières, prix unitaire $/100 g comparable</b></sub></td>
35 + </tr>
36 + <tr>
37 + <td align="center"><img src="frontend/public/doc/img/etape3.png" width="420"><br><sub><b>Fiche produit — le même produit comparé chez 6 bannières, historique de prix</b></sub></td>
38 + <td align="center"><img src="frontend/public/doc/img/etape4.png" width="420"><br><sub><b>Aubaines — prix courant vs prix régulier, tri par rabais</b></sub></td>
39 + </tr>
40 + <tr>
41 + <td align="center"><img src="docs/screenshots/food-ka-desktop.png" width="420"><br><sub><b>Accueil desktop — design « éditorial sharp », accent vert épicerie</b></sub></td>
42 + <td align="center"><img src="docs/screenshots/food-ka-mobile.png" width="230"><br><sub><b>Accueil mobile — mobile-first, installable sur l'écran d'accueil</b></sub></td>
43 + </tr>
44 +</table>
25 45
26 46 ## Fonctionnalités
27 47
@@ -47,13 +67,54 @@ Les épiceries n'offrent pas de webhooks ; Food-Ka en reproduit l'équivalent :
47 67 | Frontend | React 18 · Vite · TypeScript | PWA, react-router, ka-ui vendorisé, fiches avec comparaison inter-bannières (build → `frontend/dist/`) |
48 68 | PDF | reportlab · fpdf2 | Export des rapports statistiques |
49 69
50 −Trois processus PM2 assurent la production :
70 +### Processus PM2
51 71
52 72 | Processus | Commande | Rôle |
53 73 |---|---|---|
54 −| `food-ka-web` | `.venv/bin/python run.py serve 8097` | API + frontend |
55 −| `food-ka-sync` | `.venv/bin/python run.py watch 360` | Resynchronisation périodique des bannières (cycle 6 h) |
56 −| `food-ka-ngrok` | `ngrok http --url=www.food-ka.com 8097` | Tunnel public vers le domaine |
74 +| `food-ka-web` | `.venv/bin/python run.py serve 8097` | Sert l'API `/api/*`, la PWA buildée et le rendu SEO — le seul processus exposé (via ngrok) |
75 +| `food-ka-sync` | `.venv/bin/python run.py watch 360` | Watcher de resynchronisation : reparcourt les 57 sources en boucle, **cycle complet ≈ 6 h**, alimente le diff engine et `price_log` |
76 +| `food-ka-ngrok` | `ngrok http --url=www.food-ka.com 8097` | Tunnel public vers le domaine www.food-ka.com |
77 +
78 +### API principale
79 +
80 +| Méthode | Endpoint | Rôle |
81 +|---|---|---|
82 +| GET | `/api/products` | Recherche paginée : catégorie, bannière, marque, fourchette de prix, soldes, texte libre + tris (prix, $/100 g, rabais, récents) |
83 +| GET | `/api/products/{uid}` | Fiche complète d'un produit (prix, prix régulier, $/100 g, nutrition, historique `price_log`) |
84 +| GET | `/api/products/{uid}/compare` | Équivalents du produit chez les autres bannières (matching inter-bannières) |
85 +| GET | `/api/facets` | Facettes dynamiques (compteurs par catégorie, bannière, marque…) pour les filtres |
86 +| GET | `/api/sources` | Registre et état des bannières connectées |
87 +| GET | `/api/stats` · `/api/stats/dashboard` · `/api/stats/detailed` | Statistiques du catalogue (tuiles, distributions, soldes) |
88 +| GET | `/api/stats/catalog` · `/api/stats/report` · `/api/stats/rapport.pdf` | Catalogue stats v3 + rapports PDF |
89 +| POST | `/api/stats/report/custom` | Rapport PDF personnalisé (ReportBuilder) |
90 +| GET/POST | `/api/favorites` · `/api/favorites/toggle` | Favoris KA ID (synchronisés au hub) |
91 +| POST | `/api/sync` | Déclencher une synchronisation |
92 +| GET | `/ka/login` · `/ka/callback` · `/me` · POST `/logout` | SSO KA ID (hub groupe-ka.com) |
93 +
94 +S'y ajoutent les routes SSR SEO (`/produit/{uid}`, sitemaps produits/pages, `robots.txt`) et les pages `/aubaines`, `/stats`, `/sources`, `/doc`, `/contact`, `/confidentialite`.
95 +
96 +### Connecteurs et sources
97 +
98 +**~58 modules** dans `foodka/connectors/` couvrent **57 sources** recensées dans `data/sources.json` (chaque bannière non-connectable y est documentée avec sa raison). Les bannières d'un même groupe partagent une **base technique commune** :
99 +
100 +| Base partagée | Technique | Bannières servies |
101 +|---|---|---|
102 +| `_metro.py` | Site Metro & cie | `metro`, `superc` |
103 +| `_loblaw.py` | API Loblaw | `maxi`, `provigo`, `club_entrepot` |
104 +| `_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`) |
105 +| `_shopify.py` | Shopify `products.json` | `giant_tiger`, `pa`, `epipresto`, `nuvo`, `boite_a_grains` |
106 +| `_woocommerce.py` | WooCommerce Store API | `akhavan`, `aliments_merci`, `bocoboco` |
107 +| `base.py` + `_resilient.py` | Socle commun | normalisation, hash, throttle, retries/backoff, escalade anti-bot |
108 +
109 +Connecteurs autonomes (site propre ou API dédiée) : `iga` (Voilà), `walmart`, `saq`, `costco`, `adonis`, `avril`, `mayrand`, `aubut`, `tau`, `tt`, `loco`, `maturin`.
110 +
111 +### Diff engine, `price_log` & matching inter-bannières
112 +
113 +1. Chaque produit normalisé reçoit un **hash de contenu** ; l'upsert dans SQLite (mode WAL) classe le produit **nouveau / modifié / disparu**.
114 +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é).
115 +3. Le **prix unitaire $/100 g** est calculé à la normalisation pour rendre les formats comparables entre bannières.
116 +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`).
117 +5. Chaque passage de connecteur est journalisé dans **`sync_log`** (supervision api-ka, fenêtre de sync paramétrable).
57 118
58 119 ## Structure du repo
59 120
@@ -62,12 +123,18 @@ Trois processus PM2 assurent la production :
62 123 | `run.py` | Point d'entrée CLI : `sync` · `watch` · `serve` |
63 124 | `requirements.txt` | Dépendances backend (FastAPI, uvicorn, requests, bs4, reportlab, fpdf2, pillow) |
64 125 | `foodka/` | Backend Python : schéma Product, normalisation, ingestion, db, web, seo, matching inter-bannières, nutrition, auth KA ID, favoris, stats, PDF + `connectors/` |
65 −| `frontend/` | PWA React 18 + Vite + TypeScript (build servi par FastAPI) |
126 +| `frontend/` | PWA React 18 + Vite + TypeScript (build servi par FastAPI) — inclut la page `/doc` (`frontend/public/doc/`) |
66 127 | `data/` | `foodka.db` (SQLite) + `sources.json` (registre des bannières) |
67 128 | `docs/` | Captures d'écran + documentation générée des connecteurs |
68 129 | `scripts/` | Outillage (`gen_connector_docs.py`) |
69 130 | `tests/` | Tests (normalisation, connecteur Flipp) |
70 131
132 +## Documentation
133 +
134 +- **Guide d'utilisation en ligne** : [www.food-ka.com/doc](https://www.food-ka.com/doc/) — visite guidée pas à pas (accueil, recherche, fiche comparée, aubaines) avec captures d'écran.
135 +- **Guide PDF téléchargeable** : [food-ka-documentation.pdf](https://www.food-ka.com/doc/food-ka-documentation.pdf).
136 +- Le guide est aussi lié depuis le pied de page du site ; ses captures vivent dans `frontend/public/doc/img/`.
137 +
71 138 ## Développement (remote-first)
72 139
73 140 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](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.
@@ -95,7 +162,7 @@ git add <fichiers> && git commit -m "..." && git push origin main
95 162
96 163 - **Nœud** : M4M64b (Mac Studio, cluster MacLustr) — répertoire `~/apps/food-ka`
97 164 - **Port local** : 8097
98 −- **Processus PM2** : `food-ka-web` (API + frontend), `food-ka-sync` (watcher de synchronisation), `food-ka-ngrok` (tunnel)
165 +- **Processus PM2** : `food-ka-web` (API + frontend), `food-ka-sync` (watcher de synchronisation, cycle ≈ 6 h), `food-ka-ngrok` (tunnel)
99 166 - **Exposition publique** : tunnel ngrok → [https://www.food-ka.com](https://www.food-ka.com)
100 167
101 168 Philosophie d'exploitation : on ne pousse que le code — le serveur maintient ses données lui-même.
@@ -118,6 +185,11 @@ Philosophie d'exploitation : on ne pousse que le code — le serveur maintient s
118 185 | [trouve-ka.com](https://www.trouve-ka.com) | Petites annonces |
119 186 | [api-ka.com](https://www.api-ka.com) | API de données |
120 187
188 +## Contact
189 +
190 +**Simon-Pierre Boucher** — fondateur, Groupe KA
191 +📧 [contact@spboucher.ai](mailto:contact@spboucher.ai)
192 +
121 193 ---
122 194
123 195 © Groupe KA — Simon-Pierre Boucher · [contact@spboucher.ai](mailto:contact@spboucher.ai)
124 196