# Architecture : comment le socle est construit

Tout est calculé au build : une chaîne de scripts moissonne et fusionne les sources ouvertes, Next.js génère les pages à partir des JSON publiés, Pagefind indexe le HTML produit. Aucun service à superviser en dehors du serveur web.

---

## 📑 Sommaire de la section

<FeatureGrid cols={2}>
  <FeatureCard
    icon="🧱"
    title="Stack technique"
    description="Node 22, pnpm, Next.js 16, React 19, Mantine 7, Pagefind, Zod, Vitest, Playwright, Storybook. Les dossiers, les trois paquets autonomes, les commandes et leurs durées."
    href="/architecture/stack-technique"
  />
  <FeatureCard
    icon="🔗"
    title="Chaîne de données"
    description="data:extract copie, data:build fusionne et publie, le site se génère. Règles de fusion par entité, volumes, et comment ajouter une source."
    href="/architecture/chaine-de-donnees"
  />
  <FeatureCard
    icon="🏷️"
    title="Marque blanche"
    description="Une instance = un fichier de configuration et deux logos. Créer une instance, brancher l'annuaire de l'établissement, les langues."
    href="/architecture/marque-blanche"
  />
  <FeatureCard
    icon="🔎"
    title="Recherche"
    description="Pagefind indexe les fiches au build, la recherche tourne dans le navigateur. Limites, options comparées, quand passer à Meilisearch."
    href="/architecture/recherche"
  />
</FeatureGrid>

---

## 🏷️ Une instance pilote tout

<Mermaid
  title="Ce que la configuration d'instance commande"
  caption="Le code ne lit la configuration qu'à travers son schéma Zod (src/config/schema.ts)."
  chart={`flowchart TB
  CONF["instances/&lt;id&gt;/research.config.ts"]
  subgraph BLOCS["Blocs de configuration"]
    direction LR
    SITE["site<br/>nom, accroche, langues, URL"]
    BRAND["brand<br/>4 couleurs, 2 polices, logos"]
    PERIM["perimeter<br/>ROR, scanR, HAL, RNSR, annuaire"]
    GROUPS["groups<br/>Graduate Schools, règles"]
    THEMES["themes<br/>thématiques transversales"]
    SOURCES["sources<br/>rôle et priorité"]
  end
  subgraph EFFETS["Effets dans le socle"]
    direction LR
    THEME["Thème Mantine calculé<br/>échelles de 10 nuances, jetons CSS"]
    EXTRACT["Moisson<br/>requêtes par identifiant"]
    BUILD["Fusion<br/>liste maître, priorités des champs,<br/>rattachements par domaines HAL"]
    PAGES["Pages fr/en<br/>navigation, libellés, SEO"]
  end
  CONF --> BLOCS
  BRAND --> THEME
  PERIM --> EXTRACT
  SOURCES --> EXTRACT
  SOURCES --> BUILD
  GROUPS --> BUILD
  THEMES --> BUILD
  SITE --> PAGES
  THEME --> PAGES`}
/>

---

## 🔎 La recherche, sans serveur

<Mermaid
  title="De la page générée au résultat affiché"
  chart={`flowchart LR
  NEXT["next build<br/>fiches avec data-pagefind-body,<br/>filtres data-pagefind-filter"]
  PF["pagefind --site .next/server/app<br/>index découpé en fragments"]
  OUT{{"Comment l'index entre dans le site ?"}}
  PUBLIC["public/pagefind/&lt;instance&gt;<br/>auto-hébergement : servi tel quel"]
  STATIC["/pagefind/&lt;instance&gt; déclaré à l'adaptateur<br/>Vercel : pagefind-adapter.mjs"]
  BROWSER["Navigateur<br/>PagefindSearch.tsx : préchauffe,<br/>variantes accentuées, structures en tête"]
  NEXT --> PF --> OUT
  OUT -->|"pnpm build:&lt;instance&gt;"| PUBLIC
  OUT -->|"scripts/vercel-build.mjs"| STATIC
  PUBLIC --> BROWSER
  STATIC --> BROWSER`}
/>

Les deux pièges rencontrés en déployant pour de vrai (index non déployé, liens de résultats en 404) sont racontés dans [Déploiement Vercel](/exploitation/deploiement-vercel) et [ADR 009](/decisions/recherche-pagefind).

---

## ⚖️ Les décisions derrière l'architecture

| Décision                                                     | Ce qu'elle fixe                                                         |
| ------------------------------------------------------------ | ----------------------------------------------------------------------- |
| [ADR 007](/decisions/instances-marque-blanche)               | Instances en marque blanche : un fichier de configuration, deux logos   |
| [ADR 008](/decisions/chaine-de-donnees-ouvertes)             | Chaîne de données sur sources ouvertes, brut conservé                   |
| [ADR 009](/decisions/recherche-pagefind)                     | Recherche Pagefind en version 1, Meilisearch si le besoin apparaît      |
| [ADR 012](/decisions/version-anglaise)                       | Version anglaise sous `/en`, français sans préfixe                      |
| [ADR 013](/decisions/liste-officielle-et-annuaire-generique) | L'annuaire de l'établissement comme liste officielle, parseur générique |
