docs: README v2 — galerie multi-pages, style du site, documentation, contact
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 | −[](https://www.food-ka.com) | |
| 9 | +<div align="center"> | |
| 10 | + | |
| 11 | +[](https://www.food-ka.com) | |
| 12 | +[](https://www.food-ka.com/doc/) | |
| 13 | +[](https://www.food-ka.com/doc/food-ka-documentation.pdf) | |
| 6 | 14 |  |
| 7 | 15 |  |
| 8 | 16 |  |
@@ -12,16 +20,28 @@ | ||
| 12 | 20 |  |
| 13 | 21 |  |
| 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 | |