Files
_Assistant_Lead_Tech/knowledge/backend/risques/nextjs.md
MaksTinyWorkshop b3417ad77b capitalisation: intégration ~60 entrées RL799_V2 (triage 2026-05-02)
Triage du 95_a_capitaliser.md (~75 propositions) :
- 60 entrées intégrées dans knowledge/ (backend, frontend, workflow)
- 4 nouveaux fichiers : backend/patterns/tests.md, backend/risques/tests.md,
  frontend/patterns/general.md, workflow/patterns/general.md
- 6 doublons rejetés
- Mise à jour des READMEs index pour refléter les nouvelles entrées
- 95_a_capitaliser.md restauré à sa structure initiale
- 40_decisions_et_archi.md : décision mono-tenant déployable vs SaaS multi-tenant
- 90_debug_et_postmortem.md : sub-agents Write indisponible, effet iceberg CI,
  prisma migrate diffs cosmétiques

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 22:12:44 +02:00

8.0 KiB

Backend — Risques & vigilance : Next.js

Extrait de la base de connaissance Lead_tech. Voir knowledge/backend/risques/README.md pour l'index complet.


Prisma initialisé au chargement de module — casse le build Next.js

Risques

  • Un import global qui initialise Prisma immédiatement peut faire échouer la collecte de pages/routes au build si DATABASE_URL n'est pas disponible dans l'environnement de build

Symptômes

  • PrismaClientInitializationError ou Error: Environment variable not found: DATABASE_URL au next build
  • L'app tourne en dev mais le build CI échoue

Bonnes pratiques / mitigations

  • Préférer une initialisation lazy-safe : retarder l'accès DB au moment de l'appel métier

  • Retourner un proxy qui lève une erreur claire uniquement lors du premier accès réel à la DB

  • Ne jamais instancier new PrismaClient() au top-level d'un module importé par Next.js

  • Contexte technique : Next.js App Router / Prisma — app-template-resto 16-03-2026


server-only dans les repositories — bloque les tests unitaires

Risques

  • import "server-only" empêche l'exécution des fichiers hors runtime Next.js
  • Les tests Node.js échouent avec Error: This module cannot be imported from a Client Component module

Symptômes

  • Tests qui passent via le dev server mais échouent via jest en mode node
  • Erreur au require() d'un repository depuis un test unitaire

