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/page.tsx                 le tableau de bord connecté
    admin/page.tsx               derrière ADMIN_EMAILS
    blog/                        articles MDX
    sign-in/page.tsx
    layout.tsx                   polices, langue, thème, providers
    globals.css                  tous les tokens de design
    sitemap.ts  robots.ts  icon.tsx  opengraph-image.tsx
  components/
    ui/                          Card, Field : les deux que vous réutiliserez
    SignInForm  SignOutButton  LocaleSwitcher  CopyField  Logo  Icons
  lib/
    auth.ts                      currentUser, requireUser
    supabase/server.ts           les deux clients serveur
    supabase/client.ts           le client navigateur
    stripe.ts  email.ts  blog.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é des textes
content/blog/                    les articles sont des fichiers
supabase/schema.sql              tables, policies, triggers
scripts/setup.mjs  scripts/db-push.mjs
proxy.ts                         s'exécute à 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.