Docs/Extra
// extra
Lavorare con l'AI sul codice
Il motivo per cui un boilerplate fa risparmiare tempo a un assistente AI non è che il codice è già scritto — è che le convenzioni sono già scritte. Nella root del repo c'è .cursorrules: un file di testo che Cursor carica ad ogni prompt, e che dice al modello com'è fatto questo progetto prima che tocchi un solo file. Accanto c'è CLAUDE_INSTRUCTIONS.md, la versione per Claude Code.
1. Cosa c'è dentro .cursorrules
Non sono quattro righe di buoni propositi. Il file apre con lo stack — Next.js 15 App Router, TypeScript 5.9, Supabase con Row Level Security, Stripe con webhook, Tailwind 4.1 con DaisyUI 5, Resend — e poi scende nel concreto con sezioni su convenzioni TypeScript, naming e struttura file, architettura dei componenti, ordine degli import, route handler, database, autenticazione, Stripe, variabili d'ambiente, gestione errori, performance, sicurezza e messaggi di commit.
La parte di struttura è quella che evita all'AI di inventarsi cartelle nuove:
### File Naming & Structure
- Use PascalCase for component names: ButtonCheckout
- API routes: /app/api/[feature]/route.ts
- Components: /components/ComponentName.tsx
- Pages: /app/[route]/page.tsx
- Types: /types/[feature].ts
- Utils/Libs: /libs/[utility].ts2. Le regole che cambiano davvero l'output
La maggior parte dei modelli ha in testa più codice Next.js 14 che 15, e Tailwind 3 che 4. Sono esattamente le due cose su cui .cursorrules insiste di più, perché sono quelle che producono codice che sembra giusto e non compila.
Su Next 15 diverse API sono diventate asincrone, e il file lo dice a chiare lettere:
### Async APIs
- headers() and cookies() now return Promises - always use await
- params in dynamic routes are now Promises - use await params
export default async function Page({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
}Stessa storia per il client Supabase lato server: in questo repo createClient() di libs/supabase/server.ts è asincrono, quindi va sempre atteso. Il file lo ripete in tre sezioni diverse — server component, client component, route handler — perché è l'errore che l'AI fa più spesso.
// Server: await required
const supabase = await createClient();
// Client component: no await
"use client";
const supabase = createClient();Su Tailwind, la regola è che non esiste più un tailwind.config.js: la configurazione è CSS-first dentro app/globals.css, con @import "tailwindcss", il blocco @theme per i token e @utility per le classi custom. Se il tuo assistente prova a crearti un file di config JS, è perché non ha letto questa sezione.
3. La lista “Do Not”
In fondo al file c'è un elenco di divieti secchi. Questi valgono più di dieci paragrafi di stile, perché un modello li tratta come vincoli:
- niente
anyse non è davvero inevitabile, e niente aggiramenti dello strict mode; - niente valori di configurazione hardcodati — vanno in
config.tso nelle variabili d'ambiente; - mai dimenticare
awaitsulle API asincrone di Next 15; - mai saltare la verifica della firma sui webhook Stripe;
- mai esporre la service role key di Supabase lato client;
- mai dimenticare le policy RLS quando si crea una tabella;
- niente componenti senza interfaccia TypeScript per le props, e niente stati di loading ed errore lasciati fuori.
Una nota onesta su una di queste regole: il file dice anche don't use inline styles, prefer TailwindCSS classes, ma buona parte dei componenti della landing usa style={{ background: "var(--cream)" }} di proposito, per leggere i token del tema definiti in globals.css. Se la tua AI ti riscrive quegli stili in classi Tailwind “per rispettare le regole”, ora sai perché — e sai che in quel punto la regola va ignorata.
4. CLAUDE_INSTRUCTIONS.md
Stessa sostanza, formato diverso. CLAUDE_INSTRUCTIONS.md è costruito quasi tutto per coppie sbagliato/giusto: mostra il pattern Next 14 e accanto quello Next 15, il client Supabase senza await e quello con await, il config Tailwind in JS e quello in CSS. Per un modello è la forma più efficace, perché rende esplicito l'errore da non fare invece di descrivere solo il comportamento corretto.
Contiene anche due cose che .cursorrules non ha: un albero delle cartelle del progetto, e una sezione finale su come verificare il lavoro.
### Common Build Errors to Watch For:
1. Missing await on async Next.js 15 APIs
2. Incorrect params typing in dynamic routes
3. Client/Server component boundary issues
4. Missing environment variables
5. Tailwind CSS configuration errorsUn dettaglio pratico: Claude Code per convenzione cerca un file chiamato CLAUDE.md, e qui il file si chiama CLAUDE_INSTRUCTIONS.md. Se vuoi che venga letto in automatico, copialo o rinominalo:
cp CLAUDE_INSTRUCTIONS.md CLAUDE.mdAltrimenti citalo tu nel prompt la prima volta: “leggi CLAUDE_INSTRUCTIONS.md prima di iniziare”.
5. Come scrivere i prompt su questo repo
Siccome il contesto ce l'ha già, il prompt più efficace non spiega il progetto: nomina i file. Un modello che sa già cosa contiene libs/api.ts non deve indovinare come si chiama il client axios.
Crea /api/newsletter sullo stesso schema di app/api/lead/route.ts:
valida body.email, salva su Supabase, ritorna { error } sui fallimenti.
Poi un client component che lo chiama con apiClient da libs/api.ts.
Aggiungi un terzo piano "Team" in config.ts sotto stripe.plans,
con isFeatured false, e verifica che <Pricing /> lo renderizzi senza modifiche.
Nel webhook Stripe, dentro checkout.session.completed,
manda una email di benvenuto con sendEmail() di libs/resend.ts.Quando invece stai lavorando sul look, punta ai token e alle primitive: “usa i token di app/globals.css e WobbleBorder da components/drawn” ti restituisce un componente coerente col resto della landing, invece di un blocco DaisyUI blu che stona con tutto.
6. Tieni i due file aggiornati
Questa è la parte che si dimentica. .cursorrules e CLAUDE_INSTRUCTIONS.md non sono documentazione decorativa: sono la fonte di verità che l'AI legge prima di scrivere. Se sostituisci Resend con un altro provider di email, o aggiungi una cartella services/ con una tua convenzione, e non aggiorni quei file, il modello continuerà a produrre codice per il progetto di prima. Ogni volta che cambi una convenzione, cambiala anche lì.
E una regola di igiene che vale sempre, a prescindere dal modello: dopo una sessione in cui l'AI ha toccato più file, lancia il build prima di committare. Gli errori della lista al passo 4 vengono fuori tutti lì.
npm run buildSe ti serve un ripasso su cosa deve esserci nel .env.local prima che il build passi, è in Configurare le variabili.