Files
lage-chat-control/ADR.md
T
sucupira db5a997e50 feat(oki): fondations de la migration vers la stack souveraine OKI
Architecture décidée et documentée dans ADR.md : SvelteKit natif en
fichiers plats plutôt que Strapi (55 outils, données statiques,
souveraineté et budget performance prioritaires — doctrine §1.2, §4.4).

- frontend/ : SvelteKit 2 + Svelte 5 (runes), adapter-static, 58 pages
  prérendues, CSS natif en @layer (reset→tokens→base→layouts→components),
  tokens oklch(), container queries, typo fluide clamp(), 2 polices WOFF2
  auto-hébergées (Atkinson Hyperlegible, Fraunces), zéro CDN tiers
- i18n FR/gcf typé (clé manquante = erreur de build), bascule Kréyòl
  persistée en localStorage, micro-textes créoles (« Ou pa manké ayen »)
- Composants : ToolCard, DifficultyBadge (forme+texte+couleur, jamais la
  couleur seule), CategoryNav (≤5 entrées, divulgation progressive),
  SearchBar (raccourci /), LanguageSwitcher, EndMarker
- content/ : 55 fiches migrées depuis src/ (script frontend/scripts/
  migrate-tools.mjs, idempotent), licences SPDX reprises de directory.json
- docs/ : DESIGN_SYSTEM.md et CONTENT_GUIDE.md

Budgets vérifiés : JS 41 Ko gzip, CSS 2,9 Ko gzip, svelte-check 0 erreur.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:51:17 -04:00

4.8 KiB

ADR-001 — Backend : SvelteKit natif (fichiers plats), pas de Strapi

Statut : accepté · Date : 2026-07-10 · Décideur : migration OKI d'exitchatcontrol.org Doctrine de référence : ui-ux-souveraine-oki.md (citée « doctrine §x.y » ci-dessous)

Contexte

exitchatcontrol.org est un annuaire de ~55 outils libres répartis en 23 sections thématiques, actuellement généré statiquement par Astro à partir de fichiers versionnés (src/data/*.json, src/content/sections/*/*.mdx). Le déploiement cible est un conteneur nginx auto-hébergé (YunoHost/Docker), sans backend.

Deux options étaient sur la table (mission §2.1) :

  • Option A : Strapi v5 headless, base relationnelle, admin web, API, i18n plugin.
  • Option B : SvelteKit full-stack, contenu en fichiers Markdown/JSON versionnés, parsés au build, site prérendu.

Décision

Option B — SvelteKit 2 + Svelte 5, contenu en fichiers plats prérendus.

Justification par la règle de décision

La règle imposée : minimiser la charge cognitive extrinsèque (doctrine §1.2, Sweller) pour l'utilisateur final ET l'administrateur, dans le budget performance (doctrine §4.4).

  1. Les données sont déjà statiques et versionnées. 55 outils, mises à jour par pull request espacées de plusieurs jours/semaines (historique git). Le seuil « le volume de données justifie une base relationnelle » posé comme condition de l'option A n'est pas atteint — 55 fiches tiennent dans un dossier de fichiers Markdown lisibles à l'œil nu.
  2. Charge d'administration. Strapi = un service Node persistant + une base + des migrations de schéma + des mises à jour de sécurité + des sauvegardes. Pour l'admin OKI, c'est de la charge extrinsèque pure : la tâche réelle (« corriger une fiche ») devient « se connecter à un admin, naviguer un CMS, publier, invalider un cache ». En fichiers plats : éditer un fichier, commit. Le git devient l'historique éditorial, la revue par PR devient la modération.
  3. Budget performance (doctrine §4.4). Site 100 % prérendu : premier rendu = HTML servi par nginx, zéro requête API, JS initial minimal (hydratation sélective). Strapi n'aiderait pas mais ajouterait un point de latence et de panne si l'on cédait à la tentation du rendu à la demande.
  4. Souveraineté et surface d'attaque. Un site statique n'a pas de CVE de CMS, pas de compte admin à voler, pas de base à exfiltrer. C'est la posture cohérente avec le sujet même du site (OPSEC, résistance à la censure) : le site doit être mirrorable (un tarball du build suffit), ce qu'un Strapi rend impossible.
  5. Loi de Tesler (doctrine §1.3) : la complexité éditoriale n'est pas supprimée, elle est déplacée vers le format de fichier. On l'absorbe par un frontmatter strict + validation au build (le build échoue si une fiche est invalide — équivalent des types du CMS, sans le CMS).

Ce qui ferait rebasculer vers Strapi (critères de réversibilité)

  • Une équipe éditoriale non-technique de plusieurs personnes publiant chaque semaine ;
  • Des soumissions communautaires en volume nécessitant un workflow draft/publish ;
  • Plus de ~500 fiches ou des relations réellement complexes.

Dans ce cas, le modèle de données de la mission §3 s'applique tel quel ; le frontend SvelteKit resterait inchangé (il consommerait l'API au build). Étape intermédiaire possible sans backend : Decap CMS (git-based) sur le dossier content/ — écarté pour l'instant, « préférer la solution la plus simple ».

Décisions techniques associées

  • adapter-static + prerender total : parité avec le déploiement nginx actuel (Dockerfile conservé dans l'esprit). Un lien fonctionne sans JS (doctrine §4.4).
  • Markdown + frontmatter maison : parseur frontmatter minimal (~40 lignes, zéro dépendance) + marked (MIT) pour le corps, exécuté au build uniquement — rien de tout cela n'est expédié au client.
  • i18n maison typé (pattern repris du projet source) plutôt que Paraglide/inlang : ~40 lignes, dictionnaires JSON fr/gcf vérifiés par le compilateur TypeScript (une clé manquante = erreur de build). Paraglide reste la piste si le nombre de locales croît.
  • Langues : fr (défaut) + gcf (créole guadeloupéen, code ISO 639-3 enregistré BCP 47 valide). Micro-textes créoles d'abord (doctrine §4.2 : impact affectif disproportionné pour un coût faible) ; traduction intégrale des fiches = chantier éditorial séparé (voir docs/CONTENT_GUIDE.md).
  • CSS natif en @layer : reset → tokens → base → layouts → components → utilities (doctrine §5.2), tokens oklch(), container queries, clamp(). Pas de Tailwind (doctrine §5.2 option 4 : écarté en connaissance de cause).
  • Licence du code : MIT, comme le projet source (continuité).