expria-frontend/docs/adr/006-stack-versions-2026.md
Hermann_Kitio b68f160bce feat(design-system): reskin Charcoal — tokens dark-default + sidebar navy permanent
- Remplacement intégral index.css par palette Charcoal (DESIGN_SYSTEM.md v2.0)
- Dark = thème par défaut, .light = override via @custom-variant light
- Sidebar navy #0C1528 permanent (identique dark+light)
- Script anti-FOUC inline dans index.html
- Layout : radial-gradient sur <main>, sidebar 230px, max-w-[1100px]
- Renommage tokens Boréal→Charcoal sur ~45 composants
- Inversion dark: → baseline + light: sur primitives shadcn
- Fix logo blanc forcé dans sidebar
- ADR 006 mis à jour

Typecheck: OK · Tests: 122/122 

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:09:15 +03:00

12 KiB

ADR 006 — Stack frontend : versions 2026 (React 19, Vite 8, TypeScript 6, Tailwind 4, RR7)

Statut : Accepté — mis à jour Sprint 0.5 Date : 2026-04-17 Décideur : Hermann Contexte : Révélé par l'état des lieux Claude Code au démarrage du Sprint 0 frontend


Contexte

La première version d'ARCHITECTURE.md §2 listait une stack basée sur les versions "connues stables" :

  • React 18
  • Vite 5
  • TypeScript 5
  • Tailwind 3
  • React Router v6

L'état des lieux effectué par Claude Code au démarrage du Sprint 0 (2026-04-17) a révélé que le scaffold installé plusieurs semaines auparavant utilisait des versions plus récentes :

  • React 19.2.4
  • Vite 8.0.4
  • TypeScript 6.0.2
  • Tailwind 4.2.2
  • React Router v7.14.1

Cette divergence doit être résolue : soit downgrader le scaffold, soit mettre à jour la documentation.

Options envisagées

Option A — Downgrader vers les versions de la doc originale

Aligner le scaffold sur React 18, Vite 5, TypeScript 5, Tailwind 3, React Router v6.

  • Avantages : documentation historique respectée, versions "éprouvées" en production.
  • Inconvénients :
    • Casse un node_modules qui fonctionne
    • Perd l'optimisation du compilateur React 19 (Actions, useOptimistic)
    • Perd le moteur Oxide de Tailwind 4 (builds 3,5x plus rapides)
    • Perd le typage strict amélioré de TypeScript 6
    • Downgrade effectué pour des raisons qui n'existent plus (les versions récentes sont matures en avril 2026)

Option B — Mettre à jour la documentation

Accepter les versions installées et mettre à jour ARCHITECTURE.md §2 pour refléter la réalité.

  • Avantages :
    • Préserve le travail de scaffold déjà fait
    • Bénéficie des améliorations de performance des versions récentes
    • Écosystème mature : shadcn/ui supporte complètement Tailwind 4 et React 19 depuis début 2025
    • Alignement avec l'écosystème 2026 (les nouveaux tutoriels, docs, et ressources communautaires supposent ces versions)
  • Inconvénients :
    • Versions légèrement plus récentes = moins de StackOverflow disponible pour les cas exotiques
    • Mitigation : Claude Opus 4.7 connaît bien ces versions (cf. knowledge cutoff janvier 2026)

Option C — Hybride

Garder React 19, Vite 8, TypeScript 6 mais downgrader Tailwind 4 → 3 pour "compatibilité shadcn/ui classique".

  • Avantages : apparemment plus prudent.
  • Inconvénients : injustifié depuis que shadcn/ui supporte complètement Tailwind 4 avec configuration CSS-first via @theme. Ajoute de la complexité sans bénéfice.

Décision

Option B — accepter les versions installées et mettre à jour la documentation.

Stack frontend officielle au 2026-04-17

Couche Version Notes
React 19.2.x Server Components N/A (SPA pur), Actions et useOptimistic disponibles
React DOM 19.2.x
Vite 8.0.x Moteur Rolldown stable, config simplifiée
TypeScript 6.0.x Typage strict activé (voir tsconfig.app.json)
Tailwind CSS 4.2.x Configuration CSS-first via @theme, pas de tailwind.config.ts
@tailwindcss/vite 4.2.x Plugin Vite officiel (préféré au plugin PostCSS)
React Router v7.14.x Compatible API v6, data loaders disponibles
Supabase JS 2.103.x

Dépendances à ajouter lors du scaffold

