Files
lage-chat-control/ADR.md
T

84 lines
4.8 KiB
Markdown
Raw Normal View History

# 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é).