spb/fabri-ka Public
Agrégateur de produits québécois — www.fabri-ka.com
HTML 57.9%
Python 18.6%
TypeScript 15.6%
CSS 7.8%
1<div align="center">23# Fabri·Ka45### Tous les produits québécois. Un seul endroit.67**[www.fabri-ka.com](https://www.fabri-ka.com)**8910111213141516171819202122*Agrégateur de découverte des produits vendus en ligne par les entreprises du Québec —23chaque produit renvoie vers la boutique d'origine. Aucune vente sur Fabri-Ka :24les prix, photos et stocks appartiennent aux marchands sources.*2526</div>2728---2930## Aperçu3132| Accueil | Catalogue | Boutiques |33|---|---|---|34|  |  |  |3536| Page boutique (landing) | Statistiques |37|---|---|38|  |  |3940<p align="center"><img src="docs/screenshots/mobile.png" width="260" alt="Version mobile"/></p>41<p align="center"><i>Mobile-first : barre d'onglets, filtres en bottom sheet, galeries swipe, pages boutiques avec logo/couverture, page statistiques.</i></p>4243## Pourquoi Fabri-Ka ?4445Acheter québécois demande de connaître des centaines de boutiques dispersées —46érablières, microbrasseries, savonneries, ébénistes, torréfacteurs, fermes…47**Fabri-Ka retourne le problème** : un pipeline de découverte recense les boutiques48en ligne du Québec, des connecteurs par *plateforme* aspirent leurs catalogues49publics complets, et un moteur de recherche unique les rend trouvables — filtrés50par catégorie, région et origine de fabrication (classes A–E).5152> Contrairement à un agrégateur classique (1 connecteur / site), Fabri-Ka utilise53> **1 connecteur / plateforme ecommerce** : le même code Shopify sert des centaines54> de boutiques, piloté par le registre `data/stores.json` produit par la recherche.5556## L'architecture en 30 secondes5758```mermaid59flowchart LR60 subgraph Discovery["Pipeline de découverte (scripts/)"]61 A["30+ annuaires sources<br/>certifications · associations ·<br/>marques régionales · balayages"] --> B["harvest → aggregate →<br/>verify → classify A–E"]62 B --> R[("stores.json<br/>3 131 boutiques QC")]63 end64 subgraph FabriKa["Plateforme (fabrika/)"]65 R --> C["Connecteurs plateforme<br/>Shopify · WooCommerce · Wix ·<br/>Squarespace · Scrapfly/Firecrawl"]66 C --> D[("SQLite + FTS5<br/>hash + diff")]67 D --> E["API FastAPI<br/>/api/products · /api/facets"]68 E --> F["React 18 + Vite<br/>recherche · filtres · fiches"]69 end70 W["⏱ Watcher 6 h (PM2)"] -.-> C71 F --> U["🍁 Acheteur local"]72```7374| Couche | Rôle | Fichiers |75|---|---|---|76| **Découverte** | Sitemaps d'annuaires, API cachées de cartes (wpgmza, FacetWP), pagination htmx, résolution de redirections affiliées, sessions Firecrawl pour répertoires JS (CMAQ) | `scripts/harvest.py`, `scripts/cmaq_firecrawl.py` |77| **Vérification** | Plateforme ecommerce + test réel de l'endpoint catalogue + signaux de localisation QC (codes postaux, indicatifs, TLD, wording) | `scripts/verify.py` |78| **Classification** | Origine A–E avec évidence conservée (certifications → a priori ; wording du site → ajustement) | `scripts/build_registry.py` |79| **Connecteurs** | Shopify `products.json` (transport curl anti-429 TLS), WooCommerce Store API, Wix Stores GraphQL (jeton public), Squarespace `?format=json`, Firecrawl en secours | `fabrika/connectors/` |80| **Diff engine** | Upsert par hash de contenu, retraits avec délai de grâce (2 syncs) | `fabrika/db.py` |81| **API** | Recherche FTS5 accent-insensible, facettes, filtres catégorie/région/origine/prix, stats, sync | `fabrika/web.py` |82| **Frontend** | « Chaleur artisanale, précision éditoriale » — Fraunces + Outfit, crème/terracotta/pin, PWA-lite, fr-CA | `frontend/` |8384## Chiffres (2026-08-12)8586| Mesure | Valeur |87|---|---|88| Domaines candidats découverts et dédupliqués | 3 481 |89| Boutiques québécoises actives vérifiées | **3 131** |90| — avec ecommerce détecté | 1 970 |91| — connectables par un connecteur plateforme | 1 369 |92| Produits agrégés (catalogues complets) | **281 000+** |93| Boutiques avec produits en ligne | 1 204 |94| Régions administratives couvertes | **17 / 17** |95| Classes d'origine | A : 3 062 · C : 19 · E : 50 |9697Détails, méthodologie, taux de découverte marginal et angles morts :98[`deliverables/research_report.md`](deliverables/research_report.md) ·99stratégie de découverte continue : [`deliverables/discovery_strategy.md`](deliverables/discovery_strategy.md).100101## Démarrage rapide102103```bash104git clone https://git.spboucher.ai/fabri-ka.git && cd fabri-ka105106# Backend107python3 -m venv .venv && .venv/bin/pip install -r requirements.txt108109# Frontend110cd frontend && npm install && npm run build && cd ..111112# (optionnel) répertoires JS / sites anti-bot113echo "FIRECRAWL_API_KEY=fc-votre-cle" > .env114115# Ingestion puis service116.venv/bin/python run.py sync # toutes les boutiques connectables117.venv/bin/python run.py serve 8090 # → http://localhost:8090118.venv/bin/python run.py watch 360 # resynchronisation en boucle (minutes)119```120121## API122123| Endpoint | Description |124|---|---|125| `GET /api/products?q=&category=®ion=&origin=&price_min=&price_max=&sort=&page=` | Recherche plein-texte + filtres, triée |126| `GET /api/products/{uid}` | Fiche produit (galerie, boutique, produits liés) |127| `GET /api/stores?region=&q=&with_products=` | Répertoire des boutiques (logo, région, plateforme) |128| `GET /api/stores/{id}` | Fiche boutique enrichie : logo, couverture, stats de prix, catégories, boutiques similaires |129| `GET /api/facets` | Catégories/régions/origines avec compteurs |130| `GET /api/stats` | Totaux, ventilation régionale, journal de sync |131| `GET /api/stats/extended` | Statistiques riches : prix (médian/moyen/histogramme), catégories, régions, plateformes, croissance, top boutiques |132| `GET /api/report.pdf` | Rapport de marché PDF (couverture de marque, KPIs, graphiques, tableaux) — généré à la volée |133| `POST /api/sync` | Déclenche une synchronisation en arrière-plan |134135## Classification d'origine136137| Classe | Signification |138|---|---|139| **A** | Fabriqué / cultivé / transformé au Québec |140| **B** | Conçu au Québec, fabriqué ailleurs |141| **C** | Détaillant québécois (revente) |142| **D** | Mixte |143| **E** | Incertain — à vérifier |144145Chaque classe est justifiée par une **évidence conservée** (certification Aliments146du Québec / Les Produits du Québec, adhésion à une association de producteurs,147wording du site) — jamais déduite du seul fait qu'une entreprise « semble » québécoise.148149## Production150151Déployé sous **PM2** (3 processus) derrière **ngrok** sur le nœud M4M64a :152153```154fabri-ka-web .venv/bin/python run.py serve 8097 # API + frontend155fabri-ka-sync .venv/bin/python run.py watch 360 # resync aux 6 h156fabri-ka-ngrok ngrok http --url=www.fabri-ka.com 8097 # tunnel157```158159## Principes1601611. **Politesse** — throttle global par plateforme (Shopify : 0,7 s/req toutes162 boutiques confondues), délais entre requêtes, User-Agent identifié.1632. **Fidélité** — aucun prix inventé ; entités HTML décodées ; si la source ne164 publie pas une donnée, elle est `null`.1653. **Traçabilité** — chaque produit renvoie vers la boutique d'origine ; chaque166 boutique conserve sa provenance de découverte et son évidence d'origine.1674. **Robustesse** — une boutique qui casse n'affecte jamais les autres ;168 journal `sync_log` avec raison d'échec par boutique.169170---171172<div align="center">173174## Auteur175176**Simon-Pierre Boucher**177178[](mailto:contact@spboucher.ai)179[](https://git.spboucher.ai)180181*Conçu, construit et déployé en une journée — du recensement provincial182(3 131 boutiques vérifiées, 35+ sources) au moteur de recherche en production.*183184© 2026 Simon-Pierre Boucher — tous droits réservés.185186</div>187