Files
limier/docs/01-architecture.md
hcornet 78fb13b0e5
CI / Backend — lint, types, tests (push) Failing after 4m44s
CI / Interface — types et compilation (push) Successful in 10m23s
CI / Construction des images (sans publication) (push) Skipped
first sync
2026-09-12 13:10:16 +02:00

5.2 KiB

Architecture

Vue d'ensemble

                    tunnel Cloudflare
                            │
                       Traefik (https)
                            │
        ┌───────────────────┴───────────────────┐
        │ priorité 20 : /api       priorité 10 : /  │
        ▼                                       ▼
   limier-api                              limier-web
   (FastAPI)                               (nginx + React compilé)
        │
        ├──── PostgreSQL ──── recherches, résultats, comptes, quotas
        │
        └──── Redis ────┬──── file de travaux (arq)
                        └──── progression en direct (SSE)
                                      ▲
                                      │
                                 limier-worker
                                      │
                    ┌─────────────────┼─────────────────┐
                    ▼                 ▼                 ▼
             moteur pseudonyme   moteur e-mail    moteur domaine
                (Maigret)                              │
                                      │                │
                              limier-holehe       RDAP, DNS, CT
                              (optionnel, GPL)

Pourquoi cette découpe

API et worker dans la même image, deux commandes. Même code, même base de sites, aucune divergence possible à la mise à jour. Deux images finiraient par se désynchroniser à la première publication oubliée.

Interface servie par un conteneur nginx distinct. L'API ne sert aucun fichier statique. Reconstruire l'interface ne touche pas au backend, et inversement. Traefik arbitre par priorité de routeur : /api (priorité 20) l'emporte sur / (priorité 10).

Une recherche est un travail, pas une requête. Un balayage de 500 sites prend 30 à 120 secondes. Le faire dans une requête HTTP produirait des délais dépassés côté proxy et bloquerait un worker uvicorn. L'API accepte, met en file et rend un identifiant ; le worker exécute.

arq plutôt que Celery. Maigret est asynchrone de bout en bout, arq aussi. Celery aurait imposé un pont entre son modèle de travailleurs synchrones et une boucle asyncio, sans aucun gain.

SSE plutôt que WebSocket. Le flux est unidirectionnel, SSE se reconnecte seul, passe partout en HTTP/1.1 et ne demande aucune configuration Traefik particulière.

Le contrat des moteurs

Tout part de engines/base.py. Un moteur reçoit une EngineRequest et émet un flux d'évènements au lieu de rendre un résultat final :

Évènement Rôle
ProgressEvent avancement, alimente la barre de progression
FindingEvent un résultat, déjà scoré
NoticeEvent information non bloquante (module désactivé, source KO)

C'est ce qui permet l'affichage en direct, et c'est aussi ce qui rend l'ajout d'un moteur trivial : créer un module dans engines/<nom>/engine.py, l'enregistrer dans engines/registry.py. Rien d'autre ne change.

Les résultats sont écrits pendant la recherche, pas à la fin : une recherche interrompue à 80 % conserve ses 80 %.

Chemin d'un évènement

moteur ──► worker ──► Redis ──┬──► liste  (historique rejouable)
                              └──► canal  (réveil immédiat)
                                      │
                                      ▼
                              API /flux (SSE) ──► navigateur

La liste permet à un navigateur qui se connecte en retard, ou qui se reconnecte, de ne rien perdre. EventSource renvoie Last-Event-ID, le backend ne rejoue que le manquant.

Où chercher quoi

Question Fichier
Une variable d'environnement backend/src/limier/config.py
Le schéma de la base backend/src/limier/db/models.py
Comment un résultat est jugé fiable backend/src/limier/engines/scoring.py
L'appel à Maigret engines/username/engine.py
Les variantes « prénom nom » engines/username/permutations.py
Ce que fait le worker backend/src/limier/jobs/tasks.py
Les règles d'acceptation d'une recherche api/routes/searches.py
L'authentification Authentik backend/src/limier/auth/oidc.py
Les quotas et la limitation de débit backend/src/limier/quotas/service.py
La conservation et l'effacement backend/src/limier/privacy/retention.py
La sortie réseau et les proxies backend/src/limier/net/proxy_pool.py