diff --git a/.planning/phases/21-agente-ai-generazione-preventivo/21-CONTEXT.md b/.planning/phases/21-agente-ai-generazione-preventivo/21-CONTEXT.md
new file mode 100644
index 0000000..808af25
--- /dev/null
+++ b/.planning/phases/21-agente-ai-generazione-preventivo/21-CONTEXT.md
@@ -0,0 +1,122 @@
+# Phase 21: Agente AI — generazione preventivo - Context
+
+**Gathered:** 2026-06-20
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+L'admin apre il dettaglio di un lead, seleziona un'offerta e lancia la generazione: Claude legge i transcript del lead e i dati dell'offerta (tutti e 3 i tier) e produce una bozza di preventivo strutturata in sezioni fisse. L'admin rivede il testo in una textarea e salva la bozza prima che diventi pubblicabile in Phase 22.
+
+**In scope:** prompt engineering + chiamata API Claude + bozza strutturata in sezioni + form di revisione/editing + tabella `proposals` nel DB
+**Out of scope:** pagina pubblica `/preventivo/[slug]` (Phase 22), invio email (Phase 22), accettazione/rifiuto cliente (Phase 22)
+
+
+
+
+## Implementation Decisions
+
+### Struttura output AI
+
+- **D-01:** Claude produce sezioni strutturate fisse, non testo libero. Il prompt specifica esattamente i blocchi da riempire.
+- **D-02:** Le sezioni del preventivo generato sono, in ordine:
+ 1. **Situazione Attuale** — Claude descrive la situazione del cliente basandosi sul contenuto dei transcript (cosa sta vivendo, i pain emersi nelle call)
+ 2. **La Proposta** — Presentazione personalizzata dell'offerta: perché questa offerta è giusta per questo cliente specifico
+ 3. **Opzione A / Opzione B / Opzione C** — Una sotto-sezione per ogni tier, con lista dei servizi inclusi e prezzo pubblico del tier
+ 4. **Prossimi Passi** — Call to action finale (Claude scrive testo standard, admin può editare)
+- **D-03:** L'admin **non sceglie un tier** prima della generazione. Claude genera tutti e 3 i tier in un unico documento. Il cliente leggerà le 3 opzioni e sceglierà.
+
+### Claude's Discretion
+
+Le seguenti aree non sono state discusse — Claude ha flessibilità:
+
+- **Builder location:** Entry point nel LeadDetail esistente (`src/components/admin/leads/LeadDetail.tsx`) — bottone "Genera Preventivo" che apre un modal o sezione inline con selezione offerta + trigger generazione. È il posto più naturale perché i transcript del lead sono già in contesto.
+- **UX generazione:** Fire-and-wait con spinner. Nessun streaming. L'admin clicca "Genera", vede uno stato di caricamento, poi il testo appare. Più semplice e affidabile per il caso d'uso (generazione ~5-15 sec).
+- **Editor bozza:** Textarea non-formattata. Il preventivo generato appare in una `
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Requirements & Roadmap
+- `.planning/ROADMAP.md` — Phase 21 goal, success criteria (AI-01/AI-02), dipendenze (Phase 20 + DB offerte Phase 11/12)
+- `.planning/REQUIREMENTS.md` — AI-01 (generazione), AI-02 (revisione bozza)
+
+### Contesto Phase 20 (transcript — input dell'AI)
+- `.planning/phases/20-knowledge-base-cliente/20-CONTEXT.md` — Decisioni schema `client_transcripts`, pattern query, struttura dati che l'AI deve leggere
+- `src/lib/lead-service.ts` — `getTranscripts(leadId)` → restituisce array con `{id, title, content, call_date}` ordinati per data DESC; il campo `content` è testo integrale, non troncato
+
+### Dati offerta (input dell'AI)
+- `src/lib/offer-queries.ts` — `getOfferEditorData(macroId)` → restituisce i dati completi dell'offerta inclusi tier A/B/C con servizi e `public_price`; questa è la funzione da usare per costruire il contesto offerta nel prompt
+- `src/app/admin/offers/actions.ts` — pattern server actions per offerte (riferimento per nuovo layer proposals)
+
+### Schema & Migrations
+- `src/db/schema.ts` — pattern tabelle esistenti: `leads`, `activities`, `clientTranscripts`, `offer_macros` — usare per definire `proposals`
+- `src/db/migrations/0009_client_transcripts.sql` — ultimo esempio SQL migration a mano (struttura e convenzioni da replicare per `0010_proposals.sql`)
+
+### UI & Integration Points
+- `src/components/admin/leads/LeadDetail.tsx` — struttura UI dove va aggiunto il trigger "Genera Preventivo" e la sezione bozza
+- `src/app/admin/leads/[id]/page.tsx` — page con `Promise.all` per fetch parallele (pattern da seguire, aggiungere fetch proposals)
+- `src/app/admin/leads/actions.ts` — pattern `requireAdmin` guard + `revalidatePath` (da seguire per le nuove actions proposals)
+
+### Sicurezza & Architettura
+- `CLAUDE.md` → sezione Architecture Constraints: `quote_items` MAI esposti via client API; la nuova tabella `proposals` segue lo stesso principio — `content` non esposto via client token senza consenso esplicito Phase 22
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `getTranscripts(leadId)` in `src/lib/lead-service.ts` — pronta, restituisce `content` integrale; concatenare i transcript in ordine cronologico per il prompt AI
+- `getOfferEditorData(macroId)` in `src/lib/offer-queries.ts` — restituisce tier A/B/C con array di servizi e `public_price` per tier; mappare questi dati nel prompt con nome servizi + prezzi
+- `nanoid` — già in uso nel progetto per PK; riusare per `proposals.id` e `proposals.slug`
+- `requireAdmin()` — già in ogni server action, obbligatorio anche per le nuove actions proposals
+
+### Established Patterns
+- **Migration a mano**: `CREATE TABLE IF NOT EXISTS`, tipi Postgres espliciti, FK con `ON DELETE CASCADE` (o `SET NULL` se nullable). NON usare `drizzle-kit generate`.
+- **Prod-first migration**: la migration `0010_proposals.sql` DEVE essere applicata a prod via SSH+docker exec (`ssh -L 54321:localhost:54321 root@178.104.27.55`) PRIMA di pushare il codice che la referenzia.
+- **Server Actions con revalidatePath**: ogni mutation chiama `revalidatePath()` sul path del lead.
+- **Promise.all fetch**: `page.tsx` del lead usa `await Promise.all([...])` — aggiungere `getProposals(id)` nello stesso array.
+
+### Integration Points
+- `src/app/admin/leads/[id]/page.tsx` — aggiungere `getProposals(id)` nel `Promise.all`, passare `proposals` a ``
+- `src/components/admin/leads/LeadDetail.tsx` — aggiungere sezione "Preventivo" con bottone trigger + form selezione offerta + textarea bozza
+- `src/db/schema.ts` — aggiungere definizione `proposals` + relazioni Drizzle
+- `src/lib/lead-service.ts` (o nuovo `src/lib/proposal-service.ts`) — `generateProposal(leadId, offerId)`, `getProposals(leadId)`, `saveProposal(id, content)`
+- `.env.local` — aggiungere `ANTHROPIC_API_KEY` (richiede configurazione in Coolify per produzione)
+
+
+
+
+## Specific Ideas
+
+- Il preventivo è multi-tier by design: non c'è una scelta del tier nella UI di generazione. Claude scrive 3 opzioni (A/B/C) in un solo documento, il cliente legge e sceglie.
+- La sezione "Opzione A/B/C" deve mostrare i nomi dei servizi inclusi in modo leggibile (non JSON grezzo), e il `public_price` del tier in modo prominente.
+- La sezione "Situazione Attuale" è la parte più personalizzata — Claude deve pescare dai transcript specifici insights sul cliente, non frasi generiche. Il prompt deve guidare su questo.
+- L'admin in fase di review vede l'intero testo del preventivo in una `
+
+
+## Deferred Ideas
+
+- **Scelta tier nel preventivo:** eventualmente l'admin potrebbe scegliere un tier da presentare → Phase 22 o fase futura post v2.2.
+- **Streaming output AI:** Claude scrive in real-time → futura ottimizzazione UX se la latenza diventa un problema.
+- **Versioning bozze:** mantenere storico delle generazioni per un lead → futura fase.
+- **Agente multi-step con tool_use:** architettura più sofisticata dove Claude chiama tool API invece di ricevere dati pre-imbarcati nel prompt → futura fase.
+
+
+
+---
+
+*Phase: 21-Agente AI — generazione preventivo*
+*Context gathered: 2026-06-20*
diff --git a/.planning/phases/21-agente-ai-generazione-preventivo/21-DISCUSSION-LOG.md b/.planning/phases/21-agente-ai-generazione-preventivo/21-DISCUSSION-LOG.md
new file mode 100644
index 0000000..b9ac323
--- /dev/null
+++ b/.planning/phases/21-agente-ai-generazione-preventivo/21-DISCUSSION-LOG.md
@@ -0,0 +1,40 @@
+# Phase 21: Discussion Log
+
+**Session:** 2026-06-20
+**Areas discussed:** 1 of 4 identified (Struttura preventivo)
+
+---
+
+## Area: Struttura preventivo
+
+### Q1 — Tipo di output AI
+- **Opzioni:** Testo libero personalizzato / Sezioni strutturate fisse / Ibrido intro+sezioni
+- **Scelta:** Sezioni strutturate fisse
+- **Note:** L'admin e il cliente hanno bisogno di un documento prevedibile — le sezioni fisse rendono più facile sia il prompt engineering che l'editing successivo.
+
+### Q2 — Quali sezioni
+- **Opzioni (multi-select):** Situazione Attuale / La Proposta / Cosa è Incluso / Investimento + Prossimi Passi
+- **Scelta:** Tutte e 4 le sezioni
+- **Note:** L'utente ha aggiunto "penso che creo un agente apposta per questa parte" — chiarito che si trattava di un'altra sessione Claude Code, nessuna interferenza con questo progetto.
+
+### Q3 — Tier: singolo o tutti e 3
+- **Opzioni:** Un solo tier scelto dall'admin / Tutti e 3 i tier in un documento
+- **Scelta:** Tutti e 3 i tier in un documento
+- **Note:** Il preventivo presenta opzioni A/B/C al cliente, che sceglie leggendo.
+
+---
+
+## Aree non discusse (Claude's discretion)
+
+- **Builder location:** Entry point nel LeadDetail esistente
+- **UX generazione:** Fire-and-wait con spinner (no streaming)
+- **Editor bozza:** Textarea plain text
+
+---
+
+## Idee deferred
+
+- Scelta tier singolo nel preventivo (post v2.2)
+- Streaming output AI (ottimizzazione futura)
+- Versioning bozze
+- Agente multi-step con tool_use