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>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# 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é).
|
||||
Reference in New Issue
Block a user