docs: README v3 — chiffres live vérifiés, pastilles dynamiques, sections complètes
1 changed file +160 −80
modified
README.md
+160 −80
@@ -1,54 +1,66 @@ | ||
| 1 | −<div align="center"> | |
| 2 | − | |
| 3 | −# Fabri·Ka | |
| 4 | − | |
| 5 | −### Tous les produits québécois. Un seul endroit. | |
| 1 | +<p align="center"> | |
| 2 | + <a href="https://www.fabri-ka.com"><img src="https://www.fabri-ka.com/og.png" width="760" alt="Fabri·Ka — Tous les produits québécois. Un seul endroit."></a> | |
| 3 | +</p> | |
| 6 | 4 | |
| 7 | −**[www.fabri-ka.com](https://www.fabri-ka.com)** | |
| 5 | +<h1 align="center">Fabri·Ka</h1> | |
| 8 | 6 | |
| 9 | − | |
| 10 | − | |
| 11 | − | |
| 12 | − | |
| 13 | − | |
| 7 | +<p align="center"><b>Tous les produits québécois. Un seul endroit.</b><br><a href="https://www.fabri-ka.com">www.fabri-ka.com</a></p> | |
| 14 | 8 | |
| 15 | − | |
| 16 | − | |
| 17 | − | |
| 18 | − | |
| 19 | − | |
| 20 | − | |
| 9 | +<div align="center"> | |
| 21 | 10 | |
| 22 | − | |
| 23 | − | |
| 24 | − | |
| 25 | − | |
| 11 | +<a href="https://www.fabri-ka.com"><img src="https://img.shields.io/website?url=https%3A%2F%2Fwww.fabri-ka.com&style=flat-square&label=www.fabri-ka.com&up_color=c4532e" alt="Site"></a> | |
| 12 | +<a href="https://www.fabri-ka.com/doc/fabri-ka-documentation.pdf"><img src="https://img.shields.io/badge/guide-PDF-c4532e?style=flat-square" alt="Guide PDF"></a> | |
| 13 | +<a href="https://www.fabri-ka.com/stats"><img src="https://img.shields.io/badge/📊_statistiques-%2Fstats-c4532e?style=flat-square" alt="Stats"></a> | |
| 14 | +<img src="https://img.shields.io/badge/n%C5%93ud-M4M64a-1f6feb?style=flat-square" alt="Nœud"> | |
| 15 | +<img src="https://img.shields.io/badge/port-8097-555?style=flat-square" alt="Port"> | |
| 16 | +<img src="https://img.shields.io/badge/PM2-3_processus-2b037a?style=flat-square" alt="PM2"> | |
| 17 | + | |
| 18 | +<a href="https://www.fabri-ka.com/api/stats"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.fabri-ka.com%2Fapi%2Fstats&query=%24.totals.products&label=produits&color=c4532e&style=flat-square" alt="Produits (live)"></a> | |
| 19 | +<a href="https://www.fabri-ka.com/api/stats"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.fabri-ka.com%2Fapi%2Fstats&query=%24.totals.stores_live&label=boutiques%20live&color=c4532e&style=flat-square" alt="Boutiques live"></a> | |
| 20 | +<a href="https://www.fabri-ka.com/api/stats"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.fabri-ka.com%2Fapi%2Fstats&query=%24.totals.stores_registry&label=registre%20QC&color=c4532e&style=flat-square" alt="Registre"></a> | |
| 21 | +<a href="https://www.fabri-ka.com/api/stats"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fwww.fabri-ka.com%2Fapi%2Fstats&query=%24.totals.regions&label=r%C3%A9gions&color=c4532e&style=flat-square" alt="Régions"></a> | |
| 22 | +<img src="https://img.shields.io/badge/connecteurs_plateforme-9-234438?style=flat-square" alt="Connecteurs"> | |
| 23 | +<img src="https://img.shields.io/badge/cat%C3%A9gories-20-234438?style=flat-square" alt="Catégories"> | |
| 24 | + | |
| 25 | +<img src="https://img.shields.io/badge/Python-FastAPI-3776ab?style=flat-square&logo=python&logoColor=white" alt="Python FastAPI"> | |
| 26 | +<img src="https://img.shields.io/badge/React_18-Vite_%2B_TS-61dafb?style=flat-square&logo=react&logoColor=black" alt="React 18"> | |
| 27 | +<img src="https://img.shields.io/badge/SQLite-FTS5-003b57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite FTS5"> | |
| 28 | +<img src="https://img.shields.io/badge/Firecrawl-rendu_JS-ff6b35?style=flat-square" alt="Firecrawl"> | |
| 29 | +<img src="https://img.shields.io/badge/Scrapfly-anti--bot-6f42c1?style=flat-square" alt="Scrapfly"> | |
| 30 | +<img src="https://img.shields.io/badge/PM2-prod-2b037a?style=flat-square&logo=pm2&logoColor=white" alt="PM2"> | |
| 31 | +<img src="https://img.shields.io/badge/ngrok-tunnel-1f1e37?style=flat-square&logo=ngrok&logoColor=white" alt="ngrok"> | |
| 32 | +<img src="https://img.shields.io/badge/KA_ID-SSO-c4532e?style=flat-square" alt="KA ID"> | |
| 33 | +<img src="https://img.shields.io/badge/Groupe-KA-b7f000?style=flat-square" alt="Groupe KA"> | |
| 34 | +<a href="https://git.spboucher.ai"><img src="https://img.shields.io/badge/remote--first-spbgit-f05032?style=flat-square&logo=git&logoColor=white" alt="spbgit"></a> | |
| 26 | 35 | |
| 27 | 36 | </div> |
| 28 | 37 | |
| 38 | +*Les pastilles « produits / boutiques live / registre QC / régions » sont **dynamiques** : elles interrogent `https://www.fabri-ka.com/api/stats` en direct.* | |
| 39 | + | |
| 29 | 40 |  |
| 30 | 41 | |
| 31 | 42 | --- |
| 32 | 43 | |
| 33 | 44 | ## Description |
| 34 | 45 | |
| 35 | −**Fabri-Ka** est le **répertoire des produits québécois** : un agrégateur de découverte qui recense **301 534 produits** provenant de **1 377 boutiques en ligne** du Québec, couvrant les **17 régions administratives** de la province. Chaque produit renvoie vers la **boutique d'origine** — **aucune vente sur Fabri-Ka** : les prix, photos et stocks appartiennent aux marchands sources. | |
| 46 | +**Fabri-Ka** est le **répertoire des produits québécois** : un agrégateur de découverte qui recense **385 308 produits** (au 2026-08-24) provenant de **1 582 boutiques en ligne** du Québec, couvrant les **17 régions administratives** de la province. Chaque produit renvoie vers la **boutique d'origine** — **aucune vente sur Fabri-Ka** : les prix, photos et stocks appartiennent aux marchands sources. | |
| 36 | 47 | |
| 37 | −Acheter québécois demande de connaître des centaines de boutiques dispersées — érablières, microbrasseries, savonneries, ébénistes, torréfacteurs, fermes… **Fabri-Ka retourne le problème** : un pipeline de découverte recense les boutiques en ligne du Québec (**3 507 boutiques vérifiées** au registre), des connecteurs par *plateforme* aspirent leurs catalogues publics complets, et un **moteur de recherche unique** les rend trouvables — filtrés par **catégorie**, **région** et **origine de fabrication** (classes **A–E**). | |
| 48 | +Acheter québécois demande de connaître des centaines de boutiques dispersées — érablières, microbrasseries, savonneries, ébénistes, torréfacteurs, fermes… **Fabri-Ka retourne le problème** : un pipeline de découverte recense les boutiques en ligne du Québec (**4 082 boutiques vérifiées** au registre), des connecteurs par *plateforme* aspirent leurs catalogues publics complets, et un **moteur de recherche unique** les rend trouvables — filtrés par **catégorie**, **région** et **origine de fabrication** (classes **A–E**). | |
| 38 | 49 | |
| 39 | 50 | > Contrairement à un agrégateur classique (1 connecteur / site), Fabri-Ka utilise **1 connecteur / plateforme ecommerce** : le même code **Shopify** sert des centaines de boutiques, piloté par le registre `data/stores.json` produit par la recherche. |
| 40 | 51 | |
| 41 | 52 | ## Fonctionnalités |
| 42 | 53 | |
| 43 | −- **Recherche de produits** — plein-texte **FTS5 accent-insensible** sur **301 534 produits**, filtres **catégorie / région / origine / prix**, tri, pagination, fiches riches (galerie, boutique, produits liés). | |
| 44 | −- **Répertoire de boutiques** — **1 377 boutiques** avec produits (sur **3 507 vérifiées**), fiches enrichies : logo, région, plateforme, **stats de prix**, **politique de livraison** (colonne `shipping_info`, extraite des pages politiques), catégories, boutiques similaires. | |
| 45 | −- **Statistiques** — tableau de bord analytique `/stats` (module commun **ka-stats**) : totaux, médianes, histogrammes, ventilation régionale, croissance — et **rapport de marché PDF** généré à la volée (`/api/report.pdf`, moteur **kapdf**). | |
| 46 | −- **Catégories** — taxonomie de **20 catégories** (mode 38 k · bijoux 34 k · épicerie fine 29 k · …) avec **~350 pages programmatiques SEO** (`/categorie/erable`, `/region/monteregie`, combinaisons non vides). | |
| 54 | +- **Recherche de produits** — plein-texte **FTS5 accent-insensible** sur **385 308 produits**, filtres **catégorie / région / origine / prix**, tri, pagination, fiches riches (galerie, boutique, produits liés). | |
| 55 | +- **Répertoire de boutiques** — **1 582 boutiques** avec produits (sur **4 082 vérifiées**), fiches enrichies : logo, région, plateforme, **stats de prix**, **politique de livraison** (colonne `shipping_info`, extraite des pages politiques), catégories, boutiques similaires. | |
| 56 | +- **Statistiques** — tableau de bord analytique `/stats` (module commun **ka-stats**) : totaux, médianes, histogrammes, ventilation régionale, croissance — et **rapports de marché PDF** générés à la volée (`/api/report.pdf`, moteur **kapdf**, 5 modes + rapports personnalisés). | |
| 57 | +- **Catégories** — taxonomie de **20 catégories** (épicerie fine 44 k · mode 43 k · bijoux 39 k · …) avec **~350 pages programmatiques SEO** (`/categorie/erable`, `/region/monteregie`, combinaisons non vides). | |
| 47 | 58 | - **Classification d'origine A–E** — chaque boutique justifiée par une **évidence conservée** (certifications *Aliments du Québec* / *Les Produits du Québec*, associations, wording du site). |
| 48 | −- **SEO / SSR** — **301 000+ pages indexables** : HTML complet dès la 1ʳᵉ requête, **JSON-LD** schema.org, **sitemaps** exhaustifs, 301/404/410 propres (détails plus bas). | |
| 59 | +- **SEO / SSR** — **385 000+ pages indexables** : HTML complet dès la 1ʳᵉ requête, **JSON-LD** schema.org, **sitemaps** exhaustifs, 301/404/410 propres (détails plus bas). | |
| 49 | 60 | - **KA ID (SSO)** + favoris **« Mon univers Ka »** synchronisés au hub **groupe-ka.com**. |
| 50 | 61 | - **Widget KA Agent** — bulle de chat Groupe KA (`ka-agent.js`). |
| 51 | 62 | - **Mobile-first** — barre d'onglets, filtres en bottom sheet, galeries swipe, CTA collant, PWA-lite, **fr-CA** d'abord. |
| 63 | +- **Supervision** — connecteurs surveillés par les gardiens autonomes du Groupe KA (agents ka6, supervision api-ka) ; `/api/stats` expose le `sync_log` et les boutiques désactivées. | |
| 52 | 64 | |
| 53 | 65 | ### Galerie |
| 54 | 66 | |
@@ -70,6 +82,22 @@ Acheter québécois demande de connaître des centaines de boutiques dispersées | ||
| 70 | 82 | <img src="docs/screenshots/mobile-produit.png" width="240" alt="Fiche produit mobile"/> |
| 71 | 83 | </p> |
| 72 | 84 | |
| 85 | +## Chiffres (au 2026-08-24, `/api/stats` live + registre) | |
| 86 | + | |
| 87 | +| Mesure | Valeur | | |
| 88 | +|---|---| | |
| 89 | +| Produits agrégés (catalogues complets) | **385 308** (dont 370 533 avec prix — prix médian 25 $, moyen 228 $) | | |
| 90 | +| Boutiques avec produits en ligne | **1 582** | | |
| 91 | +| Boutiques québécoises vérifiées au registre (`data/stores.json`) | **4 082** — dont 2 466 avec ecommerce détecté et 1 701 activées pour la sync | | |
| 92 | +| Régions administratives couvertes | **17 / 17** (Montréal 56 k produits · Outaouais 32 k · Saguenay–Lac-Saint-Jean 24 k · …) | | |
| 93 | +| Connecteurs plateforme | **9** — boutiques actives : Shopify 715 · WooCommerce 545 · Wix 302 · Votresite.ca 45 · Square 36 · Squarespace 27 · générique 22 · autres 9 | | |
| 94 | +| Classes d'origine au registre | A : 3 863 · E : 180 · C : 39 | | |
| 95 | +| Catégories | **20** (épicerie fine 44 k · mode 43 k · bijoux 39 k · …) | | |
| 96 | +| Pages indexables (produits + boutiques + programmatiques) | **385 000+** | | |
| 97 | +| Base | `data/fabrika.db` **3,2 Go** (SQLite + FTS5) | | |
| 98 | + | |
| 99 | +Détails et méthodologie : [`deliverables/research_report.md`](deliverables/research_report.md) · stratégie de découverte continue : [`deliverables/discovery_strategy.md`](deliverables/discovery_strategy.md) · conformité par source : [`docs/CONFORMITE.md`](docs/CONFORMITE.md). | |
| 100 | + | |
| 73 | 101 | ## Stack technique |
| 74 | 102 | |
| 75 | 103 | | Couche | Technologies | |
@@ -77,10 +105,10 @@ Acheter québécois demande de connaître des centaines de boutiques dispersées | ||
| 77 | 105 | | **Backend** | **Python 3.14** · **FastAPI** (API + SSR SEO + service du frontend) | |
| 78 | 106 | | **Base de données** | **SQLite + FTS5** — upsert par **hash de contenu**, retraits avec délai de grâce (2 syncs) | |
| 79 | 107 | | **Frontend** | **React 18 + Vite + TypeScript** — 9 pages, identité famille KA « éditorial sharp » (Space Grotesk + Inter + JetBrains Mono, palette crème/terracotta/pin/miel), tokens **ka-ui** | |
| 80 | −| **Connecteurs** | **Shopify** `products.json` (transport curl anti-429 TLS) · **WooCommerce** Store API · **Wix Stores** GraphQL · **Squarespace** `?format=json` · **Square Online** API storefront publique (`/app/store/api/v13/…/products`, IDs user/site extraits du HTML de la page d'accueil) · **Votresite.ca** (plateforme QC : Drupal 8 + boutique OpenCart en sous-répertoire — sitemap OpenCart ou crawl des catégories, puis fiche par fiche) · **connecteur générique** (sitemap → JSON-LD/microdata/OG : PrestaShop, Lightspeed, Snipcart, Magento, sites custom) · **Scrapfly/Firecrawl** en secours anti-bot. **Ecwid** non couvert : storefront 100 % client-side (l'API REST v3 exige un token secret — le token `pub…` de script.js est générique et refusé (403) ; aucun rendu serveur du catalogue, ni sur les instant sites ni via le plugin WordPress) | | |
| 108 | +| **Connecteurs** | **Shopify** `products.json` (transport curl anti-429 TLS) · **WooCommerce** Store API (+ fallback sitemap Yoast/AIOSEO, permaliens personnalisés) · **Wix Stores** GraphQL · **Squarespace** `?format=json` · **Square Online** API storefront publique (`/app/store/api/v13/…/products`, IDs user/site extraits du HTML de la page d'accueil) · **Votresite.ca** (plateforme QC : Drupal 8 + boutique OpenCart en sous-répertoire — sitemap OpenCart ou crawl des catégories, puis fiche par fiche) · **connecteur générique** (sitemap → JSON-LD/microdata/OG : PrestaShop, Lightspeed, Snipcart, Magento, sites custom) · **Scrapfly/Firecrawl** en secours anti-bot. **Ecwid** non couvert : storefront 100 % client-side (l'API REST v3 exige un token secret — le token `pub…` de script.js est générique et refusé (403) ; aucun rendu serveur du catalogue, ni sur les instant sites ni via le plugin WordPress) | | |
| 81 | 109 | | **Découverte** | **35+ sources** : sitemaps d'annuaires, API cachées de cartes (wpgmza, FacetWP), pagination htmx, sessions **Firecrawl** pour répertoires JS | |
| 82 | 110 | | **Comptes** | **KA ID** SSO (JWT HS256, stdlib pure) · favoris HMAC-SHA256 vers le hub central | |
| 83 | −| **Prod** | **PM2** + **ngrok** sur le cluster **MacLustr** | | |
| 111 | +| **Prod** | **PM2** + **ngrok** sur le cluster **MacLustr** (nœud M4M64a) | | |
| 84 | 112 | |
| 85 | 113 | ### Architecture en 30 secondes |
| 86 | 114 | |
@@ -88,10 +116,10 @@ Acheter québécois demande de connaître des centaines de boutiques dispersées | ||
| 88 | 116 | flowchart LR |
| 89 | 117 | subgraph Discovery["Pipeline de découverte (scripts/)"] |
| 90 | 118 | A["35+ annuaires sources<br/>certifications · associations ·<br/>marques régionales · balayages"] --> B["harvest → aggregate →<br/>verify → classify A–E"] |
| 91 | − B --> R[("stores.json<br/>3 507 boutiques QC")] | |
| 119 | + B --> R[("stores.json<br/>4 082 boutiques QC")] | |
| 92 | 120 | end |
| 93 | 121 | subgraph FabriKa["Plateforme (fabrika/)"] |
| 94 | − R --> C["Connecteurs plateforme<br/>Shopify · Woo · Wix · Squarespace · Square ·<br/>générique (JSON-LD) · Scrapfly"] | |
| 122 | + R --> C["Connecteurs plateforme<br/>Shopify · Woo · Wix · Squarespace · Square ·<br/>Votresite.ca · générique (JSON-LD) · Scrapfly"] | |
| 95 | 123 | C --> D[("SQLite + FTS5<br/>hash + diff")] |
| 96 | 124 | D --> E["API FastAPI<br/>/api/products · /api/facets"] |
| 97 | 125 | D --> S["Rendu serveur SEO<br/>HTML complet · JSON-LD ·<br/>sitemaps · 301/404/410"] |
@@ -103,7 +131,7 @@ flowchart LR | ||
| 103 | 131 | F --> U["🍁 Acheteur local"] |
| 104 | 132 | ``` |
| 105 | 133 | |
| 106 | −## SEO & rendu serveur — **301 000+ pages indexables** | |
| 134 | +## SEO & rendu serveur — **385 000+ pages indexables** | |
| 107 | 135 | |
| 108 | 136 | Le site est une SPA React, mais **aucun moteur de recherche ne voit une page vide** : le catch-all FastAPI (`fabrika/seo.py`) injecte dans le HTML du build Vite, pour chaque route, un `<head>` complet **et le contenu essentiel de la page dans `#root`** — React remplace ce contenu au montage (hydratation). |
| 109 | 137 | |
@@ -117,25 +145,44 @@ Le site est une SPA React, mais **aucun moteur de recherche ne voit une page vid | ||
| 117 | 145 | |
| 118 | 146 | **URLs & statuts propres** : slug lisible + uid (`/produits/sirop-d-erable-…-b63130ffc8b18c8cc650`), **301** de l'uid nu vers l'URL slugée, **410 Gone** pour les produits retirés, **404** pour les uid inconnus — fini le soft-404. |
| 119 | 147 | |
| 120 | −**Sitemaps & robots** : `/robots.txt` → `/sitemap.xml` (index) → `sitemap-pages.xml` + `sitemap-boutiques.xml` + `sitemap-produits-{1..8}.xml` (**40 000 URLs/chunk**, `lastmod` réel, régénérés automatiquement, cache 1 h). | |
| 148 | +**Sitemaps & robots** : `/robots.txt` → `/sitemap.xml` (index) → `sitemap-pages.xml` + `sitemap-boutiques.xml` + `sitemap-produits-{n}.xml` (**40 000 URLs/chunk**, `lastmod` réel, régénérés automatiquement, cache 1 h). | |
| 121 | 149 | |
| 122 | 150 | **Performance** : **GZip** (‑80 % sur le HTML), `Cache-Control: immutable` sur les assets hashés, images `loading="lazy"` avec dimensions explicites, polices en `swap`. |
| 123 | 151 | |
| 124 | 152 | ## API |
| 125 | 153 | |
| 126 | −| Endpoint | Description | | |
| 127 | −|---|---| | |
| 128 | −| `GET /api/products?q=&category=®ion=&origin=&price_min=&price_max=&sort=&page=` | Recherche plein-texte + filtres, triée | | |
| 129 | −| `GET /api/products/{uid}` | Fiche produit (galerie, boutique, produits liés) | | |
| 130 | −| `GET /api/stores?region=&q=&with_products=` | Répertoire des boutiques (logo, région, plateforme) | | |
| 131 | −| `GET /api/stores/{id}` | Fiche boutique enrichie : stats de prix, catégories, boutiques similaires | | |
| 132 | −| `GET /api/facets` | Catégories/régions/origines avec compteurs | | |
| 133 | −| `GET /api/stats` · `GET /api/stats/extended` | Totaux, ventilation régionale · stats riches (médianes, histogrammes, croissance) | | |
| 134 | −| `GET /api/report.pdf` | Rapport de marché PDF — généré à la volée | | |
| 135 | −| `POST /api/sync` | Déclenche une synchronisation en arrière-plan | | |
| 136 | −| `GET /api/auth/ka/login` → `…/callback` · `GET /api/auth/me` · `POST /api/auth/logout` | SSO **KA ID** | | |
| 137 | −| `GET /api/favorites` · `POST /api/favorites/toggle` | Favoris « Mon univers Ka » (hub central) | | |
| 138 | −| `GET /robots.txt` · `GET /sitemap.xml` (+ sous-sitemaps) | Infrastructure SEO | | |
| 154 | +| Endpoint | Méthode | Description | | |
| 155 | +|---|---|---| | |
| 156 | +| `/api/products?q=&category=®ion=&origin=&price_min=&price_max=&sort=&page=` | GET | recherche plein-texte + filtres, triée | | |
| 157 | +| `/api/products/{uid}` | GET | fiche produit (galerie, boutique, produits liés) | | |
| 158 | +| `/api/stores?region=&q=&with_products=` | GET | répertoire des boutiques (logo, région, plateforme) | | |
| 159 | +| `/api/stores/{id}` | GET | fiche boutique enrichie : stats de prix, catégories, boutiques similaires | | |
| 160 | +| `/api/facets` | GET | catégories/régions/origines avec compteurs | | |
| 161 | +| `/api/stats` | GET | totaux live, ventilation régionale, `sync_log`, boutiques désactivées | | |
| 162 | +| `/api/stats/extended` | GET | stats riches : médianes, histogrammes, croissance, ventilation par catégorie | | |
| 163 | +| `/api/report.pdf` | GET | rapport de marché PDF — généré à la volée (5 modes + `ReportBuilder` personnalisé) | | |
| 164 | +| `/api/sync` | POST | déclenche une synchronisation en arrière-plan | | |
| 165 | +| `/api/auth/ka/login` → `…/callback` · `/api/auth/me` · `/api/auth/logout` | GET/POST | SSO **KA ID** | | |
| 166 | +| `/api/favorites` · `/api/favorites/toggle` | GET/POST | favoris « Mon univers Ka » (hub central) | | |
| 167 | +| `/robots.txt` · `/sitemap.xml` (+ sous-sitemaps) | GET | infrastructure SEO | | |
| 168 | + | |
| 169 | +## Connecteurs & cadences | |
| 170 | + | |
| 171 | +**9 connecteurs plateforme** (`fabrika/connectors/`) pilotés par le registre `data/stores.json` : | |
| 172 | + | |
| 173 | +| Connecteur | Boutiques actives | Technique | Cadence | | |
| 174 | +|---|---|---|---| | |
| 175 | +| `shopify.py` | 715 | `products.json` paginé, transport curl anti-429, retry durci | resync complète aux 6 h | | |
| 176 | +| `woocommerce.py` | 545 | Store API `/wp-json/wc/store/v1/products` + fallback sitemap → fiches | aux 6 h | | |
| 177 | +| `wix.py` | 302 | GraphQL storefront public (jeton public) | aux 6 h | | |
| 178 | +| `votresite.py` | 45 | plateforme QC (Drupal 8 + OpenCart) : sitemap ou crawl catégories → fiche par fiche | aux 6 h | | |
| 179 | +| `square.py` | 36 | API storefront publique v13, IDs extraits du HTML | aux 6 h | | |
| 180 | +| `squarespace.py` | 27 | `?format=json` par collection | aux 6 h | | |
| 181 | +| `generic.py` | 22 | sitemap → JSON-LD/microdata/OG (PrestaShop, Lightspeed, Snipcart, Magento, custom) | aux 6 h | | |
| 182 | +| `scrapfly.py` / Firecrawl | secours | rendu JS / anti-bot pour les sites qui bloquent | à la demande | | |
| 183 | + | |
| 184 | +- Journal `sync_log` par boutique (found/added/updated/removed + raison d'échec), exposé par `/api/stats`. | |
| 185 | +- Une boutique qui casse **n'affecte jamais les autres** ; les faux positifs de découverte sont désactivés (`enabled=0`) avec garde anti-réintroduction (`reprobe_stores.py`). | |
| 139 | 186 | |
| 140 | 187 | ## Classification d'origine |
| 141 | 188 | |
@@ -147,22 +194,7 @@ Le site est une SPA React, mais **aucun moteur de recherche ne voit une page vid | ||
| 147 | 194 | | **D** | Mixte | |
| 148 | 195 | | **E** | Incertain — à vérifier | |
| 149 | 196 | |
| 150 | −Chaque classe est justifiée par une **évidence conservée** — jamais déduite du seul fait qu'une entreprise « semble » québécoise. | |
| 151 | − | |
| 152 | −## Chiffres (2026-08-18, site live) | |
| 153 | − | |
| 154 | −| Mesure | Valeur | | |
| 155 | −|---|---| | |
| 156 | −| Produits agrégés (catalogues complets) | **301 534** | | |
| 157 | −| Boutiques avec produits en ligne | **1 377** | | |
| 158 | −| Régions administratives couvertes | **17 / 17** | | |
| 159 | −| Boutiques québécoises actives vérifiées (registre) | **3 507** | | |
| 160 | −| — avec ecommerce détecté | 2 141 | | |
| 161 | −| Domaines candidats découverts et dédupliqués | 3 980 | | |
| 162 | −| Catégories | **20** (mode 38 k · bijoux 32 k · épicerie fine 28 k · …) | | |
| 163 | −| Pages indexables (produits + boutiques + programmatiques) | **301 000+** | | |
| 164 | − | |
| 165 | −Détails et méthodologie : [`deliverables/research_report.md`](deliverables/research_report.md) · stratégie de découverte continue : [`deliverables/discovery_strategy.md`](deliverables/discovery_strategy.md). | |
| 197 | +Chaque classe est justifiée par une **évidence conservée** — jamais déduite du seul fait qu'une entreprise « semble » québécoise. Répartition au registre (2026-08-24) : **A 3 863 · E 180 · C 39**. | |
| 166 | 198 | |
| 167 | 199 | ## Structure du projet |
| 168 | 200 | |
@@ -178,45 +210,62 @@ fabri-ka/ | ||
| 178 | 210 | │ ├── auth.py # SSO « KA ID » (JWT HS256, zéro dépendance) |
| 179 | 211 | │ ├── hubfav.py # favoris poussés au hub Groupe KA (HMAC) |
| 180 | 212 | │ ├── hubprofile.py # profil membre lu du hub |
| 181 | −│ └── connectors/ # shopify · woocommerce · wix · squarespace · generic · scrapfly | |
| 213 | +│ └── connectors/ # shopify · woocommerce · wix · squarespace · square · votresite · generic · scrapfly | |
| 182 | 214 | ├── frontend/ # React 18 + Vite + TS — 9 pages, PWA-lite, fr-CA |
| 183 | −├── scripts/ # pipeline de découverte (harvest → verify → registry) | |
| 184 | −├── data/ # stores.json (registre) · fabrika.db · caches (non versionnés) | |
| 215 | +├── scripts/ # pipeline de découverte (harvest → aggregate → verify → registry), | |
| 216 | +│ # enrichissements (contacts, livraison, collections), reprobe, docs connecteurs | |
| 217 | +├── data/ # stores.json (registre 4 082) · fabrika.db (3,2 Go) · caches (non versionnés) | |
| 185 | 218 | ├── deliverables/ # rapport de recherche, CSV des boutiques, sources |
| 186 | −├── docs/ # captures d'écran de ce README | |
| 219 | +├── docs/ # captures d'écran, CONFORMITE.md, fiches des connecteurs | |
| 187 | 220 | └── run.py # CLI : sync · serve · watch |
| 188 | 221 | ``` |
| 189 | 222 | |
| 190 | −## Démarrage local | |
| 223 | +## Démarrage rapide | |
| 191 | 224 | |
| 192 | 225 | ```bash |
| 193 | −git clone https://git.spboucher.ai/fabri-ka.git && cd fabri-ka | |
| 226 | +git clone https://git.spboucher.ai/fabri-ka.git && cd fabri-ka # (prod : ssh M4M64a && cd ~/fabri-ka) | |
| 194 | 227 | |
| 195 | 228 | # Backend |
| 196 | 229 | python3 -m venv .venv && .venv/bin/pip install -r requirements.txt |
| 197 | 230 | |
| 198 | −# Frontend | |
| 231 | +# Frontend (dev : npm run dev ; prod : build servi par FastAPI) | |
| 199 | 232 | cd frontend && npm install && npm run build && cd .. |
| 200 | 233 | |
| 201 | −# (optionnel) répertoires JS / sites anti-bot / SSO | |
| 202 | −cat > .env <<EOF | |
| 203 | −FIRECRAWL_API_KEY=fc-votre-cle | |
| 204 | −KA_SSO_SECRET=… # SSO KA ID (facultatif — le bouton n'apparaît pas sans) | |
| 205 | −KA_HUB_URL=https://www.groupe-ka.com | |
| 206 | −FABRIKA_BASE_URL=https://www.fabri-ka.com | |
| 207 | −EOF | |
| 208 | − | |
| 209 | 234 | # Ingestion puis service |
| 210 | 235 | .venv/bin/python run.py sync # toutes les boutiques connectables |
| 211 | −.venv/bin/python run.py serve 8090 # → http://localhost:8090 | |
| 236 | +.venv/bin/python run.py serve 8097 # → http://localhost:8097 | |
| 212 | 237 | .venv/bin/python run.py watch 360 # resynchronisation en boucle (minutes) |
| 238 | + | |
| 239 | +# Après un changement en prod | |
| 240 | +pm2 restart fabri-ka-web # (ou fabri-ka-sync selon le changement) | |
| 213 | 241 | ``` |
| 214 | 242 | |
| 243 | +## Variables d'environnement | |
| 244 | + | |
| 245 | +Noms seulement — les valeurs vivent dans le `.env` du nœud (jamais dans le repo) : | |
| 246 | + | |
| 247 | +| Variable | Rôle | | |
| 248 | +|---|---| | |
| 249 | +| `FABRIKA_BASE_URL` | URL publique du site (canonicals, sitemaps) | | |
| 250 | +| `FABRIKA_ADMIN_TOKEN` | jeton des opérations d'administration (`/api/sync`) | | |
| 251 | +| `KA_SSO_SECRET` · `KA_HUB_URL` · `SESSION_SECRET` | SSO KA ID (JWT HS256) et hub groupe-ka.com | | |
| 252 | +| `FIRECRAWL_API_KEY` | sessions Firecrawl (répertoires JS, découverte) | | |
| 253 | +| `SCRAPFLY_API_KEY` | secours anti-bot de certains connecteurs | | |
| 254 | + | |
| 255 | +## Données & conformité | |
| 256 | + | |
| 257 | +- **Provenance** : le catalogue provient des **endpoints publics des boutiques elles-mêmes** (Shopify `products.json`, WooCommerce Store API, GraphQL Wix, etc.) — pas d'annuaire tiers, aucune donnée derrière authentification. | |
| 258 | +- **Revue de conformité par source** : chaque source est évaluée AVANT connexion (robots.txt/CGU lus et datés, décision consignée) — voir [`docs/CONFORMITE.md`](docs/CONFORMITE.md) (dernière revue complète : 2026-08-19). | |
| 259 | +- **Politesse réseau** : throttle global par plateforme (Shopify : **0,7 s/req** toutes boutiques confondues), backoff 429, caches disque, User-Agent identifié. | |
| 260 | +- **Traçabilité** : chaque produit renvoie vers la boutique d'origine ; chaque boutique conserve sa provenance de découverte (`discovery_sources`) et son évidence d'origine (`origin_evidence`). | |
| 261 | +- **Cadence** : resynchronisation complète **aux 6 heures** (`run.py watch 360`) ; retraits avec délai de grâce (2 syncs). | |
| 262 | +- **Retrait sur demande** : tout ayant droit peut demander le retrait de ses données (contact ci-dessous). | |
| 263 | + | |
| 215 | 264 | ## Déploiement |
| 216 | 265 | |
| 217 | 266 | En production sur le **nœud M4M64a** du cluster **MacLustr** (répertoire `~/fabri-ka`), servi sur le **port 8097** et exposé via **ngrok** sur **[www.fabri-ka.com](https://www.fabri-ka.com)**. |
| 218 | 267 | |
| 219 | −**3 processus PM2 :** | |
| 268 | +**3 processus PM2 (vérifiés live) :** | |
| 220 | 269 | |
| 221 | 270 | ``` |
| 222 | 271 | fabri-ka-web .venv/bin/python run.py serve 8097 # API + frontend + SSR SEO |
@@ -233,6 +282,19 @@ La **source de vérité est le repo git sur le nœud M4M64a** (`~/fabri-ka`) — | ||
| 233 | 282 | - Remote `origin` = **spbgit** (git perso **[git.spboucher.ai](https://git.spboucher.ai)**), via l'alias SSH **`gitsrv`** : `gitsrv:srv/git/fabri-ka.git` — bare repo hébergé sur M3U96a. |
| 234 | 283 | - **Ne pas éditer de copies laptop** ; référence complète : `~/Desktop/cluster-skill/KA-REMOTE-DEV.md`. |
| 235 | 284 | |
| 285 | +## Historique | |
| 286 | + | |
| 287 | +Jalons réels du repo (`git log`, 95 commits) : | |
| 288 | + | |
| 289 | +| Jalon | Commit | | |
| 290 | +|---|---| | |
| 291 | +| Naissance — agrégateur de produits québécois | `4d4f1b5` | | |
| 292 | +| Expansion majeure : 149 500+ produits, 3 131 boutiques, 17/17 régions | `a4bbc59` | | |
| 293 | +| Stats v2 — dashboard ultra complet + 5 rapports PDF (kapdf v2) | `6112f03` | | |
| 294 | +| Qualité produits — listing_status, quarantaine, prix « sur devis », galeries enrichies | `1f5ecb8` | | |
| 295 | +| Connecteur Votresite.ca (plateforme QC) — 45 boutiques, +3 190 produits | `037494b` | | |
| 296 | +| Stats v3 — rapports PDF personnalisés (`ReportBuilder`) · gardiens ka6 sur la supervision des connecteurs | `1fbc242` · `db542b0` | | |
| 297 | + | |
| 236 | 298 | ## Principes |
| 237 | 299 | |
| 238 | 300 | 1. **Politesse** — throttle global par plateforme (Shopify : **0,7 s/req** toutes boutiques confondues), délais entre requêtes, User-Agent identifié. |
@@ -241,6 +303,24 @@ La **source de vérité est le repo git sur le nœud M4M64a** (`~/fabri-ka`) — | ||
| 241 | 303 | 4. **Robustesse** — une boutique qui casse n'affecte jamais les autres ; journal `sync_log` avec raison d'échec par boutique. |
| 242 | 304 | 5. **Trouvabilité** — tout ce qui existe dans la base existe pour Google : HTML complet, données structurées, sitemaps exhaustifs, jamais de soft-404. |
| 243 | 305 | |
| 306 | +## Écosystème Groupe KA | |
| 307 | + | |
| 308 | +| Plateforme | Univers | | |
| 309 | +|---|---| | |
| 310 | +| [groupe-ka.com](https://www.groupe-ka.com) | portail & KA ID | | |
| 311 | +| [lou-ka.com](https://www.lou-ka.com) | logements à louer | | |
| 312 | +| [immo-ka.com](https://www.immo-ka.com) | propriétés à vendre | | |
| 313 | +| [vrai-prix.com](https://www.vrai-prix.com) | estimation immobilière | | |
| 314 | +| [auto-ka.com](https://www.auto-ka.com) | véhicules | | |
| 315 | +| [fabri-ka.com](https://www.fabri-ka.com) | produits québécois | | |
| 316 | +| [food-ka.com](https://www.food-ka.com) | épicerie/alimentation | | |
| 317 | +| [resto-ka.com](https://www.resto-ka.com) | restaurants | | |
| 318 | +| [sorti-ka.com](https://www.sorti-ka.com) | sorties et événements | | |
| 319 | +| [job-ka.com](https://www.job-ka.com) | emplois | | |
| 320 | +| [crea-ka.com](https://www.crea-ka.com) | créateurs | | |
| 321 | +| [trouve-ka.com](https://www.trouve-ka.com) | petites annonces | | |
| 322 | +| [api-ka.com](https://www.api-ka.com) | API de données | | |
| 323 | + | |
| 244 | 324 | --- |
| 245 | 325 | |
| 246 | 326 | <div align="center"> |
| 247 | 327 | |