docs: refonte du README (pastilles + captures d écran à jour)
3 changed files +91 −99
modified
README.md
+91 −99
@@ -6,129 +6,121 @@ | ||
| 6 | 6 | |
| 7 | 7 | # Sorti·Ka |
| 8 | 8 | |
| 9 | −### **Toutes les sorties et tous les événements du Québec. Un seul endroit.** | |
| 9 | +**Toutes les sorties et tous les événements du Québec — concerts, festivals, spectacles, expos, sport, famille — au même endroit.** | |
| 10 | 10 | |
| 11 | −**[www.sorti-ka.com](https://www.sorti-ka.com)** | |
| 11 | +[](https://www.sorti-ka.com) | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 12 | 19 | |
| 13 | − | |
| 20 | +**Sorti·Ka** est un **agrégateur indépendant de sorties et d'événements** couvrant les **17 régions administratives du Québec** : plus de **18 000 événements actifs** dans **~330 villes**, avec dates, lieux, gratuité (plus de 3 600 événements gratuits à venir), fiche par événement et **lien direct vers la billetterie ou la source originale**. Mise à jour **horaire**, automatiquement. | |
| 14 | 21 | |
| 15 | −--- | |
| 16 | − | |
| 17 | −## Description | |
| 22 | +Trouver quoi faire au Québec, c'est normalement ouvrir dix sites : les billetteries ne montrent que leurs propres spectacles, les calendriers municipaux que leur ville, les sites touristiques que leurs membres. Sorti·Ka retourne le problème : un **connecteur dédié par source** (une trentaine de connecteurs actifs, 44 sources au registre) visite chaque calendrier, normalise chaque événement vers un **schéma unique**, **déduplique les doublons inter-sources** et détecte les changements en continu. Sorti·Ka **n'est pas une billetterie** : c'est un **index fidèle** — aucun prix inventé, aucune date devinée, chaque fiche est attribuée à sa source. Pour qui ? Quiconque cherche quoi faire, ce soir ou cet été, n'importe où au Québec. | |
| 18 | 23 | |
| 19 | −**Sorti·Ka** est un **agrégateur indépendant de sorties et d'événements** — concerts, festivals, spectacles, expositions, sport, famille — couvrant les **17 régions administratives du Québec**, avec dates, lieux, gratuité, fiche par événement et **lien direct vers la billetterie ou la source originale**. Mise à jour **horaire**, automatiquement. | |
| 24 | +## Captures d'écran | |
| 20 | 25 | |
| 21 | −Trouver quoi faire au Québec, c'est ouvrir dix sites : les billetteries ne montrent que leurs propres spectacles, les calendriers municipaux que leur ville, les sites touristiques que leurs membres. **Sorti·Ka retourne le problème** : un **connecteur dédié par source** visite chaque calendrier, normalise chaque événement vers un **schéma unique**, **déduplique les doublons inter-sources** et détecte les changements en continu. | |
| 22 | − | |
| 23 | −Sorti·Ka **n'est pas une billetterie** : c'est un **index fidèle**. Aucun prix inventé, aucune date devinée — chaque fiche est **attribuée à sa source** et renvoie vers la fiche originale pour les billets. Membre de la famille **·Ka** ([Lou·Ka](https://www.lou-ka.com), Immo·Ka, Auto·Ka, Food·Ka, Fabri·Ka, Resto·Ka…), architecture calquée sur le **patron de référence Lou·Ka**. | |
| 26 | +<p align="center"> | |
| 27 | + <img src="docs/screenshots/sorti-ka-desktop.png" width="640" alt="Accueil — desktop"> | |
| 28 | + <img src="docs/screenshots/sorti-ka-mobile.png" width="200" alt="Accueil — mobile"> | |
| 29 | +</p> | |
| 24 | 30 | |
| 25 | 31 | ## Fonctionnalités |
| 26 | 32 | |
| 27 | −- **Recherche filtrée** — région, catégorie, période, **gratuité**, texte libre, tri et pagination | |
| 28 | −- **Fiche par événement** — dates, lieu, prix, carte, événements similaires, **SSR + JSON-LD Event** pour le SEO | |
| 29 | −- **8 connecteurs actifs** — **~15 000+ événements actifs**, **428 villes**, **17/17 régions** : | |
| 30 | − | |
| 31 | −| Source | Type / accès | Extraction | | |
| 32 | −|---|---|---| | |
| 33 | −| **Le point de vente** | billetterie QC — robots `Allow: *` | listes HTML paginées (~2 500 événements, toute la province) | | |
| 34 | −| **SIT Québec** (Ministère du Tourisme) | données ouvertes CC 4.0 | API JSON Tourinsoft (~1 600 événements, toutes les régions) | | |
| 35 | −| **Ville de Montréal** | données ouvertes CC BY 4.0 | API CKAN datastore (~5 600 événements) | | |
| 36 | −| **evenko** | promoteur — robots `Allow: /api/search*` | proxy Algolia (~460 grands concerts : Centre Bell, MTELUS…) | | |
| 37 | −| **La Vitrine** | Content-Signal `search=yes` | sitemap + fiches HTML, cache incrémental (~5 100 représentations) | | |
| 38 | −| **Atuvu.ca** | Cloudflare → **Scrapfly** | sitemaps lastmod + fiches, rattrapage progressif | | |
| 39 | −| **Ville de Sherbrooke** | calendrier municipal public | JSON embarqué — 1 requête (~270 événements, heures locales) | | |
| 40 | −| **Ville de Laval** | données ouvertes CC 4.0 | JSON officiel (~290 activités, heures locales) | | |
| 41 | −| **Ville de Brossard** | API REST WordPress publique | `/wp-json/wp/v2/city-event` + fiches (bannière ou JSON-LD, ~400 événements) | | |
| 42 | −| **Bandsintown** | API publique par artiste | dates QC des artistes connus de la base (rotation 100 artistes/sync) | | |
| 43 | −| **Ticketmaster** | Discovery API officielle | **prêt — clé requise** (`TICKETMASTER_API_KEY`, gratuite) | | |
| 44 | − | |
| 45 | −- **Déduplication inter-sources** — empreinte titre + ville + date : un même concert publié par 3 sources = **une seule carte**, la fiche la plus riche gagne | |
| 46 | −- **Répertoire des municipalités MAMH** — **1 250 villes** + arrondissements + alias, homonymes résolus par population | |
| 47 | −- **Persistance robuste** — upsert par hash de contenu, **délai de grâce 2 syncs**, alerte de dérive, historique de syncs | |
| 48 | −- **Page /stats** — tableau de bord analytique + **rapport PDF Groupe-KA** | |
| 49 | −- **Widget KA Agent** — bulle de chat Groupe KA intégrée au frontend | |
| 50 | −- **Heure précise (`start_time`) et artistes (`artists`)** — captés quand la source les publie (billetteries, calendriers municipaux), jamais inventés | |
| 51 | −- **32 tests** sur fixtures réelles, **zéro réseau** | |
| 52 | − | |
| 53 | −## Stack technique | |
| 54 | − | |
| 55 | −- **Python 3.14** + **FastAPI** — API JSON + rendu SSR SEO | |
| 56 | −- **SQLite** — stockage, diff et historique de synchronisation | |
| 57 | −- **Frontend SPA sans build** — HTML/JS, routeur History API, design system **Groupe KA « éditorial sharp »** (ka-ui) | |
| 58 | −- **PM2** + **ngrok** — exécution résiliente et exposition publique | |
| 59 | −- **Scrapfly** — contournement Cloudflare pour Atuvu (clé `SCRAPFLY_API_KEY` dans `.env`) | |
| 60 | − | |
| 61 | −## Structure du projet | |
| 33 | +- **Recherche filtrée** — région, ville, catégorie (14 catégories canoniques), période, **gratuité**, texte libre, tri et pagination (`GET /api/events`). | |
| 34 | +- **Fiche par événement** — dates, heure locale, artistes, lieu, prix (avec `price_label` original), carte, événements similaires ; **SSR + JSON-LD Event** (`/evenement/{uid}`) pour le SEO, sitemaps et robots.txt. | |
| 35 | +- **~30 connecteurs actifs** : billetteries (Le point de vente, evenko/Algolia, Ticketpro, Ticket Accès, Tuxedo Billet, Ovation, Eventbrite), données ouvertes officielles (SIT Québec/Tourinsoft, Ville de Montréal CKAN, Laval, Sherbrooke, Brossard, Longueuil), diffuseurs et salles (La Vitrine, Place des Arts, salles via JSON-LD), portails régionaux (Montérégie, Outaouais, Lanaudière, Cantons-de-l'Est, Chaudière-Appalaches, Bas-Saint-Laurent, Gaspésie, Centre-du-Québec, Saguenay…), Atuvu.ca (via Scrapfly), Bandsintown, LHJMQ, Québec animée — Ticketmaster prêt (clé `TICKETMASTER_API_KEY` requise). | |
| 36 | +- **Déduplication inter-sources** — empreinte titre + ville + date : un même concert publié par 3 sources = une seule carte, la fiche la plus riche gagne. | |
| 37 | +- **Répertoire des municipalités MAMH** — 1 250 villes + arrondissements + alias, homonymes résolus par population ; rattachement automatique aux 17 régions. | |
| 38 | +- **Persistance robuste** — upsert par hash de contenu, délai de grâce de 2 syncs avant retrait, alerte de dérive quand une source casse, historique des synchronisations. | |
| 39 | +- **Page /stats** — tableau de bord analytique + **rapports PDF Groupe-KA** (kit kacharts/kapdf v3, rapports personnalisés). | |
| 40 | +- **Widget KA Agent** + **favoris « Mon univers Ka »** (KA ID, hub groupe-ka.com). | |
| 41 | +- **Tests sur fixtures réelles, zéro réseau** (pytest). | |
| 42 | + | |
| 43 | +## Architecture | |
| 62 | 44 | |
| 63 | 45 | ``` |
| 64 | − connecteurs (1 module / source) normalisation (Event) SQLite (diff + grâce) | |
| 65 | − sortika/connectors/*.py → schema.py + normalize.py → db.py | |
| 66 | − ▲ auto-découverts + regions.py (MAMH) │ | |
| 67 | − │ ▼ | |
| 68 | − watcher horaire (PM2) frontend SPA + fiches ← API FastAPI + SSR SEO | |
| 69 | − ingest.py watch frontend/index.html web.py + seo.py | |
| 46 | +connecteurs (1 module / source) normalisation (Event) SQLite (diff + grâce) | |
| 47 | +sortika/connectors/*.py → schema.py + normalize.py → db.py | |
| 48 | + ▲ auto-découverts + regions.py (MAMH) │ | |
| 49 | + │ ▼ | |
| 50 | +watcher horaire (PM2) frontend SPA + fiches ← API FastAPI + SSR SEO | |
| 51 | +run.py watch frontend/index.html web.py + seo.py | |
| 70 | 52 | ``` |
| 71 | 53 | |
| 72 | −| Couche | Rôle | Fichiers | | |
| 73 | −|---|---|---| | |
| 74 | −| **Connecteurs** | 1 module Python par source : API JSON internes (Algolia evenko, Tourinsoft, CKAN), listes HTML, Scrapfly, caches incrémentaux | `sortika/connectors/*.py` | | |
| 75 | −| **Schéma** | `Event` standardisé : titre, catégories canoniques, lieu, ville, **région (17)**, lat/lng, dates ISO + **heure locale**, **artistes**, gratuité/prix avec `price_label` source | `sortika/schema.py` | | |
| 76 | −| **Normalisation** | dates FR/ISO, prix, **14 catégories**, villes, entités HTML | `sortika/normalize.py` | | |
| 77 | −| **Régions** | Répertoire MAMH : 1 250 villes + arrondissements + alias | `sortika/regions.py` + `data/villes_regions.json` | | |
| 78 | −| **Persistance** | upsert par hash, délai de grâce, alerte de dérive | `sortika/db.py` | | |
| 79 | −| **Dédup** | empreinte titre + ville + date | `schema.dedup_key()` + `web.py` | | |
| 80 | −| **API + SSR** | recherche/filtres JSON, fiches `/evenement/{uid}` avec `<head>` unique + **JSON-LD Event**, robots, sitemaps | `sortika/web.py` + `sortika/seo.py` | | |
| 81 | −| **Frontend** | SPA sans build, design system **Groupe KA** | `frontend/index.html` | | |
| 54 | +- **Backend** : Python 3.14 + **FastAPI** (uvicorn) — API JSON, SSR SEO des fiches, stats, PDF (fpdf2), SSO/favoris KA ID (`auth.py`, `hubfav.py`). | |
| 55 | +- **Base de données** : **SQLite** — événements, diff par hash, délai de grâce, historique de syncs, géocodage (`geocode.py`, `venues.py`). | |
| 56 | +- **Frontend** : SPA **sans build** (HTML/JS, routeur History API), design system Groupe KA « éditorial sharp » (ka-ui), widget KA Agent. | |
| 57 | +- **Anti-bot** : **Scrapfly** pour Atuvu (clé `SCRAPFLY_API_KEY` dans `.env`). | |
| 58 | +- **Processus PM2** : | |
| 59 | + - **`sorti-ka-web`** — uvicorn sur le port **8120** (API + frontend + SSR) ; | |
| 60 | + - **`sorti-ka-sync`** — watcher **horaire** (`run.py watch`) : ingestion continue des sources ; | |
| 61 | + - **`sorti-ka-ngrok`** — tunnel ngrok vers www.sorti-ka.com. | |
| 82 | 62 | |
| 83 | −### API | |
| 63 | +## Structure du repo | |
| 84 | 64 | |
| 85 | −| Route | Description | | |
| 65 | +| Répertoire / fichier | Rôle | | |
| 86 | 66 | |---|---| |
| 87 | −| `GET /api/events` | recherche — `q`, `region`, `city`, `category`, `free`, `from`, `to`, `sort`, pagination ; **dédupliquée inter-sources** | | |
| 88 | −| `GET /api/events/{uid}` | fiche complète d'un événement | | |
| 89 | −| `GET /api/stats` | volumes par région et par catégorie | | |
| 90 | −| `GET /api/sources` | registre des sources + événements actifs + dernière synchro | | |
| 91 | −| `GET /evenement/{uid}` | fiche HTML SSR (title/og/canonical + **JSON-LD Event**) | | |
| 92 | −| `GET /sitemap.xml` · `/robots.txt` | référencement | | |
| 93 | −| `GET /docs` | Swagger | | |
| 67 | +| `sortika/` | paquet Python : connecteurs, schéma `Event`, normalisation, régions MAMH, DB, web/SSR, stats, PDF, auth KA ID | | |
| 68 | +| `sortika/connectors/` | un module par source (auto-découverts), base commune + `_resilient.py` | | |
| 69 | +| `frontend/` | SPA sans build (`index.html`, `ka-agent.js`, assets) | | |
| 70 | +| `data/` | base SQLite + `villes_regions.json` (répertoire MAMH) — non versionnés pour la BD | | |
| 71 | +| `tests/` | pytest sur fixtures réelles, zéro réseau | | |
| 72 | +| `scripts/` | utilitaires (génération de docs, maintenance) | | |
| 73 | +| `docs/` | `CONFORMITE.md`, fiches `connecteurs/`, captures d'écran | | |
| 74 | +| `apify/` | acteurs/outils d'appoint pour l'ingestion | | |
| 75 | +| `run.py` | point d'entrée CLI : `sync` · `web` · `watch` | | |
| 76 | +| `requirements.txt` | fastapi, uvicorn, requests, fpdf2, pytest | | |
| 94 | 77 | |
| 95 | −## Démarrage local | |
| 78 | +## Développement (remote-first) | |
| 79 | + | |
| 80 | +⚠️ **La source de vérité est le repo git sur le nœud M3U96a** (`~/apps/sorti-ka`) — on n'édite **jamais** les copies laptop. Toute modification se fait sur le nœud via SSH : édition, tests, redémarrage PM2, puis commit + push **depuis le nœud**. | |
| 81 | + | |
| 82 | +- Remote **`origin` = spbgit** (git perso, https://git.spboucher.ai) — sur M3U96a, l'origin est le chemin local **`/Users/simon-pierreboucher/srv/git/sorti-ka.git`** (bare repo). | |
| 96 | 83 | |
| 97 | 84 | ```bash |
| 98 | −python3 -m venv .venv && .venv/bin/pip install -r requirements.txt | |
| 99 | −.venv/bin/python -m pytest tests/ -q # 32 tests (fixtures réelles, zéro réseau) | |
| 100 | −.venv/bin/python run.py sync # ingestion des 10 sources actives | |
| 85 | +ssh M3U96a | |
| 86 | +cd ~/apps/sorti-ka | |
| 87 | +python3 -m venv .venv && .venv/bin/pip install -r requirements.txt # au besoin | |
| 88 | +.venv/bin/python -m pytest tests/ -q # tests (fixtures réelles, zéro réseau) | |
| 89 | +.venv/bin/python run.py sync # ingestion des sources | |
| 101 | 90 | .venv/bin/python run.py web --port 8120 # API + frontend + SSR |
| 102 | −.venv/bin/python run.py watch --interval 3600 # boucle d'ingestion horaire | |
| 91 | +pm2 restart sorti-ka-web # après changement | |
| 92 | +git add <fichiers> && git commit -m "…" && git push origin main | |
| 103 | 93 | ``` |
| 104 | 94 | |
| 105 | −**Secrets** (gabarit : `.env.example`) : `SCRAPFLY_API_KEY` (connecteur Atuvu) ; `TICKETMASTER_API_KEY` (active le connecteur Ticketmaster, clé gratuite). | |
| 95 | +Secrets (gabarit `.env.example`) : `SCRAPFLY_API_KEY` (Atuvu), `TICKETMASTER_API_KEY` (active le connecteur Ticketmaster). | |
| 106 | 96 | |
| 107 | 97 | ## Déploiement |
| 108 | 98 | |
| 109 | −- **Nœud** : **M3U96a** (MacLustr) — répertoire `~/apps/sorti-ka` | |
| 110 | −- **Port** : **8120** | |
| 111 | −- **Domaine** : **[www.sorti-ka.com](https://www.sorti-ka.com)** (tunnel ngrok) | |
| 112 | −- **PM2** (3 processus) : | |
| 113 | − - **`sorti-ka-web`** — uvicorn sur le port **8120** (API + frontend + SSR) | |
| 114 | − - **`sorti-ka-sync`** — watcher **horaire** (mise à jour continue des 10 sources actives) | |
| 115 | − - **`sorti-ka-ngrok`** — tunnel vers **www.sorti-ka.com** | |
| 116 | −- **Registre** : `~/Desktop/cluster-skill/cluster-deployments.json` | |
| 117 | − | |
| 118 | −## Développement remote-first (IMPORTANT) | |
| 119 | − | |
| 120 | −La **source de vérité est le repo git sur le nœud M3U96a** (`~/apps/sorti-ka`), **PAS une copie laptop**. Toute modification se fait **sur le nœud via SSH** : édition, tests, `pm2 restart`, puis commit/push **depuis le nœud**. | |
| 121 | − | |
| 122 | −- **`origin` = spbgit** (git perso, git.spboucher.ai) — sur **M3U96a**, le remote est le **chemin local** `/Users/simon-pierreboucher/srv/git/sorti-ka.git` (les bare repos vivent sur ce même nœud). | |
| 123 | −- Référence complète : `~/Desktop/cluster-skill/KA-REMOTE-DEV.md`. | |
| 124 | − | |
| 125 | −## Principes | |
| 126 | − | |
| 127 | −1. **Index fidèle** — rien d'inventé : prix et dates viennent de la source, avec `price_label` original conservé et **attribution systématique**. | |
| 128 | −2. **Sources légitimes d'abord** — données ouvertes officielles et sites au robots.txt permissif ; CGU/licences consignées en tête de chaque connecteur. | |
| 129 | −3. **Travail de moine** — un connecteur robuste à la fois, testé sur fixtures réelles, avec **alerte de dérive** quand une source casse. | |
| 130 | −4. **Cohérence ·Ka** — architecture Lou·Ka, design system **Groupe KA**. | |
| 99 | +| | | | |
| 100 | +|---|---| | |
| 101 | +| **Nœud** | **M3U96a** (cluster MacLustr) — `~/apps/sorti-ka` | | |
| 102 | +| **Port** | **8120** | | |
| 103 | +| **Processus PM2** | `sorti-ka-web` (uvicorn) + `sorti-ka-sync` (watcher horaire) + `sorti-ka-ngrok` (tunnel) | | |
| 104 | +| **Domaine** | [www.sorti-ka.com](https://www.sorti-ka.com) via tunnel ngrok | | |
| 105 | + | |
| 106 | +## Écosystème Groupe KA | |
| 107 | + | |
| 108 | +- [groupe-ka.com](https://www.groupe-ka.com) — portail | |
| 109 | +- [lou-ka.com](https://www.lou-ka.com) — logements à louer | |
| 110 | +- [immo-ka.com](https://www.immo-ka.com) — propriétés à vendre | |
| 111 | +- [vrai-prix.com](https://www.vrai-prix.com) — estimation immobilière | |
| 112 | +- [auto-ka.com](https://www.auto-ka.com) — véhicules | |
| 113 | +- [fabri-ka.com](https://www.fabri-ka.com) — produits québécois | |
| 114 | +- [food-ka.com](https://www.food-ka.com) — épicerie / alimentation | |
| 115 | +- [resto-ka.com](https://www.resto-ka.com) — restaurants | |
| 116 | +- [sorti-ka.com](https://www.sorti-ka.com) — sorties et événements | |
| 117 | +- [job-ka.com](https://www.job-ka.com) — emplois | |
| 118 | +- [crea-ka.com](https://www.crea-ka.com) — créateurs | |
| 119 | +- [trouve-ka.com](https://www.trouve-ka.com) — petites annonces | |
| 120 | +- [api-ka.com](https://www.api-ka.com) — API de données | |
| 131 | 121 | |
| 132 | 122 | --- |
| 133 | 123 | |
| 134 | −Un service **Groupe Ka** — © 2026 Sorti·Ka — Simon-Pierre Boucher \<contact@spboucher.ai\> | |
| 124 | +© Groupe KA — Simon-Pierre Boucher · [contact@spboucher.ai](mailto:contact@spboucher.ai) | |
| 125 | + | |
| 126 | +*Ce dépôt vit sur **spbgit** (git perso — https://git.spboucher.ai).* | |
added
docs/screenshots/sorti-ka-desktop.png
+0 −0
Binary file not shown.
added
docs/screenshots/sorti-ka-mobile.png
+0 −0
Binary file not shown.