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: refonte du README (pastilles + captures d écran à jour)

Simon-Pierre Boucher committed 1 mo ago (Aug 24, 2026) parent 8acf4c4

3 changed files +86 −216

modified README.md +86 −216
@@ -1,255 +1,125 @@
1 −<div align="center">
2 −
3 1 # Food·Ka
4 2
5 −### Tous les prix d'épicerie du Québec. Un seul endroit.
6 −
7 −**[www.food-ka.com](https://www.food-ka.com)**
8 −
9 −![Aperçu de Food-Ka](docs/screenshot.png)
10 −
11 −![Python](https://img.shields.io/badge/Python-3.14-141814?style=for-the-badge&logo=python&logoColor=d9f26b)
12 −![FastAPI](https://img.shields.io/badge/FastAPI-API-141814?style=for-the-badge&logo=fastapi&logoColor=d9f26b)
13 −![React](https://img.shields.io/badge/React_18-Vite_+_TS-141814?style=for-the-badge&logo=react&logoColor=d9f26b)
14 −![SQLite](https://img.shields.io/badge/SQLite-storage-141814?style=for-the-badge&logo=sqlite&logoColor=d9f26b)
15 −![PWA](https://img.shields.io/badge/PWA-mobile_ready-141814?style=for-the-badge&logoColor=d9f26b)
16 −
17 −![Bannières](https://img.shields.io/badge/banni%C3%A8res_recens%C3%A9es-30-1c5c41?style=flat-square)
18 −![Connecteurs](https://img.shields.io/badge/connecteurs_actifs-24-1c5c41?style=flat-square)
19 −![Produits](https://img.shields.io/badge/produits_agr%C3%A9g%C3%A9s-22%20000%2B-1c5c41?style=flat-square)
20 −![Couverture](https://img.shields.io/badge/couverture-tout_le_Qu%C3%A9bec-1c5c41?style=flat-square)
3 +**Tous les prix d'épicerie du Québec — comparés, historisés et toujours à jour, un seul endroit.**
21 4
22 −*Agrégateur indépendant de produits d'épicerie — chaque produit avec son **prix courant**,
23 −son **prix régulier**, son **prix unitaire comparable ($/100 g)** et un lien direct vers la
24 −fiche originale de la bannière. **Toujours à jour, automatiquement.***
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)
6 +![Nœud](https://img.shields.io/badge/n%C5%93ud-M4M64b-1f6feb?style=flat-square)
7 +![Port](https://img.shields.io/badge/port-8097-555?style=flat-square)
8 +![PM2](https://img.shields.io/badge/process-PM2-2b037a?style=flat-square)
9 +![Python](https://img.shields.io/badge/Python-3.14-3776ab?style=flat-square&logo=python&logoColor=white)
10 +![FastAPI](https://img.shields.io/badge/FastAPI-API-009688?style=flat-square&logo=fastapi&logoColor=white)
11 +![React](https://img.shields.io/badge/React%2018-Vite%20%2B%20TS-61dafb?style=flat-square&logo=react&logoColor=black)
12 +![SQLite](https://img.shields.io/badge/SQLite-price__log-003b57?style=flat-square&logo=sqlite&logoColor=white)
13 +![Groupe KA](https://img.shields.io/badge/Groupe-KA-b7f000?style=flat-square)
25 14
26 −</div>
15 +**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**.
27 16
28 −---
29 −
30 −## Pourquoi Food-Ka ?
17 +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…).
31 18
32 −Comparer les prix d'épicerie au Québec, c'est ouvrir Metro, IGA, Maxi, Super C,
33 −Provigo, Walmart… chacun avec sa propre navigation, son propre panier, son propre
34 −format. **Food-Ka retourne le problème** : un **connecteur dédié par bannière** visite
35 −chaque site, **normalise chaque produit** vers un schéma unique, et **détecte les
36 −changements de prix en continu**.
19 +## Captures d'écran
37 20
38 −> Les épiceries n'offrent pas de webhooks. Food-Ka reproduit l'équivalent :
39 −> **synchronisation périodique + hash de contenu** → nouveaux produits, changements
40 −> de prix et retraits détectés automatiquement. Chaque variation de prix est
41 −> **historisée** (`price_log`) — les soldes deviennent traçables.
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>
42 25
43 26 ## Fonctionnalités
44 27
45 −- **Agrégation multi-bannières** — **24 connecteurs actifs** (sur **30 bannières recensées**), **22 000+ produits** couvrant **tout le Québec**.
28 +- **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`.
46 29 - **Prix unitaire comparable** — chaque produit ramené en **$/100 g** pour comparer l'incomparable.
47 −- **Détection des soldes** — prix courant vs **prix régulier**, tri par **rabais**, historique complet des variations.
48 −- **Comparaison inter-bannières** — chaque fiche produit montre les **équivalents chez les autres bannières**.
49 −- **Connexion KA ID** — **SSO du Groupe Ka** (courriel + Google) : un seul compte (`ka_id`) valable sur **toutes les plateformes ·Ka** (`foodka/auth.py`, profil via `hubprofile.py`).
50 −- **Favoris** — cœur sur chaque produit, **favoris synchronisés au compte KA ID** via le hub central (`foodka/hubfav.py`, page **Profil** dans le frontend).
30 +- **Détection des soldes** — prix courant vs prix régulier, tri par rabais, historique complet des variations de prix.
31 +- **Comparaison inter-bannières** — chaque fiche produit montre les équivalents chez les autres bannières (`foodka/matching.py`).
51 32 - **Recherche et filtres** — catégorie, bannière, marque, fourchette de prix, soldes, texte libre ; tris prix / prix unitaire / rabais / récents.
52 −- **Stats Groupe KA** — tableau de bord analytique commun avec **export PDF** (`statsdash.py`, `kapdf.py`).
53 −- **PWA installable** — design « éditorial sharp » (Space Grotesk, accent lime, ticker temps réel), **mobile-first**, cibles tactiles ≥ 44 px.
54 −- **Design system ka-ui** — tokens, footer, badge et écosystème **Groupe Ka** partagés (13 sites), page `/contact`, widget **KA Agent** (bulle de chat IA).
55 −
56 −## L'architecture en 30 secondes
57 −
58 −```mermaid
59 −flowchart LR
60 − subgraph Sources["Bannières d'épicerie"]
61 − S1["Metro · Super C · IGA/Voilà<br/>Maxi · Provigo · Walmart<br/>Mayrand · Avril · PA · Tau<br/>… 24 connecteurs actifs"]
62 − end
63 − subgraph FoodKa["Food-Ka"]
64 − C["Connecteurs<br/><i>1 adaptateur / bannière</i>"] --> N["Normalisation<br/><i>schéma Product unique</i>"]
65 − N --> D[("SQLite<br/>hash + diff + prix")]
66 − D --> A["API FastAPI<br/>/api/products · /api/facets"]
67 − A --> F["React 18 + Vite<br/>PWA mobile"]
68 − end
69 − W["⏱ Watcher (PM2)"] -.-> C
70 − S1 --> C
71 − F --> U["🛒 Consommateur"]
72 −```
33 +- **Données nutritionnelles** — enrichissement des fiches (`foodka/nutrition.py`).
34 +- **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`).
35 +- **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.
36 +- **SEO** — rendu serveur des fiches et pages (`foodka/seo.py`).
37 +- **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).
38 +- **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`.
73 39
74 −## Stack technique
40 +## Architecture
75 41
76 −| Couche | Techno | Rôle |
42 +| Composant | Technologie | Rôle |
77 43 |---|---|---|
78 −| **Backend** | **Python 3.14 + FastAPI** | API REST, sync, auth KA ID, favoris |
79 −| **Frontend** | **React 18 + Vite + TypeScript** | PWA, react-router, design ka-ui |
80 −| **Stockage** | **SQLite** (`data/foodka.db`) | produits, hash, `price_log`, `sync_log` |
81 −| **Scraping** | requests + **Scrapfly** / **Firecrawl** | HTML, APIs JSON, `__NEXT_DATA__`, anti-bot |
82 −| **Process** | **PM2** + **ngrok** | résilience (auto-restart) + tunnel |
44 +| Backend | Python 3.14 · FastAPI · Uvicorn | API REST (`/api/products`, `/api/facets`, `/api/stats`…), auth KA ID, favoris, stats (`foodka/web.py`) |
45 +| Base de données | SQLite (`data/foodka.db`, mode WAL) | Produits, hash de contenu, `price_log`, `sync_log` — diff engine (upsert : nouveau / modifié / disparu) |
46 +| 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__`… |
47 +| Frontend | React 18 · Vite · TypeScript | PWA, react-router, ka-ui vendorisé, fiches avec comparaison inter-bannières (build → `frontend/dist/`) |
48 +| PDF | reportlab · fpdf2 | Export des rapports statistiques |
83 49
84 −## Structure du projet
85 −
86 −```
87 −food-ka/
88 −├── run.py # CLI : sync · serve · watch
89 −├── requirements.txt
90 −├── foodka/ # backend Python
91 −│ ├── web.py # API FastAPI (produits, facettes, stats, sync)
92 −│ ├── auth.py # connexion KA ID (SSO Groupe Ka)
93 −│ ├── hubfav.py # favoris synchronisés au hub KA ID
94 −│ ├── hubprofile.py # profil utilisateur KA ID
95 −│ ├── schema.py # Product normalisé + prix unitaire $/100 g
96 −│ ├── db.py # diff engine (hash, upsert, price_log)
97 −│ ├── ingest.py # orchestration des synchronisations
98 −│ ├── normalize.py # catégories canoniques, parsing des prix
99 −│ ├── statsdash.py # tableau de bord Stats Groupe KA
100 −│ ├── kapdf.py / pdfgen.py# export PDF
101 −│ └── connectors/ # 1 module auto-découvert par bannière
102 −├── frontend/ # React 18 + Vite + TS (PWA, ka-ui vendorisé)
103 −├── data/ # foodka.db + sources.json (registre des bannières)
104 −├── docs/ # screenshot.png
105 −└── tests/
106 −```
50 +Trois processus PM2 assurent la production :
107 51
108 −| Couche | Détail | Fichiers |
52 +| Processus | Commande | Rôle |
109 53 |---|---|---|
110 −| **Connecteurs** | 1 module Python par bannière : HTML rendu serveur, API JSON ouvertes (Shopify `products.json`, WooCommerce Store API), `__NEXT_DATA__` (Loblaw), ou **Scrapfly** (anti-bot ASP + rendu JS) / **Firecrawl** pour les sites protégés | `foodka/connectors/*.py` |
111 −| **Schéma** | `Product` standardisé : nom, marque, format, prix, prix régulier, **prix unitaire $/100 g**, catégorie canonique, images | `foodka/schema.py` |
112 −| **Diff engine** | Upsert par hash de contenu — nouveau / modifié / disparu (désactivé), historique de prix | `foodka/db.py` |
113 −| **API** | Filtres catégorie / bannière / marque / prix / soldes / recherche, tris (prix, prix unitaire, rabais), facettes, stats | `foodka/web.py` |
114 −| **Frontend** | Design « éditorial sharp » : Space Grotesk, ombres décalées, accent lime, ticker temps réel, fiches produit avec comparaison inter-bannières, PWA installable | `frontend/` |
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 |
57 +
58 +## Structure du repo
59 +
60 +| Répertoire / fichier | Rôle |
61 +|---|---|
62 +| `run.py` | Point d'entrée CLI : `sync` · `watch` · `serve` |
63 +| `requirements.txt` | Dépendances backend (FastAPI, uvicorn, requests, bs4, reportlab, fpdf2, pillow) |
64 +| `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) |
66 +| `data/` | `foodka.db` (SQLite) + `sources.json` (registre des bannières) |
67 +| `docs/` | Captures d'écran + documentation générée des connecteurs |
68 +| `scripts/` | Outillage (`gen_connector_docs.py`) |
69 +| `tests/` | Tests (normalisation, connecteur Flipp) |
70 +
71 +## Développement (remote-first)
115 72
116 −## Démarrage local
73 +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.
117 74
118 75 ```bash
119 −git clone gitsrv:srv/git/food-ka.git && cd food-ka
76 +ssh M4M64b
77 +cd ~/apps/food-ka
120 78
121 79 # Backend
122 80 python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
81 +.venv/bin/python run.py sync # synchroniser toutes les bannières (ou : run.py sync metro iga)
82 +.venv/bin/python run.py serve 8080 # servir en local
123 83
124 84 # Frontend
125 85 cd frontend && npm install && npm run build && cd ..
126 86
127 −# Sites protégés (anti-bot) et rendu JavaScript
128 −cat > .env <<'ENV'
129 −SCRAPFLY_API_KEY=scp-live-votre-cle
130 −FIRECRAWL_API_KEY=fc-votre-cle
131 −ENV
87 +# Après un changement en production
88 +pm2 restart food-ka-web # (ou food-ka-sync selon le changement)
132 89
133 −# Ingestion puis service
134 −.venv/bin/python run.py sync # toutes les sources (ou: run.py sync metro iga)
135 −.venv/bin/python run.py serve 8080 # → http://localhost:8080
136 −.venv/bin/python run.py watch 360 # resynchronisation en boucle (minutes)
90 +# Versionner depuis le nœud (agent forwarding actif)
91 +git add <fichiers> && git commit -m "..." && git push origin main
137 92 ```
138 93
139 −## Ajouter une bannière (≈ 30 lignes)
140 −
141 −L'enregistrement est **auto-découvrant** : déposez un module dans `foodka/connectors/`,
142 −c'est tout — aucun fichier partagé à modifier.
143 −
144 −```python
145 −# foodka/connectors/mon_epicerie.py
146 −from ..schema import Product, normalize_category, parse_price
147 −from .base import BaseConnector
148 −
149 −class MonEpicerieConnector(BaseConnector):
150 − source_id = "mon_epicerie"
151 −
152 − def fetch(self) -> list[Product]:
153 − html = self.get("https://mon-epicerie.ca/produits").text # throttlé, poli
154 − # ... ou self.get_scrapfly(url) si le site est protégé ...
155 − return [Product(
156 − source=self.source_id, external_id="123",
157 − url="https://mon-epicerie.ca/produit/123",
158 − name="Beurre d'arachide croquant", brand="Kraft",
159 − category=normalize_category("Garde-manger"),
160 − size_label="500 g", price=parse_price("4,99 $"),
161 − regular_price=6.49, images=[...],
162 − )]
163 −```
164 −
165 −Puis : `.venv/bin/python run.py sync mon_epicerie` — et les produits apparaissent sur
166 −le site, avec prix unitaire calculé et comparaison inter-bannières. Ajoutez l'entrée
167 −correspondante dans `data/sources.json` pour la page **Sources**.
168 −
169 −## API
170 −
171 −| Endpoint | Description |
172 −|---|---|
173 −| `GET /api/products?category=&source=&brand=&price_min=&price_max=&on_sale=1&q=&sort=` | Recherche filtrée (tris : prix, prix unitaire, rabais, nom, récents) |
174 −| `GET /api/products/{uid}` | Fiche complète + historique de prix + **comparaison inter-bannières** |
175 −| `GET /api/facets` | Valeurs distinctes pour construire les filtres |
176 −| `GET /api/sources` | Registre des bannières + compteurs + dernière sync |
177 −| `GET /api/stats` | Totaux, soldes actifs, meilleures aubaines, journal de synchronisation |
178 −| `POST /api/sync` | Déclenche une synchronisation en arrière-plan |
94 +## Déploiement
179 95
180 −L'authentification **KA ID** et les **favoris** exposent leurs propres routes
181 −(`foodka/auth.py`, `foodka/hubfav.py`) adossées au **hub SSO central du Groupe Ka**
182 −(groupe-ka.com).
96 +- **Nœud** : M4M64b (Mac Studio, cluster MacLustr) — répertoire `~/apps/food-ka`
97 +- **Port local** : 8097
98 +- **Processus PM2** : `food-ka-web` (API + frontend), `food-ka-sync` (watcher de synchronisation), `food-ka-ngrok` (tunnel)
99 +- **Exposition publique** : tunnel ngrok → [https://www.food-ka.com](https://www.food-ka.com)
183 100
184 −## Couverture
101 +Philosophie d'exploitation : on ne pousse que le code — le serveur maintient ses données lui-même.
185 102
186 −**Grandes bannières** — Metro, Super C, IGA (Voilà), Maxi, Provigo, Walmart Canada,
187 −Costco Canada (épicerie livrée), Marché Adonis.
103 +## Écosystème Groupe KA
188 104
189 −**Spécialisées & indépendantes** — Mayrand (grossiste), Avril Supermarché Santé,
190 −Marché Tau, PA Supermarché, Aubut, Maturin (producteurs québécois), Giant Tiger,
191 −Epipresto, Marché Nuvo, La Boîte à Grains, BocoBoco, Aliments Merci, Club Entrepôt,
192 −Épiceries LOCO, Akhavan, T&T Supermarket.
193 −
194 −Chaque bannière non-connectable est **documentée avec sa raison** dans
195 −`data/sources.json` (ex. : prix liés à une session Instacart/DoorDash, catalogue
196 −sans prix, anti-bot strict).
197 −
198 −## Déploiement (production)
199 −
200 −- **Nœud** : **M4M64b** (Mac Studio, 16 cœurs / 64 Go) — répertoire `~/apps/food-ka`
201 −- **Port** : **8097**
202 −- **Domaine** : **[www.food-ka.com](https://www.food-ka.com)** (tunnel **ngrok**)
203 −- **Process manager** : **PM2** (3 processus, auto-restart) :
204 −
205 −```
206 −food-ka-web .venv/bin/python run.py serve 8097 # API + frontend
207 −food-ka-sync .venv/bin/python run.py watch 360 # resync aux 6 h
208 −food-ka-ngrok ngrok http --url=www.food-ka.com 8097 # tunnel
209 −```
210 −
211 −Philosophie d'exploitation : **on ne pousse que le code — le serveur maintient ses
212 −données lui-même.**
213 −
214 −## Développement remote-first (IMPORTANT)
215 −
216 −La **source de vérité est le repo git SUR le nœud M4M64b** (`~/apps/food-ka`), **pas
217 −une copie locale**. Toute modification se fait **via SSH sur le nœud** : édition,
218 −`npm run build` du frontend, `pm2 restart food-ka-web`, puis commit/push **depuis le
219 −nœud** (agent forwarding actif).
220 −
221 −- **Remote `origin` = spbgit** (git perso, **git.spboucher.ai**) via l'**alias SSH `gitsrv`** :
222 − `gitsrv:srv/git/food-ka.git` (bare repo hébergé sur M3U96a). **Pas GitHub.**
223 −- Ne **jamais** éditer d'éventuelles copies laptop — elles ne sont pas synchronisées.
224 −
225 −## Principes
226 −
227 −1. **Politesse** — délai ≥ 0,5 s entre requêtes, périmètre de crawl borné,
228 − User-Agent identifié.
229 −2. **Fidélité** — aucun prix inventé : si la source n'affiche pas de prix,
230 − `price = null` ; un « prix régulier » incohérent est rejeté.
231 −3. **Traçabilité** — chaque fiche renvoie vers le produit original de la bannière,
232 − et chaque changement de prix est historisé.
233 −4. **Robustesse** — un connecteur qui casse n'affecte jamais les autres
234 − (auto-découverte tolérante, try/except par produit, détection de dérive,
235 − journal `sync_log`).
105 +| Plateforme | Rôle |
106 +|---|---|
107 +| [groupe-ka.com](https://www.groupe-ka.com) | Portail |
108 +| [lou-ka.com](https://www.lou-ka.com) | Logements à louer |
109 +| [immo-ka.com](https://www.immo-ka.com) | Propriétés à vendre |
110 +| [vrai-prix.com](https://www.vrai-prix.com) | Estimation immobilière |
111 +| [auto-ka.com](https://www.auto-ka.com) | Véhicules |
112 +| [fabri-ka.com](https://www.fabri-ka.com) | Produits québécois |
113 +| [food-ka.com](https://www.food-ka.com) | Épicerie / alimentation |
114 +| [resto-ka.com](https://www.resto-ka.com) | Restaurants |
115 +| [sorti-ka.com](https://www.sorti-ka.com) | Sorties et événements |
116 +| [job-ka.com](https://www.job-ka.com) | Emplois |
117 +| [crea-ka.com](https://www.crea-ka.com) | Créateurs |
118 +| [trouve-ka.com](https://www.trouve-ka.com) | Petites annonces |
119 +| [api-ka.com](https://www.api-ka.com) | API de données |
236 120
237 121 ---
238 122
239 −<div align="center">
240 −
241 −## Auteur
242 −
243 −**Simon-Pierre Boucher**
244 −
245 −[![Email](https://img.shields.io/badge/contact@spboucher.ai-141814?style=for-the-badge&logo=minutemailer&logoColor=d9f26b)](mailto:contact@spboucher.ai)
246 −[![GitHub](https://img.shields.io/badge/spboucher--ai-141814?style=for-the-badge&logo=github&logoColor=d9f26b)](https://github.com/spboucher-ai)
247 −
248 −*Conçu, construit et déployé en une journée — de la recherche de marché
249 −(30 bannières recensées et vérifiées) au produit en production.*
250 −
251 −© 2026 Simon-Pierre Boucher — tous droits réservés.
252 −
253 −**Un service [Groupe Ka](https://www.groupe-ka.com)**
123 +© Groupe KA — Simon-Pierre Boucher · [contact@spboucher.ai](mailto:contact@spboucher.ai)
254 124
255 −</div>
125 +Ce repo vit sur **spbgit** ([git.spboucher.ai](https://git.spboucher.ai)) — la source de vérité est le clone sur le nœud M4M64b.
added docs/screenshots/food-ka-desktop.png +0 −0

Binary file not shown.

added docs/screenshots/food-ka-mobile.png +0 −0

Binary file not shown.