spb/trouve-ka Public
Trouve-KA — moteur de recherche web indépendant, Québec-first. Crawler distribué, index OpenSearch, ranking bilingue, galerie d'images. En prod : www.trouve-ka.com
Python 76.8%
TypeScript 15.7%
SQL 3.9%
Shell 1.4%
CSS 1.3%
Dockerfile 0.7%
1# Trouve-KA — Architecture23Author: Simon-Pierre Boucher — Contact: contact@spboucher.ai45## Vue d'ensemble67```mermaid8flowchart LR9 subgraph Découverte10 SEEDS[Seeds §8] --> FRONTIER11 SUBMIT[Soumissions /soumettre] --> FRONTIER12 LINKS[Liens sortants] --> FRONTIER13 end14 FRONTIER[(Frontier<br/>Postgres)] -->|claim SKIP LOCKED| CW[crawler-worker × N]15 CW -->|politesse SET NX PX| REDIS[(Redis)]16 CW --> ROBOTS[robots.txt cache]17 CW --> FETCH[Fetcher HTTP<br/>garde SSRF]18 FETCH --> PARSE[Parser selectolax]19 PARSE --> QC[Classification Québec<br/>page_quebec_score]20 QC --> DEDUP[Hash contenu / doublons]21 DEDUP -->|indexation IMMÉDIATE| OS[(OpenSearch<br/>trouveka-docs)]22 DEDUP --> PG[(Postgres<br/>documents, domaines, liens)]23 CW -->|jamais bloquant| STREAM[Redis Stream<br/>trouveka:enrich]24 STREAM --> EW[enrichment-worker]25 EW -->|update partiel| OS26 SCHED[scheduler] -->|items abandonnés,<br/>autorité de domaine| PG27 OS --> API[API FastAPI]28 PG --> API29 API --> WEB[Next.js web<br/>+ /admin]30 WEB --> NGROK[ngrok<br/>www.trouve-ka.com]31```3233## Principe cardinal (§0.3)3435```mermaid36sequenceDiagram37 participant F as Frontier38 participant W as crawler-worker39 participant O as OpenSearch40 participant U as Utilisateur41 F->>W: claim URL (t+0s)42 W->>W: fetch + parse + score Québec (t+2s)43 W->>O: index_document (t+3s)44 Note over O: refresh_interval 1s45 U->>O: recherche (t+4s) — la page est déjà cherchable46 W--)W: enrichissement async (étapes 2-3, plus tard)47```4849Jamais de cycle « crawler tout → indexer → chercher ». L'enrichissement met à jour50des documents **déjà cherchables** (update partiel), il ne conditionne rien.5152## Cycle de vie d'une URL5354```mermaid55stateDiagram-v256 [*] --> pending: découverte (seed, lien, soumission)57 pending --> in_progress: claim (priorité DESC, SKIP LOCKED)58 in_progress --> pending: politesse (trop tôt pour cet hôte)59 in_progress --> pending: succès → next_crawl_at adaptatif60 in_progress --> pending: erreur transitoire (retry backoff ≤3)61 in_progress --> done: robots refusé / redirection / doublon62 in_progress --> failed: erreur permanente ou retries épuisés63 in_progress --> blocked: domaine bloqué64 pending --> in_progress: recrawl (fréquence mesurée §5.5)65```6667## Scores (§4, §7, §9)6869| Étape | Quand | Champs |70|---|---|---|71| 1 — immédiat | pipeline inline | titre, corps, headings, langue, `page_quebec_score`, `locations`, catégories grossières |72| 2 — async | enrichment-worker | `domain_quebec_score` à jour, `authority_score` propagé (plus tard : embeddings, entités) |73| 3 — async | scheduler | autorité de domaine depuis `domain_links` (inlinks pondérés Québec) |7475Ranking à la requête : `function_score = BM25 (multi_match FR/EN + synonymes) +76w·page_quebec + w·domain_quebec + w·autorité + gauss(published_at) + boost localité`77(désactivable composant par composant — BM25 reste seul debout si tout tombe, §9).7879## Dégradation gracieuse (§13)8081- OpenSearch en panne → l'API répond 503 sur /search, /status reste up; le crawler continue d'alimenter Postgres? Non : l'indexation échoue → l'item est relâché en retry; le frontier survit.82- Redis en panne → politesse locale impossible : le worker s'arrête proprement; Postgres intact.83- Un worker crash → `scheduler.reset_stale_items` relance ses URLs après 30 min.84- Enrichissement en retard → aucune conséquence sur la recherche (backlog visible dans /admin).8586## Déploiement m2m32 (§0.2)8788```mermaid89flowchart LR90 NG[ngrok www.trouve-ka.com] --> WEB3000[web :3000]91 WEB3000 -->|rewrite /api/*| API8080[api :8080]92 subgraph m2m32[Docker Compose sur m2m32 — 32 Go]93 WEB300094 API808095 PG5432[postgres]96 RD[redis]97 OS9200[opensearch 2 Go heap]98 CWX[crawler-worker × N]99 EN[enrichment-worker]100 SC[scheduler]101 end102```103104Un seul port exposé publiquement (3000 via ngrok). Budgets mémoire : OpenSearch 2 Go105de heap (~3 Go RSS), Postgres < 1 Go, workers Python ~100-200 Mo chacun, web ~150 Mo —106large marge sur 32 Go, scalable par `docker compose up -d --scale crawler-worker=3`.107