# seoinsight v2 — Flow utilisateur et features (SEOINSIGHT-36)

Date : 2026-08-28
Statut : validé en brainstorming, en attente de relecture avant les specs de modules.
S'appuie sur : architecture (2026-08-26), workflow de dev & auth API (2026-08-27), données à grande échelle (2026-08-28).

## 0. Le but de l'app (clarifié le 2026-08-31)

1. **All-in-one keywords** : accéder à toutes les données mots-clés des différentes plateformes SEO en un seul endroit.
2. **Vue d'ensemble simple pour planifier** : préparer les modifications on-page sans basculer entre les dashboards (Semrush, KWFinder, Screaming Frog…), repérer les oublis, organiser le travail.

**Ce n'est pas un outil d'audit** : le crawl produit un inventaire factuel au service de la planification, pas de notation. Aucun « score SEO » par page ; là où les specs antérieures (architecture §2) parlent d'« issues, score par page », lire « inventaire + éléments à traiter dans le planning ».

## 1. Le flow en une ligne

**Entrer un site → définir ses cibles (pays/langue) → crawl automatique → connecter GSC (optionnel) → importer les listes de mots-clés du domaine (fournisseurs connectés + CSV) → travailler dans cinq écrans.**

L'utilisateur n'attend jamais sur un écran bloquant : tout ce qui est long est un job (table `jobs` + worker), la page du site affiche l'état (« Crawl 34 % · GSC non connecté · 0 liste »).

## 2. Création d'un site (wizard, 3 écrans)

1. **Domaine** : saisie `https://exemple.fr` → vérifications immédiates (résolution DNS, `robots.txt`, sitemap détecté) affichées avant de continuer.
2. **Cibles** : table `site_targets`, **1..n couples (pays, langue)** par site — une cible par défaut pré-remplie (TLD, attribut `lang` de la home). Un site mono-marché reste le cas simple : une seule ligne. Chaque crawl, snapshot GSC et liste importée est rattaché à une cible.
3. **Lancement** : le crawl démarre immédiatement (job) ; la connexion GSC et les imports sont proposés mais optionnels et asynchrones.

## 3. Crawl (module Pages)

