SPB Git

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%
9.0 KB · 187 lines markdown
Rendered Raw Blame History
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)**89![Python](https://img.shields.io/badge/Python-3.14-1E1B16?style=for-the-badge&logo=python&logoColor=C4532E)10![FastAPI](https://img.shields.io/badge/FastAPI-API-1E1B16?style=for-the-badge&logo=fastapi&logoColor=C4532E)11![React](https://img.shields.io/badge/React_18-Vite_+_TS-1E1B16?style=for-the-badge&logo=react&logoColor=C4532E)12![SQLite](https://img.shields.io/badge/SQLite-FTS5-1E1B16?style=for-the-badge&logo=sqlite&logoColor=C4532E)13![Firecrawl](https://img.shields.io/badge/Firecrawl-rendu_JS-1E1B16?style=for-the-badge&logoColor=C4532E)1415![Produits](https://img.shields.io/badge/produits_agr%C3%A9g%C3%A9s-281_000%2B-234438?style=flat-square)16![Boutiques connectées](https://img.shields.io/badge/boutiques_avec_produits-1_204-234438?style=flat-square)17![Registre](https://img.shields.io/badge/boutiques_QC_v%C3%A9rifi%C3%A9es-3_224-234438?style=flat-square)18![Connecteurs](https://img.shields.io/badge/connecteurs_plateforme-6-234438?style=flat-square)19![Régions](https://img.shields.io/badge/r%C3%A9gions_couvertes-17%2F17-234438?style=flat-square)20![Sources](https://img.shields.io/badge/sources_de_d%C3%A9couverte-35%2B-234438?style=flat-square)2122*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| ![Accueil](docs/screenshots/accueil.png) | ![Catalogue](docs/screenshots/catalogue.png) | ![Boutiques](docs/screenshots/boutiques.png) |3536| Page boutique (landing) | Statistiques |37|---|---|38| ![Boutique](docs/screenshots/boutique-medusa.png) | ![Stats](docs/screenshots/stats.png) |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=&region=&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[![Email](https://img.shields.io/badge/contact@spboucher.ai-1E1B16?style=for-the-badge&logo=minutemailer&logoColor=C4532E)](mailto:contact@spboucher.ai)179[![Git](https://img.shields.io/badge/git.spboucher.ai-1E1B16?style=for-the-badge&logo=git&logoColor=C4532E)](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