84 lines
4.8 KiB
Markdown
84 lines
4.8 KiB
Markdown
|
|
# 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é).
|