- **Moteur (décidé 2026-08-28)** : crawler **Python maison in-process** dans le worker — `httpx` async + parsing `selectolax`, texte principal via `trafilatura` ; **repli Playwright** uniquement pour les pages dont le HTML utile est vide (SPA). Respect `robots.txt`, plafond de pages par plan, historique conservé par run, re-crawl manuel (site entier ou page à la page).
- **Écarté** : Firecrawl self-host (service en plus — pool navigateurs + Redis —, ~7× plus lent que spider-rs sur pages statiques, rendu JS avancé/anti-bot réservés au Cloud payant, sortie markdown alors qu'on a besoin du HTML brut). **Évolution inscrite** : `spider-rs` (Rust, Apache-2.0) comme moteur de fetch dans `crates/` quand les crawls concurrents massifs arriveront — il remplace le fetcher sans changer le reste.
- **Extrait par page** : title (+ longueur), meta description, canonical, directives robots, H1–H6 (structure), texte principal, images + alt, liens internes/externes, status HTTP, taille, temps de réponse, `text_hash`. HTML brut en zstd sur disque, champs structurés en Postgres (spec data §3).

## 4. GSC (par site, optionnel)

Connexion OAuth gérée par `api/` (spec architecture §7) ; choix de la propriété ; **backfill limité à 12 mois maximum** (décision utilisateur 2026-08-28 — l'API en offre 16, on n'en récupère qu'un an) puis snapshots quotidiens ; dimensions pays/appareil rattachées aux `site_targets` (segmentation qui maintient chaque requête API sous le plafond des 50 k lignes/jour). GSC est la seule source des requêtes **réelles** ; sans GSC, les écrans fonctionnent avec les données importées.

## 5. Import de listes (module Keywords)

Par cible (pays/langue) :

- **« Récupérer les mots-clés du domaine »** chez chaque fournisseur connecté. Capacités vérifiées (2026-08-28) :

| Fournisseur | Domaine → keywords | Pays/langue | Notes |
|---|---|---|---|
| Mangools | `kwfinder/competitor-keywords` | `location_id` (pays) | 1 000 kw/req, 1 crédit |
| SE Ranking | `domain/keywords` | base régionale `source` | 100 crédits/req, positions incluses |
| DataForSEO | `labs/google/ranked_keywords` | pays **et** langue indépendants | ~0,13 $/1 000 lignes — candidat « source incluse » |
| Semrush | `domain_organic` | base = pays | 10 units/ligne |
| Ahrefs v3 | `site-explorer/organic-keywords` | pays | units ligne×colonne |
| Keywords Everywhere | `get_domain_keywords` | pays | sans positions |
| Keysearch / LowFruits | non (API interne / pas d'API) | — | **upload CSV** |
| SerpApi | non (SERP par mot-clé) | pays+langue | vérification de position, pas de découverte |

- **Upload CSV** pour tout le reste (exports manuels Semrush/Ahrefs inclus).
- Tout passe par **un adaptateur par source** → modèle canonique `keywords` + `keyword_metrics` avec provenance (spec data §7) ; import = job idempotent avec rapport.
- **Clés API : modèle mixte (décidé 2026-08-28)** — écran « Intégrations » par organisation : **BYOK** par défaut (clés chiffrées dans DATA, comme le refresh token GSC) ; certaines sources « incluses » via les clés de la plateforme avec **quota par org** (DataForSEO, facturé à la ligne, s'y prête).

## 6. Les cinq écrans

| # | Écran | Contenu | Source |
|---|---|---|---|
| 0 | **Vue d'ensemble** (post-crawl) | Agrégats du run : titles manquants/dupliqués/hors longueur, metas, structure Hx incohérente, images sans alt, 4xx/5xx, canonicals, profondeur — chaque tuile ouvre l'inventaire filtré | Crawl |
| 1 | **Inventaire page par page** | Tableau des pages (title, meta, H1, statut, éléments manquants ou à revoir) + fiche page détaillée — matière à planifier, pas une note | Crawl |
| 2 | **Matrice page × mots-clés** (cœur) | Par page : requêtes GSC réelles + mots-clés importés qui s'y positionnent + assignations manuelles, origine visible ; **orphelins** (mots-clés sans page) = opportunités à assigner | GSC + imports + manuel |
| 3 | **Réservoir de mots-clés** | Toutes les listes fusionnées, provenance par source, filtres (volume, KD, intent, source, cible), tags, sélection planning | Imports |
| 4 | **Suivi dans le temps** | Clics/impressions/positions par page et requête, semaine après semaine | GSC |

**Mapping mot-clé ↔ page (décidé 2026-08-28)** : automatique par URL (GSC : requête→page ; fournisseurs : URL de positionnement) + **ajustement manuel** pour le planning. Rapprochement sémantique (embeddings) = évolution v2.x, premier usage réel des vecteurs (spec data §3).

## 7. Hors périmètre du flow v2

Crawl de sites **concurrents** (viendra avec spider-rs et la comparaison de contenus), suivi de positions par SERP (SerpApi), clustering sémantique, assistant IA/RAG, quotas/facturation fine des sources incluses. Chacun aura sa spec.

## 8. Ordre de construction (une spec + un plan par module)

1. **Sites** : modèle `sites` + `site_targets`, wizard 3 écrans, page du site avec états des jobs.
2. **Crawl** : table `jobs` + worker, crawler HTTP-first, écrans 0 et 1.
3. **GSC** : OAuth, backfill + snapshots partitionnés, écran 4.
4. **Intégrations + imports** : écran Intégrations (BYOK + incluses), adaptateurs fournisseurs + CSV, réservoir (écran 3).
5. **Matrice** (écran 2) : croisement des trois sources, orphelins, assignation.

Chaque étape livre un écran utilisable seul. Les décisions ouvertes SEOINSIGHT-1 à 5 et 37 seront tranchées au fil de ces specs.
