docs: README à jour avec screenshot
2 changed files +113 −134
modified
README.md
+113 −134
@@ -1,105 +1,108 @@ | ||
| 1 | 1 | # Trouve-KA — Cherche le Québec. |
| 2 | 2 | |
| 3 | +**Moteur de recherche web indépendant, Québec-first** — son propre crawler, son propre index, son propre ranking, son API et son application web publique. | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 3 | 7 |  |
| 4 | 8 |  |
| 5 | − | |
| 6 | − | |
| 7 | − | |
| 8 | 9 |  |
| 9 | 10 |  |
| 10 | 11 |  |
| 11 | 12 |  |
| 12 | 13 |  |
| 13 | − | |
| 14 | 14 |  |
| 15 | 15 | |
| 16 | −**Moteur de recherche web indépendant, Québec-first.** Son propre crawler, son propre | |
| 17 | −index, son propre ranking, son API et son application web publique. Pas un métamoteur : | |
| 18 | −aucune dépendance à Google, Bing ou Brave pour les résultats. | |
| 16 | +--- | |
| 17 | + | |
| 18 | +## Description | |
| 19 | + | |
| 20 | +**Trouve-KA** est un **moteur de recherche québécois indépendant**. Ce n'est **pas un métamoteur** : **aucune dépendance à Google, Bing ou Brave** pour les résultats. Le crawler découvre le web québécois à partir de **seeds à forte autorité** (gouvernement, municipalités, universités, médias), suit les liens sortants, juge la **pertinence québécoise** de chaque page (`page_quebec_score` **et** `domain_quebec_score`) et indexe **immédiatement** : une page fetchée est **cherchable en ~2–4 secondes**, pendant que le frontier continue de grandir. L'enrichissement (autorité, entités, embeddings) arrive après, **en asynchrone**, sans jamais bloquer. | |
| 19 | 21 | |
| 20 | 22 | > **Crawl en continu. Indexe immédiatement. Recherche immédiatement. Améliore en asynchrone.** |
| 21 | 23 | |
| 22 | −En production : **https://www.trouve-ka.com** — un moteur de recherche par | |
| 23 | −[Groupe KA](https://www.groupe-ka.com). | |
| 24 | +En production : **https://www.trouve-ka.com** — un moteur de recherche par [**Groupe KA**](https://www.groupe-ka.com). | |
| 24 | 25 | |
| 25 | −Author: Simon-Pierre Boucher — Contact: contact@spboucher.ai | |
| 26 | +``` | |
| 27 | +Crawler → Frontier → Fetcher → Parser → Classification Québec | |
| 28 | +→ Déduplication → Indexer → Index → Ranking → API → Web App | |
| 29 | +``` | |
| 26 | 30 | |
| 27 | −--- | |
| 31 | +Détails : [docs/architecture.md](docs/architecture.md) (diagrammes Mermaid) et [docs/decisions.md](docs/decisions.md) (pourquoi OpenSearch, pourquoi Postgres comme frontier, etc.). | |
| 28 | 32 | |
| 29 | −## Aperçu | |
| 33 | +**Auteur** : Simon-Pierre Boucher — **Contact** : contact@spboucher.ai | |
| 30 | 34 | |
| 31 | −| | | | |
| 32 | −|---|---| | |
| 33 | −|  |  | | |
| 34 | −| **Accueil** — la boîte de recherche, le compteur vivant, le flux « KA bot scrappe en ce moment » au footer | **Résultats** — pastilles éditoriales (◆ gradué selon le score Québec), vignettes og:image, snippets surlignés, 21 ms | | |
| 35 | −|  |  | | |
| 36 | −| **Onglet Images** — galerie des pages avec image représentative (hotlink + attribution, jamais de crawl d'images) | **/status** — métriques publiques réelles, auto-refresh 10 s | | |
| 35 | +--- | |
| 37 | 36 | |
| 38 | −## Métriques réelles (2026-08-13, jour 1 — ~6 h après le premier crawl) | |
| 37 | +## Fonctionnalités | |
| 39 | 38 | |
| 40 | −| Métrique | Valeur | | |
| 41 | −|---|---| | |
| 42 | −| Pages indexées et cherchables | **59 073** (+~35 000/heure) | | |
| 43 | −| Domaines québécois découverts | **7 898** (à partir de 64 seeds) | | |
| 44 | −| URLs découvertes en attente (frontier) | **433 999** | | |
| 45 | −| Pages fetchées / heure | **76 198** | | |
| 46 | −| Latence de recherche (mesurée en prod) | **20–95 ms** (cible p50 < 100 ms ✓) | | |
| 47 | −| Délai fetch → cherchable | **~2–4 secondes** | | |
| 48 | −| Nodes de crawl | **3** (M2M32 ×5 workers Docker, M2M32b, M2M32c) | | |
| 49 | −| Taille de l'index | ~14 Ko/document (791 Mo à 55 k docs) | | |
| 50 | −| Tests unitaires | 57 ✓ (canonicalisation, SSRF, robots, scoring Québec, pièges, fetcher, ranking) | | |
| 51 | − | |
| 52 | −*Chaque chiffre ci-dessus vient des vraies tables (`crawl_attempts`, `frontier_items`) et de | |
| 53 | −l'index réel — aucun compteur simulé (règle § fake du projet).* | |
| 39 | +- **Recherche Québec-first** : **59 000+ pages indexées**, **7 900+ domaines québécois** découverts à partir de 64 seeds, **latence de recherche 20–95 ms** (mesurée en prod). | |
| 40 | +- **Indexation incrémentale** : fetch → parse → score → index **inline** (`refresh_interval: 1s` côté OpenSearch) → **cherchable en secondes**. Détection de changement par **hash de contenu + ETag/If-Modified-Since**, recrawl adaptatif (inchangé → intervalle ×2, volatil → ÷2). | |
| 41 | +- **Détection Québec déterministe** : TLD (**.qc.ca**, **.quebec**), gazetteer de toponymes, codes postaux **G/H/J**, indicatifs (**418/514/438/…**), organisations connues (Hydro-Québec, RAMQ, UQAM…), JSON-LD, langue française — **aucun LLM dans le chemin chaud**. | |
| 42 | +- **Ranking bilingue** : `function_score` OpenSearch — **BM25 FR/EN** avec synonymes bilingues (thermopompe ↔ heat pump) + scores Québec + **autorité de domaine** (inlinks pondérés) + fraîcheur + **boost de localité** (« plombier Gatineau » → documents avec preuve géographique). | |
| 43 | +- **Crawler poli et assumé** : UA identifié `TrouveKABot`, page publique [/trouveka-bot](https://www.trouve-ka.com/trouveka-bot), **robots.txt respecté** (Protego, cache 24 h), **verrou de politesse Redis par hôte** (défaut 2 s, `Crawl-delay` honoré), **garde SSRF** (IP privées/loopback/métadonnées cloud bloquées, revalidée à chaque redirection), détection de **pièges de crawl** (session IDs, calendriers infinis, facettes explosives). | |
| 44 | +- **Onglet Images** : galerie des pages avec image représentative (**hotlink + attribution**, jamais de crawl d'images). | |
| 45 | +- **Métriques publiques réelles** : `/status` et `/stats` (tableau de bord + rapport PDF Groupe-KA) — **aucun compteur simulé** (règle du projet). | |
| 46 | +- **Crawl distribué multi-nœuds** : workers satellites sur **M2M32b** et **M2M32c**, coordonnés **sans orchestrateur** via le frontier Postgres (`FOR UPDATE SKIP LOCKED`) et les verrous Redis, communication par le **LAN interne 192.168.2.x**. | |
| 47 | +- **SSO KA ID** + design Groupe KA (éditorial sharp, accent azur) + widget **KA Agent** (bulle de chat IA). | |
| 54 | 48 | |
| 55 | 49 | --- |
| 56 | 50 | |
| 57 | −## Ce que c'est | |
| 51 | +## Architecture (multi-services) | |
| 58 | 52 | |
| 59 | −``` | |
| 60 | −Crawler → Frontier → Fetcher → Parser → Classification Québec | |
| 61 | −→ Déduplication → Indexer → Index → Ranking → API → Web App | |
| 62 | −``` | |
| 53 | +En production sur le nœud **M2M32**, l'application tourne en **processus natifs sous PM2**, avec l'infrastructure de données en **Docker** : | |
| 54 | + | |
| 55 | +| Service PM2 | Rôle | | |
| 56 | +|---|---| | |
| 57 | +| **tk-web** | Application web publique **Next.js 15** (**port 3000**) — proxifie `/api/*` vers l'API interne | | |
| 58 | +| **tk-api** | API **FastAPI** (`trouveka.api`) — recherche, statut, soumission, admin | | |
| 59 | +| **tk-crawler-1** / **tk-crawler-2** | Workers de crawl (fetch → parse → score → index inline) | | |
| 60 | +| **tk-enrichment** | Enrichissement asynchrone (autorité, entités, embeddings) via **Redis Streams** | | |
| 61 | +| **tk-scheduler** | Planification des recrawls, entretien du frontier | | |
| 62 | +| tk-tun-search / tk-tun-embed | Tunnels vers l'index de recherche et le service d'embeddings | | |
| 63 | + | |
| 64 | +| Conteneur Docker | Rôle | | |
| 65 | +|---|---| | |
| 66 | +| **PostgreSQL 16** (`postgres:16-alpine`, port 5432) | Frontier, domaines, documents, graphe de liens, analytics | | |
| 67 | +| **Redis 7** (`redis:7-alpine`, port 6379) | Politesse par hôte, pause, **Redis Streams** pour l'enrichissement | | |
| 63 | 68 | |
| 64 | −Le crawler découvre le web québécois à partir de seeds à forte autorité (gouvernement, | |
| 65 | −municipalités, universités, médias), suit les liens sortants, juge la pertinence | |
| 66 | −québécoise de chaque page (`page_quebec_score` **et** `domain_quebec_score`), | |
| 67 | −et indexe **immédiatement** : une page fetchée est cherchable en ~2-4 secondes, | |
| 68 | −pendant que le frontier continue de grandir. L'enrichissement (autorité, entités, | |
| 69 | −embeddings) arrive après, en asynchrone, sans jamais bloquer. | |
| 69 | +L'exposition publique se fait par **ngrok** sous **launchd** (`com.trouveka.ngrok`) : `ngrok http --url=www.trouve-ka.com 3000`. **Un seul port exposé** — pas d'URL absolues côté client, cookies/CORS sans surprise derrière le tunnel. | |
| 70 | 70 | |
| 71 | −Détails : [docs/architecture.md](docs/architecture.md) (diagrammes Mermaid) et | |
| 72 | −[docs/decisions.md](docs/decisions.md) (pourquoi OpenSearch, pourquoi Postgres | |
| 73 | −comme frontier, etc.). | |
| 71 | +--- | |
| 74 | 72 | |
| 75 | 73 | ## Stack |
| 76 | 74 | |
| 77 | 75 | | Couche | Choix | |
| 78 | 76 | |---|---| |
| 79 | −| Web | Next.js 15, TypeScript, React 19, Tailwind (composants style shadcn/ui) | | |
| 80 | −| API | FastAPI (Python 3.12) | | |
| 81 | −| Pipeline | Python 3.12 async — httpx, selectolax, Protego | | |
| 82 | −| BD relationnelle | PostgreSQL 16 (frontier, domaines, documents, graphe de liens, analytics) | | |
| 83 | −| Coordination | Redis 7 (politesse par hôte, pause, Redis Streams pour l'enrichissement) | | |
| 84 | −| Recherche | OpenSearch 2.17 (BM25 FR/EN, synonymes bilingues, function_score Québec-first) | | |
| 85 | −| Déploiement | Docker Compose sur m2m32 + ngrok (www.trouve-ka.com) | | |
| 77 | +| **Web** | **Next.js 15**, TypeScript, React 19, Tailwind (composants style shadcn/ui) | | |
| 78 | +| **API** | **FastAPI** (Python 3.12) | | |
| 79 | +| **Pipeline** | **Python 3.12 async** — httpx, selectolax, Protego | | |
| 80 | +| **BD relationnelle** | **PostgreSQL 16** (frontier, domaines, documents, graphe de liens, analytics) | | |
| 81 | +| **Coordination** | **Redis 7** (politesse par hôte, pause, Redis Streams) | | |
| 82 | +| **Recherche** | **OpenSearch 2.17** (BM25 FR/EN, synonymes bilingues, `function_score` Québec-first) | | |
| 83 | +| **Déploiement** | **PM2 + Docker (postgres, redis) sur M2M32** + ngrok launchd (**www.trouve-ka.com**) | | |
| 86 | 84 | |
| 87 | −## Layout du monorepo | |
| 85 | +--- | |
| 86 | + | |
| 87 | +## Structure du monorepo | |
| 88 | 88 | |
| 89 | 89 | ``` |
| 90 | 90 | apps/web # moteur public + dashboard /admin (Next.js) |
| 91 | 91 | apps/api # FastAPI (trouveka.api) |
| 92 | −services/ # crawler, frontier, parser, classifier, indexer, ranking, scheduler, enrichment | |
| 92 | +services/ # crawler, frontier, parser, classifier, indexer, ranking, | |
| 93 | + # scheduler, enrichment, embedding | |
| 93 | 94 | packages/ # config, database, logging, queue, search-core, shared, types |
| 94 | −infrastructure/ # docker/, migrations/, monitoring/, deployment/ (m2m32 + ngrok) | |
| 95 | +infrastructure/ # docker/, migrations/, monitoring/, deployment/ | |
| 95 | 96 | scripts/ # bootstrap-seeds/, start-crawler/, health-check/, eval/, check-headers.py |
| 96 | 97 | tests/ # unitaires : canonicalisation, SSRF, robots, scoring Québec, fetcher, ranking |
| 98 | +docs/ # architecture.md, decisions.md, screenshot.png | |
| 97 | 99 | ``` |
| 98 | 100 | |
| 99 | −Le backend Python est un seul package namespace `trouveka.*` mappé sur ce layout | |
| 100 | −(voir `pyproject.toml`). | |
| 101 | +Le backend Python est un **seul package namespace `trouveka.*`** mappé sur ce layout (voir `pyproject.toml`). | |
| 102 | + | |
| 103 | +--- | |
| 101 | 104 | |
| 102 | −## Démarrage rapide (dev) | |
| 105 | +## Démarrage local (dev) | |
| 103 | 106 | |
| 104 | 107 | ```bash |
| 105 | 108 | git clone … && cd trouve-ka |
@@ -115,110 +118,86 @@ pnpm dev # → http://localhost:3000 | ||
| 115 | 118 | # → des résultats apparaissent en quelques secondes |
| 116 | 119 | ``` |
| 117 | 120 | |
| 118 | −Ports occupés sur la machine? Surcharger dans `.env` : `PG_PORT`, `REDIS_PORT`, | |
| 119 | −`SEARCH_PORT`, `API_PORT` (et les URLs correspondantes). | |
| 120 | − | |
| 121 | −Stack complet en containers : `docker compose up -d --build` (le service `migrate` | |
| 122 | −applique les migrations, `crawler-worker` se scale avec | |
| 123 | −`docker compose up -d --scale crawler-worker=3`). | |
| 124 | − | |
| 125 | −## Comment ça marche | |
| 126 | − | |
| 127 | −### Crawl et politesse | |
| 128 | −- **Identité assumée** : UA `Mozilla/5.0 (compatible; TrouveKABot/0.1; +https://www.trouve-ka.com/trouveka-bot)`, | |
| 129 | − page publique [/trouveka-bot](https://www.trouve-ka.com/trouveka-bot), pas de stealth. | |
| 130 | −- **robots.txt** parsé avec Protego, cache 24 h en base; `noindex`/`nofollow`/`X-Robots-Tag` respectés. | |
| 131 | −- **Politesse par origine** : verrou Redis par hôte (défaut 2 s entre requêtes, `Crawl-delay` respecté), | |
| 132 | − quel que soit le nombre de workers. | |
| 133 | −- **Sécurité** : garde SSRF (IP privées/loopback/métadonnées cloud bloquées, revalidée à chaque | |
| 134 | − redirection), limites par réponse (3 Mo, 5 redirections, timeout 20 s), détection de pièges | |
| 135 | − (session IDs, calendriers infinis, facettes explosives, pagination sans fin). | |
| 136 | − | |
| 137 | −### Indexation incrémentale | |
| 138 | −Le worker exécute fetch→parse→score→index **inline** : `refresh_interval: 1s` côté | |
| 139 | −OpenSearch → cherchable en secondes. Détection de changement par hash de contenu + | |
| 140 | −ETag/If-Modified-Since; recrawl adaptatif (inchangé → intervalle ×2, volatil → ÷2). | |
| 141 | − | |
| 142 | −### Détection Québec | |
| 143 | −Deux scores distincts (`page` et `domaine`) calculés à partir de : TLD (.qc.ca, .quebec), | |
| 144 | −gazetteer de toponymes (pondération réduite pour les ambigus type Laval/Hull), codes | |
| 145 | −postaux G/H/J, indicatifs (418/514/438/…), organisations connues (Hydro-Québec, RAMQ, | |
| 146 | −UQAM…), mentions structurées de la province (JSON-LD), langue française (indice, pas preuve). | |
| 147 | −Déterministe et gratuit — aucun LLM dans le chemin chaud (§12). | |
| 121 | +Ports occupés sur la machine? Surcharger dans `.env` : `PG_PORT`, `REDIS_PORT`, `SEARCH_PORT`, `API_PORT` (et les URLs correspondantes). | |
| 148 | 122 | |
| 149 | −### Ranking | |
| 150 | −`function_score` OpenSearch : BM25 bilingue (analyzers FR + EN, synonymes | |
| 151 | −thermopompe↔heat pump à la recherche) + scores Québec + autorité de domaine | |
| 152 | −(inlinks pondérés) + fraîcheur + boost de localité (« plombier Gatineau » → documents | |
| 153 | −avec preuve géographique `locations`). Chaque composant est optionnel; BM25 tient seul. | |
| 154 | − | |
| 155 | −Évaluation mesurable : `python3 scripts/eval/run-eval.py --api http://localhost:8080` | |
| 156 | −(dataset dans `scripts/eval/ranking-eval.yaml`). | |
| 157 | − | |
| 158 | −## API | |
| 123 | +### API | |
| 159 | 124 | |
| 160 | 125 | - `GET /api/search?q=&page=&limit=&language=&category=&quebec_only=&freshness=` |
| 161 | 126 | - `GET /api/status` — compteurs publics (pages, domaines, débit, état du crawler) |
| 162 | 127 | - `POST /api/submit {"url": …}` — soumettre un site québécois (soumission ≠ inclusion) |
| 163 | −- `GET|POST /api/admin/*` — protégé par header `X-Admin-Token` : overview, flux live, | |
| 164 | − pause/reprise, seeds, recrawl, blocage de domaine, inspection du frontier | |
| 128 | +- `GET|POST /api/admin/*` — protégé par header `X-Admin-Token` : overview, flux live, pause/reprise, seeds, recrawl, blocage de domaine, inspection du frontier | |
| 165 | 129 | |
| 166 | −## Tests | |
| 130 | +### Tests | |
| 167 | 131 | |
| 168 | 132 | ```bash |
| 169 | −.venv/bin/python -m pytest tests/ # 54 tests : URLs, SSRF, pièges, Québec, frontier, parser, fetcher, ranking | |
| 133 | +.venv/bin/python -m pytest tests/ # URLs, SSRF, pièges, Québec, frontier, parser, fetcher, ranking | |
| 170 | 134 | python3 scripts/check-headers.py # header auteur obligatoire dans chaque fichier source (CI) |
| 171 | 135 | bash scripts/health-check/check.sh # santé du stack |
| 172 | 136 | ``` |
| 173 | 137 | |
| 174 | −## Déploiement m2m32 + ngrok (www.trouve-ka.com) | |
| 138 | +Évaluation du ranking : `python3 scripts/eval/run-eval.py --api http://localhost:8080` (dataset dans `scripts/eval/ranking-eval.yaml`). | |
| 175 | 139 | |
| 176 | −Prérequis sur m2m32 : colima + docker + docker-compose (brew), ngrok authentifié, | |
| 177 | −domaine `www.trouve-ka.com` réservé dans le compte ngrok. | |
| 140 | +--- | |
| 178 | 141 | |
| 179 | −```bash | |
| 180 | −pnpm deploy:m2m32 # = bash infrastructure/deployment/deploy-m2m32.sh | |
| 181 | −``` | |
| 142 | +## Déploiement (production) | |
| 182 | 143 | |
| 183 | −Le script : rsync du monorepo → `docker compose up -d --build` → migrations + seeds | |
| 184 | −(idempotent) → tunnel `ngrok http --url=www.trouve-ka.com 3000` → health-check. | |
| 185 | −Le web proxifie `/api/*` vers l'API interne : un seul port exposé, pas d'URL absolues | |
| 186 | −côté client, cookies/CORS sans surprise derrière le tunnel. | |
| 144 | +- **Nœud** : **M2M32** (`~/trouve-ka`) — Mac Studio, 12 cœurs, 32 Go. | |
| 145 | +- **Web** : **tk-web** sur le **port 3000**, exposé sur **https://www.trouve-ka.com**. | |
| 146 | +- **Tunnel** : **ngrok** sous **launchd** — label **`com.trouveka.ngrok`** (`~/Library/LaunchAgents/com.trouveka.ngrok.plist`). | |
| 147 | +- **Processus** : **PM2** (`pm2 ls` → tk-web, tk-api, tk-crawler-1/2, tk-enrichment, tk-scheduler) — auto-restart, survie au reboot. | |
| 148 | +- **Données** : **PostgreSQL 16** + **Redis 7** en **Docker** (`docker compose up -d postgres redis`). | |
| 187 | 149 | |
| 188 | −Opérations courantes sur le node : | |
| 150 | +Opérations courantes sur le nœud : | |
| 189 | 151 | |
| 190 | 152 | ```bash |
| 191 | −ssh M2M32 'cd trouve-ka && docker compose logs -f crawler-worker' # crawl en direct | |
| 192 | −ssh M2M32 'cd trouve-ka && docker compose up -d --scale crawler-worker=5' | |
| 153 | +ssh M2M32 | |
| 154 | +cd ~/trouve-ka | |
| 155 | +pm2 ls # état des services | |
| 156 | +pm2 logs tk-crawler-1 # crawl en direct | |
| 157 | +pm2 restart tk-web # après un build web | |
| 158 | +docker ps # postgres + redis | |
| 193 | 159 | ``` |
| 194 | 160 | |
| 195 | 161 | ### Crawl distribué (M2M32b, M2M32c) |
| 196 | 162 | |
| 197 | −Des workers satellites tournent en natif sur d'autres nodes du cluster et se | |
| 198 | −coordonnent **sans orchestrateur** via le frontier Postgres (`FOR UPDATE SKIP LOCKED`) | |
| 199 | −et les verrous de politesse Redis (tous nodes confondus : jamais plus d'une requête | |
| 200 | −par site par seconde). Communication par l'Ethernet LAN interne (`192.168.2.x`). | |
| 163 | +Des **workers satellites** tournent en natif sur d'autres nœuds du cluster et se coordonnent **sans orchestrateur** via le frontier Postgres (`FOR UPDATE SKIP LOCKED`) et les verrous de politesse Redis (tous nœuds confondus : **jamais plus d'une requête par site par seconde**). Communication par l'Ethernet LAN interne (**192.168.2.x**). | |
| 201 | 164 | |
| 202 | 165 | ```bash |
| 203 | −# Sur un node satellite (uv + python 3.12, .env pointé sur le node central) : | |
| 166 | +# Sur un nœud satellite (uv + python 3.12, .env pointé sur le nœud central) : | |
| 204 | 167 | cd ~/trouve-ka && pm2 start .venv/bin/python --name trouveka-crawler \ |
| 205 | 168 | --interpreter none -- -m trouveka.crawler.worker |
| 206 | 169 | ``` |
| 207 | 170 | |
| 208 | −⚠️ macOS Sequoia bloque l'accès « réseau local » des processus launchd : lancer les | |
| 209 | −workers satellites via pm2/nohup depuis une session SSH, pas via LaunchAgent/Daemon. | |
| 171 | +⚠️ **macOS Sequoia bloque l'accès « réseau local » des processus launchd** : lancer les workers satellites via **pm2/nohup depuis une session SSH**, pas via LaunchAgent/Daemon. | |
| 172 | + | |
| 173 | +### Observabilité | |
| 210 | 174 | |
| 211 | −## Observabilité | |
| 175 | +Logs JSON structurés par service, métriques réelles via `/api/status` et `/api/admin/overview`, dashboard **`/admin`** (files, débits, distribution HTTP, latences p50/p95, flux live). Voir [infrastructure/monitoring/README.md](infrastructure/monitoring/README.md). | |
| 212 | 176 | |
| 213 | −Logs JSON structurés par service, métriques réelles via `/api/status` et | |
| 214 | −`/api/admin/overview`, dashboard `/admin` (files, débits, distribution HTTP, latences | |
| 215 | −p50/p95, flux live). Voir [infrastructure/monitoring/README.md](infrastructure/monitoring/README.md). | |
| 177 | +--- | |
| 178 | + | |
| 179 | +## Développement remote-first (IMPORTANT) | |
| 180 | + | |
| 181 | +La **source de vérité est le repo git sur le nœud M2M32** (`~/trouve-ka`), **pas** une copie locale sur le laptop. Toute modification se fait **sur le nœud via SSH** : édition, build, `pm2 restart`, puis commit/push **sur le nœud**. | |
| 182 | + | |
| 183 | +- **Remote `origin` = spbgit** (git perso, **git.spboucher.ai**) — bare repo `~/srv/git/trouve-ka.git` sur M3U96a, accessible via l'**alias SSH `gitsrv`** configuré sur les nœuds. **Pas GitHub.** | |
| 184 | +- **Agent forwarding actif** : le `git push` fonctionne pendant une session SSH depuis le laptop. | |
| 185 | + | |
| 186 | +```bash | |
| 187 | +ssh M2M32 | |
| 188 | +cd ~/trouve-ka | |
| 189 | +# … éditer, builder, pm2 restart … | |
| 190 | +git add … && git commit -m "…" && git push origin main | |
| 191 | +``` | |
| 192 | + | |
| 193 | +--- | |
| 216 | 194 | |
| 217 | 195 | ## Règles du dépôt |
| 218 | 196 | |
| 219 | −- **Header auteur obligatoire** dans chaque fichier source (§0.1) — vérifié par | |
| 220 | − `scripts/check-headers.py`. | |
| 221 | −- **Aucune donnée factice** : pas de compteurs simulés, pas de résultats hard-codés; | |
| 222 | − les fixtures vivent dans `tests/` uniquement. | |
| 223 | −- Provenance préservée : URL originale, canonique, timestamp de crawl, domaine source. | |
| 224 | − Trouve-KA renvoie vers les éditeurs originaux. | |
| 197 | +- **Header auteur obligatoire** dans chaque fichier source — vérifié par `scripts/check-headers.py`. | |
| 198 | +- **Aucune donnée factice** : pas de compteurs simulés, pas de résultats hard-codés; les fixtures vivent dans `tests/` uniquement. | |
| 199 | +- **Provenance préservée** : URL originale, canonique, timestamp de crawl, domaine source. **Trouve-KA renvoie vers les éditeurs originaux.** | |
| 200 | + | |
| 201 | +--- | |
| 202 | + | |
| 203 | +Un service **Groupe Ka** — [www.groupe-ka.com](https://www.groupe-ka.com) | |
added
docs/screenshot.png
+0 −0
Binary file not shown.