docs: refonte du README (pastilles + captures d écran à jour)
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 | − | |
| 10 | − | |
| 11 | − | |
| 12 | − | |
| 13 | − | |
| 14 | − | |
| 15 | − | |
| 16 | − | |
| 17 | − | |
| 18 | − | |
| 19 | − | |
| 20 | − | |
| 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 | +[](https://www.food-ka.com) | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 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 | −[](mailto:contact@spboucher.ai) | |
| 246 | −[](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.