Package Rôle Cf. ADR
@tanstack/react-query Cache serveur, refetch, mutations ARCHITECTURE.md §2
zod Validation des inputs formulaires SECURITY.md SEC-04
react-markdown Rendu sécurisé des rapports IA SECURITY.md SEC-05
class-variance-authority, clsx, tailwind-merge Utilitaires shadcn/ui
lucide-react Icônes (standard shadcn/ui)
Packages @radix-ui/react-* Primitives shadcn/ui (installés à la demande)
@sentry/react Monitoring TECH_DEBT.md FTD-07 (après MVP)

Dépendances de développement

Package Rôle
vitest Tests unitaires
@vitest/coverage-v8 Couverture
@testing-library/react Tests React
@testing-library/jest-dom Matchers DOM
@testing-library/user-event Simulation user
jsdom Environnement DOM pour Vitest
prettier Formatage
eslint-config-prettier Intégration ESLint ↔ Prettier

Configuration Tailwind 4

Pas de tailwind.config.ts. La configuration se fait exclusivement dans src/index.css.

Mode thème (mis à jour Sprint DA Charcoal — 2026-04-24)

Dark est le thème par défaut. Les tokens de contenu (--color-canvas, --color-ink-*, etc.) sont déclarés en mode dark dans @theme. Une classe .light sur <html> active le mode clair en override. Configuré via :

@custom-variant light (&:where(.light, .light *));

Ce variant permet d'écrire light:bg-surface dans les composants quand un comportement spécifique au mode clair est requis (ex. primitives shadcn où l'opacité doit être adaptée).

Tokens @theme (DA Charcoal — validée Sprint DA Charcoal 2026-04-24)

@import 'tailwindcss';
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');

@custom-variant light (&:where(.light, .light *));

@theme {
  /* ── Invariants (identiques dark + light) ── */

  /* Sidebar navy permanent */
  --color-sidebar-bg:              #0C1528;
  --color-sidebar-border:          rgba(255, 255, 255, 0.07);
  --color-sidebar-text:            rgba(255, 255, 255, 0.6);
  --color-sidebar-text-hover:      rgba(255, 255, 255, 0.9);
  --color-sidebar-text-active:     #FFFFFF;
  --color-sidebar-nav-hover:       rgba(255, 255, 255, 0.07);
  --color-sidebar-nav-active:      rgba(255, 255, 255, 0.1);
  --color-sidebar-section-label:   rgba(255, 255, 255, 0.3);

  /* Brand */
  --color-brand:        #1B4FD8;
  --color-brand-hover:  #1744B8;
  --color-brand-active: #13379C;
  --color-brand-dark:   #1740B0;
  --color-brand-ink:    #FFFFFF;

  /* Semantic (invariants) */
  --color-warning:       #F59E0B;
  --color-warning-soft:  rgba(245, 158, 11, 0.12);
  --color-danger:        #EF4444;
  --color-danger-soft:   rgba(239, 68, 68, 0.12);

  /* Typographie */
  --font-sans: "Plus Jakarta Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;

  /* Rayons (override Tailwind) */
  --radius-xs: 6px;  --radius-sm: 8px;  --radius-md: 12px;
  --radius-lg: 16px; --radius-xl: 20px; --radius-pill: 999px;

  /* Focus */
  --shadow-focus: 0 0 0 3px rgba(27, 79, 216, 0.18);

  /* ── Dark mode (défaut) ── */
  --color-canvas:           #111111;
  --color-surface:          rgba(255, 255, 255, 0.035);
  --color-surface-hover:    rgba(255, 255, 255, 0.055);
  --color-surface-solid:    #1E1E1E;
  --color-surface-raised:   #222222;
  --color-border:           rgba(255, 255, 255, 0.06);
  --color-border-strong:    rgba(255, 255, 255, 0.12);

  --color-ink-primary:      #E5E5E5;
  --color-ink-secondary:    rgba(255, 255, 255, 0.55);
  --color-ink-tertiary:     rgba(255, 255, 255, 0.3);
  --color-ink-inverse:      #111111;

  --color-brand-soft:       rgba(27, 79, 216, 0.1);
  --color-brand-text:       #7DA4F0;

  --color-success:          #4ADE80;
  --color-success-soft:     rgba(74, 222, 128, 0.12);

  --color-topbar-bg:        rgba(17, 17, 17, 0.88);
  --color-gradient-a:       rgba(27, 79, 216, 0.05);
  --color-gradient-b:       rgba(27, 79, 216, 0.03);

  --shadow-card:    none;
  --shadow-raised:  none;
}

