# Flight Checker — Intégration de la checklist The Website Specification

**Date:** 2026-06-03
**Statut:** Design validé, prêt pour plan d'implémentation

## Contexte

La page `src/app/flight-checker/page.tsx` et ses composants (`src/components/flight-check/*`)
sont actuellement remplis de scaffolding placeholder (cartes vides, onglets copier-collés
affichant tous « Security », `data-table` branchée sur un type démo `Payment`).

L'objectif est d'y intégrer la **vraie data** de la checklist
[The Website Specification](https://specification.website) — **10 catégories, ~128 items**,
chacun avec `title`, `status` (required / recommended / optional / avoid), `description`, `url` —
et de transformer la page en une **version améliorée** du self-audit de l'original :
checklist cochable, recherche globale, progression.

La source canonique est le serveur MCP `specification-website` (read-only, renvoie du Markdown,
pensé pour les agents — pas une API runtime).

## Objectifs

- Brancher la vraie data de la checklist (128 items, 10 catégories).
- Séparation propre **server / client components**.
- Self-audit **cochable**, état persistant côté navigateur (MVP).
- **Recherche globale** cross-catégorie.
- Progression par catégorie et globale.
- shadcn obligatoire pour tous les composants UI.

## Non-objectifs (hors scope MVP)

- Audit automatique d'une URL (analyse de site réel) — plus tard.
- Persistance backend / compte utilisateur — SurrealDB envisagée plus tard,
  mais le MVP reste en localStorage.
- Édition / contribution à la spec.

## Décisions d'architecture

| Sujet | Décision |
|---|---|
| Source data runtime | **Hybride** : fichier TS statique committé (lu en prod), + script de régénération versionné. |
| Fonction page | Checklist de référence cochable (self-audit local), plus avancée que l'original. |
| Moteur d'affichage | **TanStack Table** (réutilise `data-table.tsx`). |
| Structure | **Approche A** : une seule `DataTable`, l'onglet pilote un filtre de catégorie ; search globale. |
| Persistance état coché | localStorage via un hook à interface propre (remplaçable par SurrealDB sans toucher l'UI). |
| UI | shadcn obligatoire. |

## Modèle de données

`src/lib/spec/checklist-data.ts` — fichier typé, committé, généré depuis la source.

```ts
export type SpecStatus = "required" | "recommended" | "optional" | "avoid";

export type SpecCategoryId =
  | "foundations" | "seo" | "accessibility" | "security" | "well-known"
  | "agent-readiness" | "performance" | "privacy" | "resilience" | "i18n";

export type SpecItem = {
  id: string;            // slug, ex: "doctype"
  category: SpecCategoryId;
  title: string;
  status: SpecStatus;
  description: string;
  url: string;
};

export type SpecCategory = {
  id: SpecCategoryId;
  label: string;         // "Foundations"
  summary: string;       // "HTML, head, document basics."
  items: SpecItem[];
};

export const CHECKLIST: SpecCategory[];
```

Identifiants **canoniques = ids du MCP** : `foundations`, `seo`, `accessibility`, `security`,
`well-known`, `agent-readiness`, `performance`, `privacy`, `resilience`, `i18n`.
(On abandonne les valeurs actuelles `well-known-uris` / `internationalisation`.)

Les `SpecItem.id` doivent être stables (dérivés du slug d'URL) — ils servent de **clé
localStorage** et de clé React. Un changement de slug invaliderait l'état coché correspondant.

## Régénération (le « hybride »)

`scripts/generate-checklist.ts`, exécutable via `bun`.

- **À vérifier en implémentation** : si specification.website expose un endpoint data propre
  (JSON, ou markdown par page — la spec elle-même prône les « per-page markdown endpoints »),
  le script le consomme. Sinon, fallback : parsing du Markdown renvoyé par la checklist.
- **MVP** : le fichier statique est peuplé immédiatement à partir des 10 appels `get_checklist`
  du MCP `specification-website`. Le script formalise ensuite la régénération reproductible.
- Le script écrit/écrase `src/lib/spec/checklist-data.ts` (data triée, déterministe).

## Séparation server / client

| Fichier | Type | Rôle |
|---|---|---|
| `app/flight-checker/page.tsx` | **server** | Importe `CHECKLIST`, nettoie le scaffolding placeholder (3 cartes vides, breadcrumb « Data Fetching »), rend `<Checklist categories={CHECKLIST} />`. |
| `components/flight-check/checklist.tsx` *(nouveau)* | **client** | Parent. Détient l'état search, l'onglet actif, le hook d'état coché. Rend : `Input` recherche + barre de progression globale + `Tabs` + `DataTable`. |
| `components/flight-check/data-table.tsx` | **client** | Généralisée : row-selection (checkbox), `globalFilter` contrôlé (search), filtre `category`, filtre statut (faceted, optionnel), état coché branché. |
| `components/flight-check/columns.tsx` | **client** | `Payment` → colonnes `SpecItem` : checkbox, badge statut, titre, description, lien externe. |
| `components/flight-check/status-badge.tsx` *(nouveau)* | client | `Badge` shadcn, une variante de couleur par `SpecStatus`. |
| `hooks/use-checklist-state.ts` *(nouveau)* | client | localStorage. Interface : `isChecked(id)`, `toggle(id)`, `reset()`, `progress(categoryId?)`. Conçue pour être rebranchée sur SurrealDB sans toucher l'UI. |

Le composant placeholder actuel `checklist-tabs.tsx` est **remplacé** par `checklist.tsx`.

## Flux de données & interactions

1. `page.tsx` (serveur) lit `CHECKLIST` et le passe en props au `<Checklist>` (client).
2. La search alimente le `globalFilter` TanStack ; chaque `TabsTrigger` affiche un badge
   `nombre de matchs` quand une recherche est active, et un compteur de progression
   `coché/total` par catégorie.
3. Sélectionner un onglet applique un filtre `category` sur l'unique `DataTable`.
4. Cocher une case → `toggle(id)` → écrit en localStorage → progression globale + par onglet
   recalculées.
5. Filtre statut (faceted) disponible dans la toolbar de la table.

## État local (hook)

`use-checklist-state.ts` :
- Clé localStorage unique (ex: `flight-checker:checked`), valeur = `Record<string, true>`
  (seuls les items cochés sont stockés).
- Hydratation safe SSR (lecture localStorage uniquement après montage ; éviter le mismatch
  d'hydratation Next).
- `progress(categoryId?)` renvoie `{ done, total }` (global si pas d'argument).
- Interface stable pour migration SurrealDB ultérieure.

## Composants shadcn requis

À installer / vérifier via la CLI shadcn (cf. `components.json`) :
`checkbox`, `badge`, `input` (les autres — `tabs`, `table`, `card`, `button` — sont présents).

## Tests / vérification

- La data file contient bien 10 catégories et le compte d'items attendu (~128).
- Tous les `SpecItem.id` sont uniques.
- Server/client : `page.tsx` ne porte pas `"use client"` ; toute l'interactivité vit dans
  les composants client.
- Cocher / décocher persiste après reload (localStorage).
- La recherche filtre bien cross-catégorie et les badges de match sont cohérents.
- Pas de warning d'hydratation Next au chargement.
- `bun run build` passe ; lint (oxlint) propre.

## Risques / points ouverts

- **Endpoint de régénération** : forme exacte de la source à valider (JSON vs markdown
  per-page vs parsing checklist). N'impacte pas le MVP (peuplé via MCP).
- **Stabilité des slugs** : un changement de slug côté spec invalide l'état coché lié.
  Acceptable au stade MVP.
