Architecture

Marque blanche : créer et faire vivre une instance

En bref

une instance = un fichier instances/<id>/research.config.ts, deux logos, une entrée dans deux registres. Tout le reste (thème, libellés, navigation, données, recherche) en découle. Décision : ADR 007.

Ce que pilote la configuration

BlocEffet dans le site
siteNom, accroche et introduction (fr/en), URL canonique, langues publiées (locales), éditeur (©)
brand.logoLogo clair (en-tête) et foncé (pied de page)
brand.colors4 couleurs → thème Mantine calculé : brand (boutons, liens, titres de section), accent (surtitres, badges), ink (titres, pied de page), surface (fond)
brand.fontsPolices du texte et des titres (à charger dans src/app/globals.css)
perimeterIdentifiants dans chaque source ; annuaire institutionnel (directory) et liste maître (masterList)
groupsLibellé du niveau intermédiaire (« Graduate School », « Pôle disciplinaire »), liste, règles de rattachement
entitiesLibellés des types (« Laboratoires », « Unités de recherche ») ; navigation et pages
peopleRègle de publication des personnes (ADR 010)
themesThématiques transversales et leurs règles
sourcesSources actives, rôle et priorité
searchMoteur et types indexés

Créer une instance (exemple : ugA)

  1. Identifiants : chercher l'établissement dans ROR, scanR, OpenAlex, HAL (collection et structure AureHAL). Les requêtes utilisées pour Paris 1 sont dans sources.md.
  2. Configuration : copier instances/paris1/research.config.ts vers instances/<id>/, changer id, site, brand, perimeter, groups, themes.
  3. Logos : public/brand/<id>/logo.svg et logo-white.svg.
  4. Registres : ajouter l'instance dans src/config/index.ts (INSTANCES) et un port dans scripts/instance.mjs (PORTS), puis les scripts dev:<id>, build:<id>, start:<id> dans package.json.
  5. Polices : si elles diffèrent, ajouter le paquet @fontsource/… et ses @import dans globals.css.
  6. Données :
    TerminalCode
    pnpm data:probe --instance <id> # ce que les sources savent du périmètre (2 min) pnpm data:extract --instance <id> # moisson complète pnpm data:build --instance <id> # publication pnpm dev:<id>
  7. Contrôle : pnpm test (le test config.test.ts vérifie que chaque instance est valide et a un ROR distinct), puis lecture de /a-propos-des-donnees.

Brancher l'annuaire de l'établissement

Le parseur générique lit deux gabarits courants (ADR 013) :

TypeScriptCode
// Une page par structure (Paris-Saclay) directory: { url: 'https://www.universite-paris-saclay.fr/laboratoires', mode: 'pages', pagePattern: '^/laboratoires/.+', // chemins des fiches labels: { supervisors: 'Tutelles et partenaires', website: 'Site web du laboratoire', description: 'Présentation du laboratoire' }, }, // Une page liste avec une carte par unité (Paris 1) directory: { url: 'https://recherche.pantheonsorbonne.fr/structures-de-recherche/unites-de-recherche', mode: 'cards', cardMarker: 'class="sm-teaser"', // fragment HTML qui ouvre chaque carte useSitemap: false, }, masterList: 'directory', // l'annuaire devient la liste officielle

Pour vérifier un nouveau gabarit : pnpm data:extract --instance <id> --source annuaire, puis lire data/raw/<id>/annuaire/laboratories.ndjson et le rapport data/coverage/<id>/qualite.md.

Langues

Français sans préfixe, anglais sous /en (ADR 012). Chaque libellé Localized de la configuration prend un champ en. Les textes d'interface sont dans src/i18n/messages.ts.

Ce qui n'est pas encore configurable

  • Contenu juridique des pages légales : texte générique au nom de l'éditeur, à remplacer par instance.
  • Segments d'URL : en français dans les deux langues (/en/structures, /en/chercheurs).

Deux instances livrées

SaclayParis 1
Port local30003010
Pages générées23 4444 802
Pages indexées (Pagefind)12 2092 417
Génération des pages63 s (build complet : 2 min 23 s)7 s

Pourquoi ne pas reprendre scanR tel quel

Le code de scanR est public (dataesr/scanr-ui, licence MIT, mis à jour le 23/10/2026). Ce qu'on y lit :

AspectscanRConséquence pour nous
RenduApplication React + Vite rendue dans le navigateurPeu adapté au référencement d'une vitrine ; on garde Next.js (SSR/ISR)
DonnéesIndex Elasticsearch du MESR (scanr-organizations, -persons, -projects, -publications, -patents), via un proxy nginxOn réutilise ces données (sonde scanr), pas l'infrastructure
PersonnalisationVariables VITE_* (nom, bandeau), DSFR via @dataesr/dsfr-plusTrop limité pour une charte d'établissement ; d'où research.config.ts
HiérarchieLiens tutelle/participant du RNSR, à platNotre valeur propre : Graduate School, UFR, laboratoire
« Studio »Un scanR local fourni par le MESR pour une collection HALAlternative à évaluer en premier : si la vitrine se réduit à cela, demander le Studio (cf. audit, Valeur ajoutée)

À reprendre de scanR : la typologie des entités et des identifiants, la logique une page par entité avec ses liens, le découpage des index par type, et la liste des sources qu'il agrège.