Files
clienthub/.planning/phases/21-agente-ai-generazione-preventivo/21-CONTEXT.md
T

8.6 KiB

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 <textarea> grande che l'admin può editare liberamente prima di salvare. Nessun rich text editor in questa fase.
  • SDK: @anthropic-ai/sdk (pacchetto ufficiale Anthropic). Nessun Vercel AI SDK o LangChain.
  • Modello: claude-sonnet-4-6 (modello attivo del progetto).
  • Storage: Nuova tabella proposals nel DB seguendo i pattern esistenti: id (nanoid PK), lead_id (FK → leads, nullable cascade), offer_id (FK → offer_macros), content (text NOT NULL — il testo completo della bozza), slug (text unique — nanoid, per il link pubblico Phase 22), status (text: draft | published), created_at (timestamp with timezone).
  • Migration: SQL a mano come 0010_proposals.sql (drizzle-kit generate è rotto). Applicare a prod via SSH prima di pushare il codice.
  • Server action / API route: Server Action Next.js per il trigger di generazione (pattern coerente col resto del progetto). La chiamata Anthropic avviene lato server.

<canonical_refs>

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.tsgetTranscripts(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.tsgetOfferEditorData(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

</canonical_refs>

<code_context>

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 <LeadDetail />
  • 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)

</code_context>

## 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 <textarea> di altezza generosa (tipo min-h-96) e può editare liberamente prima di salvare.
## 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