# Améliorations Recherche — Pagination + Export enrichissement

**Date:** 2026-06-09
**Page:** `/keywords/recherche` (stage `research`)
**Contexte:** depuis le sync GSC, Recherche peut contenir des centaines de mots-clés (350 pour Acieb), dont beaucoup GSC-only sans métriques SEO (Volume/KD/CPC en N/A). Deux besoins : (1) naviguer la table (pagination), (2) ré-exporter les mots-clés sans métriques vers Mangools/Semrush/Ahrefs pour les enrichir.

Un seul lot, build groupé.

---

## A. Pagination

**Objectif:** paginer la table Recherche, taille de page réglable, contrôles haut + bas.

- **Client-side** via TanStack `getPaginationRowModel` — les lignes sont déjà toutes chargées côté client (`fetchKeywordsForSiteAction`), aucun refetch.
- **Tailles de page:** 20 / 50 / 100 / 500. **Défaut: 50.**
- **Contrôles dupliqués en haut ET en bas** de la table : sélecteur de taille + « ‹ Précédent / Suivant › » + indicateur « Page X / Y · N résultats ».
- **Sélection multi-pages préservée:** TanStack garde la sélection par row id à travers les pages. Le « tout sélectionner » de l'entête sélectionne **toutes les lignes filtrées** (pas seulement la page courante) — comportement actuel conservé (le ciblage en dépend).
- **Contrôles via le composant shadcn `Pagination`** (`PaginationPrevious/Next` câblés sur `table.previousPage/nextPage`, `aria-disabled` quand bornes atteintes) + un `Select` shadcn pour la taille de page. Le composant `pagination` est ajouté via la CLI shadcn (`bunx --bun shadcn@latest add pagination`).
- **Porté par le composant partagé `src/components/ui/data-table.tsx`** (props opt-in `pageSize` + `pageSizeOptions`), puis **activé sur les 4 tables** qui en ont besoin :
  - `keywords/research/research-container.tsx` (Recherche)
  - `keywords/reservoir.tsx` (réservoir keywords)
  - `backlink/reservoir-container.tsx` (réservoir backlink)
  - `backlink/domain-profile-container.tsx` (profil backlink)

**Hors scope:** pagination server-side (inutile à ces volumes) ; `content-table` et `flight-check/checklist` (non demandés — laissés tels quels).

---

## B. Export enrichissement

**Objectif:** produire des listes de mots-clés prêtes à coller/importer dans un outil de recherche, pour récupérer les métriques manquantes.

- **Déclencheur:** bouton **« Exporter »** dans la toolbar Recherche → ouvre un petit dialog.
- **Portée:** les mots-clés **sans métrique** du périmètre Recherche. Critère = `metrics[primarySource]?.volume == null` (même logique que la cellule N/A). C'est l'ensemble à enrichir.
- **Outil cible (radio):** détermine la taille de chunk.
  | Outil | Limite / fichier |
  |---|---|
  | Mangools (KWFinder) | 700 |
  | Semrush (Keyword Strategy Builder) | 2 000 |
  | Ahrefs (Keywords Explorer) | 10 000 |
- **Regroupement par pays puis découpage:** on groupe d'abord par `locale.country` (on recherche par marché), puis chaque groupe est découpé en chunks ≤ limite outil.
- **Format:** `.txt`, **1 terme par ligne**, UTF-8, sans en-tête. (Un fichier mono-colonne fonctionne pour le paste Mangools/Ahrefs et l'upload Semrush.)
- **Livraison:**
  - 1 seul chunk → téléchargement direct d'un `.txt`.
  - ≥ 2 chunks → un `.zip` (dépendance **`jszip`**) contenant les fichiers `recherche-<site>-<outil>-<pays>-<n>.txt`.
- **Génération client-side** (données déjà en mémoire) — aucun server action.
- **Récap avant download** dans le dialog : ex. « 313 sans métrique · FR · Mangools → 1 fichier (≤ 700) » ; se met à jour au changement d'outil.

**Cas limites:**
- 0 mot-clé sans métrique → message « Aucun mot-clé à enrichir » + bouton download désactivé.
- Termes dédupliqués (par `term` lowercase) avant chunking pour ne pas gaspiller le quota outil.

---

## Découpage technique (unités)

- `src/lib/keywords/export-enrichment.ts` — **fonction pure** `buildEnrichmentChunks(keywords, { tool }): { country: string; chunks: string[][] }[]` + `TOOL_LIMITS`. Testable en isolation (TDD).
- `src/components/keywords/export-enrichment-dialog.tsx` — le dialog (choix outil, récap, download txt/zip).
- `src/components/ui/data-table.tsx` — ajout de la pagination opt-in (sélecteur + contrôles haut/bas).
- `src/components/keywords/research/research-container.tsx` — bouton « Exporter » dans la toolbar + activation de la pagination ; passe les lignes sans métrique au dialog.
- Dépendance: `jszip` (installée via `sfw bun add`).

## Tests
- **Unitaire (pur, sans DB):** `export-enrichment.test.ts` — groupe par pays, chunk à la limite outil, dédup, 0-cas, filtre sans-métrique. C'est le cœur de la logique.
- **Pagination/dialog:** UI, vérifiés live (d3k) — pas de nouveau harness de test.

## Out of scope (notés pour plus tard)
- Export « données complètes » (CSV avec toutes colonnes) — l'autre besoin, à part.
- Ré-import automatique des métriques enrichies (boucle retour) — futur.
- Pagination Réservoir.
