Start here

Arrows to move, enter to open, escape to close.

Ship/Now

Pour commencer · 3 min

Structure du projet

Où tout se trouve et, plus utile encore, où regarder quand quelque chose de précis est cassé.

src/
  app/
    api/checkout/route.ts        ouvre une session Stripe Checkout
    api/webhooks/stripe/route.ts la livraison : le seul endroit où une vente devient réelle
    auth/callback/route.ts       transforme un lien magique en cookie de session
    app/layout.tsx               la coque connectée. requireUser tourne ici, donc
                                 toute route en dessous est protégée
    app/page.tsx                 le tableau de bord
    app/settings/                profil, langue, suppression du compte
    admin/layout.tsx             requireAdmin tourne ici, même raisonnement
    admin/                       derrière ADMIN_EMAILS
    blocks/                      la galerie de blocs et trois gabarits de page.
                                 Développement seulement, voir Composants
    blog/                        articles MDX
    blog/feed.xml/route.ts       le flux RSS, bâti sur les mêmes articles
    sign-in/page.tsx
    layout.tsx                   polices, locale, thème, providers
    globals.css                  tous les tokens de design
    sitemap.ts  robots.ts  icon.tsx  opengraph-image.tsx
  components/
    blocks/                      quinze sections de page. À copier, pas à configurer
    ui/                          Card, Field : les deux que vous réutiliserez
    OAuthButtons  SignInForm  SignOutButton  LocaleSwitcher  CopyField
  lib/
    auth.ts                      currentUser, requireUser
    admin.ts                     la liste d'accès. server-only, délibérément
    validation.ts                schémas Zod partagés par le formulaire et l'action
    ratelimit.ts                 adossé à Postgres, échoue en laissant passer
    observability.ts             Sentry ou Datadog derrière une seule interface
    supabase/server.ts           les deux clients serveur
    supabase/client.ts           le client navigateur
    stripe.ts  email.ts  blog.ts  store.ts  i18n.ts  i18n.server.ts
  paraglide/                     généré. Ne jamais éditer, ne jamais relire
messages/
  en.json  fr.json               la source de vérité pour les textes
content/blog/                    les articles, en fichiers
supabase/schema.sql              tables, politiques, triggers
e2e/                             Playwright, contre un vrai build
scripts/setup.mjs  scripts/db-push.mjs  scripts/doctor.mjs
Dockerfile  compose.yaml         multi étages, sans root
proxy.ts                         tourne à chaque requête

Où regarder quand

SymptômeFichier
Connecté, puis déconnecté aussitôtproxy.ts, puis auth/callback/route.ts
Le lien magique s'ouvre et ne fait rienLes modèles d'e-mail Supabase, voir Authentification
Paiement passé, mais rien ne s'est produitapi/webhooks/stripe/route.ts et le journal d'événements Stripe
Mauvais montant débitéapi/checkout/route.ts. Le prix vient de la base, jamais de la requête
Le texte affiche {name} littéralementmessages/*.json, voir Internationalisation
Un token de couleur ne fait rienapp/globals.css. Un token doit être déclaré dans @theme avant que Tailwind n'émette la classe
Un utilisateur lit la ligne d'un autresupabase/schema.sql. C'est une policy, pas du code applicatif

proxy.ts

Next.js 16 a renommé le middleware. Le fichier s'appelle proxy.ts, à la racine, et il exporte proxy, pas middleware. Si vous copiez un extrait d'un article écrit avant le renommage, c'est pour cela qu'il ne fait rien.

Il s'exécute à chaque requête et fait une seule chose : rafraîchir le cookie d'authentification. Les Server Components ne peuvent pas écrire de cookies, donc sans lui une session expire en pleine visite et l'utilisateur est déconnecté au milieu du paiement.

src/paraglide

Généré par le compilateur de messages. Le dossier est commité pour qu'un clone propre se construise sans lancer le compilateur d'abord, mais vous ne l'éditez jamais et il n'y a aucun intérêt à le lire dans un diff. Si vous voyez trois cents fichiers modifiés là-dedans, c'est que vous avez ajouté un message.

Les deux clients Supabase

C'est la distinction qui piège, elle vaut la peine d'être apprise tôt.

supabaseServer()  // agit comme l'utilisateur connecté. RLS s'applique. Par défaut.
supabaseAdmin()   // agit comme le rôle de service. RLS ne s'applique pas.

supabaseAdmin() existe pour le webhook, qui n'a pas d'utilisateur et doit écrire des lignes qu'aucun utilisateur n'a le droit d'écrire. Y recourir parce qu'une requête n'a rien renvoyé, c'est ainsi qu'on livre une application où chaque utilisateur lit toutes les lignes. Si supabaseServer() ne renvoie rien, le bug est dans la policy.

Une erreur ou un manque sur cette page ? Dites-le-nous.