/* Light mode — override sur <html class="light"> */
.light {
  --color-canvas:         #F3F4F6;
  --color-surface:        #FFFFFF;
  --color-surface-hover:  #F8F9FB;
  --color-surface-solid:  #FFFFFF;
  --color-surface-raised: #FFFFFF;
  --color-border:         rgba(0, 0, 0, 0.07);
  --color-border-strong:  rgba(0, 0, 0, 0.14);

  --color-ink-primary:    #0F0F1A;
  --color-ink-secondary:  rgba(0, 0, 0, 0.55);
  --color-ink-tertiary:   rgba(0, 0, 0, 0.3);
  --color-ink-inverse:    #FFFFFF;

  --color-brand-soft:     rgba(27, 79, 216, 0.06);
  --color-brand-text:     #1B4FD8;

  --color-success:        #16A34A;
  --color-success-soft:   rgba(22, 163, 74, 0.1);

  --color-topbar-bg:      rgba(243, 244, 246, 0.88);
  --color-gradient-a:     rgba(27, 79, 216, 0.025);
  --color-gradient-b:     rgba(27, 79, 216, 0.01);

  --shadow-card:   0 1px 2px rgba(15, 18, 32, 0.04), 0 1px 8px rgba(15, 18, 32, 0.03);
  --shadow-raised: 0 4px 16px rgba(15, 18, 32, 0.06), 0 1px 2px rgba(15, 18, 32, 0.04);
}

Classes Tailwind générées

Les tokens @theme créent des classes utilitaires directement utilisables :

Token Classes Tailwind
--color-canvas bg-canvas, text-canvas, border-canvas
--color-surface bg-surface, border-surface
--color-surface-hover bg-surface-hover
--color-sidebar-bg bg-sidebar-bg (navy permanent, identique dark+light)
--color-ink-primary text-ink-primary
--color-ink-secondary text-ink-secondary
--color-ink-tertiary text-ink-tertiary
--color-brand bg-brand, border-brand, ring-brand
--color-brand-text text-brand-text (bleu adapté au fond — #7DA4F0 dark, #1B4FD8 light)
--color-brand-soft bg-brand-soft (teinte chip / highlight discret)
--color-success-soft, -warning-soft, -danger-soft bg-success-soft, etc.
--shadow-card, --shadow-raised shadow-card, shadow-raised (auto dual-theme : none en dark, ombre en light)
--shadow-focus shadow-focus (halo bleu 3px sur :focus-visible)

Conventions critiques :

  • bg-surface = cards / modals / panels. bg-canvas = fond de page. Ne jamais inverser.
  • bg-sidebar-bg = navy permanent — ne change jamais entre dark et light (ancre visuelle de marque).
  • Utiliser le préfixe light: uniquement quand un override spécifique au mode clair est strictement nécessaire (ex. primitives shadcn où l'opacité d'une couleur sémantique diffère).

Typographie

Plus Jakarta Sans chargée via Google Fonts dans index.html (preconnect + stylesheet, weights 400/500/600/700). Migration vers auto-hébergement (@fontsource/plus-jakarta-sans) après MVP si les performances réseau deviennent un enjeu.

shadcn/ui avec Tailwind 4

La CLI shadcn/ui supporte Tailwind 4 depuis début 2025 :

npx shadcn@latest init
npx shadcn@latest add button dialog form

Les composants générés utilisent les conventions Tailwind 4 (pas de forwardRef, attributs data-slot). Le fichier de configuration reste components.json à la racine.

Conséquences

Positives :

  • Pas de perte de travail sur le scaffold existant
  • Performances optimales (build Tailwind 4 : microsecondes sur builds incrémentaux)
  • Stack aligné sur l'écosystème 2026 — facile pour un dev externe qui arrivera
  • Compilateur React 19 apporte des optimisations gratuites

Négatives :

  • Les versions récentes peuvent avoir quelques bugs non encore découverts. Mitigation : mise à jour ponctuelle vers la dernière version patch en cas de bug signalé (ex : 19.2.4 → 19.2.5).
  • Si un dev arrive avec une expertise sur React 17/18 uniquement, courbe d'apprentissage légère. Mitigation : ONBOARDING.md liste les ressources officielles pour React 19 et Tailwind 4.

À revisiter si :

  • Une faille de sécurité critique apparaît dans une version spécifique
  • Une incompatibilité bloquante est découverte entre deux packages (peu probable en avril 2026)

Actions de mise en cohérence

  1. Mettre à jour ARCHITECTURE.md §2 avec les versions ci-dessus (réalisé en session actuelle)
  2. Mettre à jour ONBOARDING.md pour référencer React 19 et Tailwind 4 dans les ressources (à faire)
  3. Aucune action sur TESTS_AUTOMATISES.md — Vitest fonctionne identiquement
  4. Aucune action sur les ADRs 001-005 — ils ne référencent pas de versions précises

Références