Centre d'aide — articles Markdown, recherche, i18n
Un centre d'aide est un petit site statique avec une exigence impérative : chaque
article doit être accessible — depuis la barre latérale, depuis la recherche, depuis une locale
traduite qui ne l'a pas encore. Écrit par l'ingénieur qui a livré ce module ;
l'implémentation précédente était un centre d'aide pour site marketing. Le
module ci-dessous vérifie cette exigence comme des propriétés validées : la barre latérale affiche
chaque article de chaque catégorie, la recherche classe une requête quelle que soit sa saisie,
les liens connexes se résolvent ou le validateur échoue la build. Les suites de chargeur, de
recherche et de tags couvrent chacune ; l'historique se trouve dans references/provenance.md.
Quand l'utiliser
Construire ou étendre un centre d'aide, une section de documentation ou une base de connaissances dont les articles sont des fichiers Markdown dans le dépôt, sur Next.js App Router, avec ou sans plusieurs locales.
Quand NE PAS l'utiliser
- Un blog. Des articles datés, avec auteurs, couvertures et slugs localisés sont un modèle de contenu différent ; gardez le module de blog de l'hôte.
- Documentation générée à partir de code (OpenAPI, TypeDoc) — utilisez leurs générateurs et liez vers la sortie.
- Un site d'aide basé sur un CMS dont les éditeurs publient en runtime — le contrat d'index s'applique toujours, mais le chargeur, les paramètres statiques et la validation changent ; voir la note CMS dans extensions.md.
- Des pages marketing qui sont Markdown. Réutilisez le rendu de l'hôte ; ce module est la navigation, la recherche et le modèle de locale autour de nombreux articles.
Architecture
content/help/<[locale]/><category>/<slug>.md
│ gray-matter + normalisation
▼
getHelpIndex(locale) ── React cache() : une analyse par requête ──┐
categories · articles (triés) · byKey · tags · byTag · ignorés │
│ │
├─► pages : accueil / catégorie / tag / article ── métadonnées, JSON-LD, canonical/hreflang
├─► HelpShell ── toSummary → arbre de navigation (barre latérale + tiroir)
│ ── toSearchDoc → HelpSearch (client, recherche par préfixe tokenisée)
├─► helpSitemapEntries()
└─► validate:help (CI) ── références non résolues, égalités d'ordre, mauvaises dates, mauvais slugs, dérive de tags
Tout lit à partir de l'index. Rien d'autre n'accède au système de fichiers.
Faits critiques
- Le système de fichiers est le schéma. Dossier = catégorie, nom de fichier = slug, et
le frontmatter n'est que des métadonnées.
slug/categorydans le frontmatter sont validés par rapport au chemin, jamais utilisés. - Seuls les résumés traversent vers le client.
toSummary/toSearchDocsuppriment le corps ; passerHelpArticleà un composant client envoie tout le corpus dans chaque page. - Une page non traduite est un doublon. Elle s'affiche à partir de la locale par défaut, garde sa place dans la navigation, montre un avis, canonicalise vers l'URL de la locale par défaut, et est absente de hreflang et du sitemap.
- Le runtime pardonne ; pas la CI. Les mauvaises références sont ignorées, les ordres
manquants sont triés en dernier — et
validate:helpéchoue la build pour l'auteur. - La recherche est côté client par conception. ~1 Ko par article, déjà dans la page pour la navigation, résultats sur la première frappe. La recherche dans le corps est une extension.
Règles strictes
Ne jamais limiter la hauteur d'une liste repliable. Un
max-h-*+overflow-hiddencoupe ce qui ne tient pas et ne signale rien. Utilisezhiddenou une primitive repliable réelle, afin qu'une liste affiche chaque lien ou aucun.
Ne jamais trier uniquement par
order. Les égalités tombent sous l'ordre dereaddir, qui diffère entre les systèmes de fichiers. Brisez les égalités par titre, puis slug.
Ne jamais résoudre
relatedsans le valider. Une référence supprimée est invisible sur la page ; le validateur est le seul endroit où un auteur apprend qu'un slug a été renommé.
Ne jamais chercher une requête non nettoyée, et ne jamais chercher uniquement le titre. Nettoyez, tokenisez, repliez les diacritiques, incluez les tags et titres, classez par champ.
Ne jamais coder en dur les chaînes de chrome dans un hôte avec un système i18n. Chaque chaîne passe par
HelpStrings, afin que l'en-tête, le pied de page et les avis changent de locale ensemble.
Ne jamais indexer un tag par son orthographe. La casse, les tirets et les pluriels dérivent entre auteurs. Regroupez par
tagSlugafin que chaque variante atterrisse sur une page, et laissez le validateur signaler la dérive.
Démarrage rapide
- Remplissez le contrat d'adaptation et fixez les IDs de catégorie — adaptation.md.
- Choisissez la disposition du contenu et écrivez la configuration — content-model.md.
- Copiez le chargeur et l'analyseur frontmatter ; exécutez le validateur sur le contenu réel immédiatement — content-loader.md.
- Connectez les chaînes et chemins à l'i18n de l'hôte — i18n.md.
- Ajoutez les trois pages, les aides SEO et les entrées de sitemap — routes.md — puis la page de tag et les puces liées — tags.md.
- Construisez la coque, l'arbre de navigation et le tiroir — ui.md — puis le fil d'Ariane, les cartes, les listes et le rendu sur les primitives de l'hôte — ui-content.md.
- Intégrez la recherche et son hook ; connectez le hook de résultat zéro à l'analytique — search.md.
- Exécutez les tests fournis, puis vérifiez le contrat de comportement : catégorie la plus longue entièrement accessible, requête avec espace de fin, requête accentuée, canonical de page non traduite.
Répertoire de références
| Scénario | Mots-clés de déclenchement | Référence |
|---|---|---|
| Intégration dans une application existante | adapter, couture, renommer catégories, sondage hôte, intégrer, dépendances | adaptation.md |
| Frontmatter, dossiers, slugs, validation | frontmatter, slug, catégorie, ordre, lié, updatedAt, en vedette, valider, CI | content-model.md |
| Lecture des fichiers dans l'index | chargeur, gray-matter, cache, repli, titres, trier, index, fs | content-loader.md |
| Champ de recherche et classement | recherche, combobox, classement, tokeniser, diacritiques, préfixe, clavier, aucun résultat | search.md |
| Tags, pages de tag, puces, nuage de tags | tag, tags, page de tag, puce, slug de tag, orthographe, pluriel, parcourir par tag | tags.md |
| Locales, chaînes, dates, canoniques | i18n, locale, traduction, repli, hreflang, chaînes, pluriel, Intl | i18n.md |
| Pages, métadonnées, JSON-LD, sitemap | route, page.tsx, generateStaticParams, dynamicParams, notFound, canonical, TechArticle, sitemap | routes.md |
| Coque, en-tête, barre latérale, tiroir | layout, barre latérale, menu mobile, tiroir, repliable, collant, HelpShell | ui.md |
| Fil d'Ariane, cartes, listes, rendu, hooks de style | fil d'Ariane, carte de catégorie, liste d'articles, react-markdown, data-help, style | ui-content.md |
| Au-delà du module livré | plein texte, Pagefind, TOC, retour, dates git, MDX, CMS, redirections | extensions.md |
| Pourquoi les modèles diffèrent de l'implémentation précédente | provenance, audit, registre, conservé délibérément, correction de l'implémentation précédente | provenance.md |