Bonnes pratiques / mitigations

  • Ne mettre server-only que dans les fichiers qui utilisent des APIs Next.js runtime (cookies(), headers(), redirect())

  • Ne pas mettre server-only dans les repositories purs (qui n'appellent que Prisma)

  • Alternative de secours : créer un stub node_modules/server-only/index.js no-op pour les tests

  • Contexte technique : Next.js App Router / Jest — app-template-resto 16-03-2026


Redirect vers la page désactivée elle-même (boucle infinie feature flags)

Risques

  • Une page désactivée redirige vers elle-même via le fallback — boucle infinie silencieuse absorbée par Next.js mais UX cassée

Symptômes

  • Page / désactivée → redirect vers buildLocalizedPath("home") = / → boucle
  • Next.js absorbe la boucle mais l'utilisateur voit un écran bloqué ou vide

Bonnes pratiques / mitigations

// Si la page est sa propre destination de fallback, ne pas rediriger
if (pageKey === "home") return null; // évite redirect home → home
return buildLocalizedPath(locale, "home");
  • Règle : dans tout mécanisme de redirection sur page désactivée, toujours vérifier que pageKey !== fallbackKey

  • Retourner null (accès non bloqué) plutôt que de boucler

  • Contexte technique : Next.js App Router / feature flags tenant — app-template-resto 17-03-2026


Server Action : self-request / loopback HTTP vers sa propre API

Risques

  • Latence réseau inutile (aller-retour HTTP interne)
  • Fragilité sur APP_URL en environnement Docker (loopback non résolu)
  • Double authentification (cookies reconstitués manuellement)
  • Surface d'attaque SSRF

Symptômes

  • fetch(process.env.APP_URL + '/api/...') dans une Server Action
  • Reconstitution manuelle de cookies de session dans l'appel

Bonnes pratiques / mitigations

  • Une Server Action peut importer et appeler directement des modules marqués server-only sans fetch interne — les deux s'exécutent côté serveur.

  • Règle : si tu te retrouves à reconstituer des cookies de session pour faire un fetch vers ta propre API depuis une Server Action, c'est le signal que l'appel doit être direct.

  • Contexte technique : Next.js App Router / Server Actions — app-template-resto 31-03-2026


Écriture atomique (tmp + rename) : EXDEV si tmp sur device différent

Risques

  • rename() lève EXDEV si le fichier temporaire et la destination sont sur deux devices différents (cas courant Docker bind-mount).
  • L'erreur survient uniquement en production (Docker) — invisible en dev local.

Symptômes

  • Error: EXDEV: cross-device link not permitted, rename '/tmp/...' → '/data/...'
  • Upload de fichier fonctionnel en dev, cassé en production Docker

Bonnes pratiques / mitigations

  • Créer le fichier temporaire dans le même répertoire que la destination finale, pas dans os.tmpdir().

  • S'assurer que le répertoire cible existe avant l'écriture du fichier temporaire.

  • Règle : os.tmpdir() est interdit pour les fichiers qui seront renommés vers un volume Docker bind-mounté.

  • Contexte technique : Node.js / Docker / fichiers media — app-template-resto 31-03-2026


CSP strict casse les routes HTML dans une API Next.js

Risques

  • Appliquer un CSP strict (default-src 'self') via headers() dans next.config.ts sur toutes les routes /api/* casse les routes qui servent du HTML avec des dépendances externes (Swagger UI, pages de documentation, etc.)

Symptômes

  • La page HTML se charge mais reste blanche — les scripts et styles externes sont bloqués silencieusement par le navigateur

Bonnes pratiques / mitigations

  • Quand on ajoute des headers de sécurité via un pattern global, vérifier s'il existe des routes qui servent du HTML (pas uniquement du JSON)

  • Si oui, ajouter une règle dédiée plus spécifique en premier dans le tableau headers() (Next.js matche dans l'ordre de déclaration) avec un CSP adapté

  • Factoriser les headers communs dans une constante partagée

  • Contexte technique : Next.js / CSP — RL799_V2 08-04-2026


Middleware Next.js — faux argument "Edge Runtime incompatible" pour éviter les imports

Risques

  • Dupliquer la logique métier dans middleware.ts au lieu d'importer depuis src/lib/ sous prétexte que "Edge Runtime ne supporte pas les imports cross-boundary"
  • C'est faux pour les modules purs (pas de fs, child_process, crypto Node-only, etc.)

Symptômes

  • Logique dupliquée entre middleware et utilitaires, dérive garantie à la prochaine modification
  • Commentaire dans le code justifiant la duplication par une incompatibilité Edge non vérifiée

Bonnes pratiques / mitigations

  • Le middleware Next.js peut importer n'importe quel module local tant que celui-ci n'utilise que des API compatibles Edge (Web APIs, process.env, opérations JS pures)

  • Factoriser la logique partagée dans un module commun et l'importer depuis le middleware

  • Signal review : logique dupliquée dans middleware.ts avec un commentaire "Edge incompatible"

  • Contexte technique : Next.js / middleware — RL799_V2 08-04-2026


App Router — dossiers _* exclus silencieusement du routing

Risques

  • Tout segment d'URL préfixé par _ (ex : _e2e, _helpers, __internal) est traité par Next.js App Router comme un private folder et exclu silencieusement du routing
  • Le route.ts ou page.tsx existe sur le filesystem, le typecheck passe, mais l'URL retourne 404
  • Aucune erreur au boot, aucun warning

Symptômes

  • "Ma route existe pourtant je vois le fichier" — apps/api/src/app/api/__e2e/visitor-token/route.ts qui retourne 404
  • Temps de debug perdu à chercher une cause obscure

Bonnes pratiques / mitigations

  • Ne jamais préfixer un segment de route par _ ou __ même pour signaler une intention "interne / e2e / debug"

  • Utiliser des noms explicites : /api/e2e/, /api/internal/, /api/dev/ (sans underscore initial)

  • Pour gater l'accès en prod : check process.env au début du handler (if (process.env.E2E !== '1') return 404)

  • Référence : Next.js docs — Project Structure → Private folders. Convention héritée de l'écosystème React/Webpack pour exclure les dossiers de la résolution

  • Contexte technique : Next.js App Router — RL799_V2 30-04-2026