Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.0 KiB
Phase 20: Knowledge Base Cliente — Context
Gathered: 2026-06-19 Status: Ready for planning
## Phase BoundaryAggiungere uno store di transcript datati per lead: l'admin incolla il testo grezzo di ogni call con data e titolo libero, la lista appare in ordine cronologico nel dettaglio lead, e i dati sono pronti per essere letti dall'agente AI in Phase 21.
In scope: schema client_transcripts + server actions + UI nel LeadDetail
Out of scope: UI per clienti (client_id FK presente ma non esposta), ricerca full-text sui transcript, trascrizione automatica da audio
Schema — client_transcripts
- D-01: La tabella
client_transcriptsha entrambe le FK nullable:lead_id(references leads, onDelete cascade) eclient_id(references clients, onDelete cascade). Ragionamento: prepara la struttura per transcript post-conversione senza richiedere una migration futura. - D-02: Campi:
id(nanoid PK),lead_id(nullable FK),client_id(nullable FK),title(text, optional — titolo libero es. "Discovery call 12 giugno"),content(text NOT NULL — testo incollato, lunghezza illimitata),call_date(date NOT NULL — giorno della call, non timestamp),created_at(timestamp with timezone, defaultNow). - D-03: Migration mano-scritta come 0009 — drizzle-kit generate è rotto. Applicata a prod via SSH prima di pushare il codice dipendente (invariante bloccante del progetto).
UI — Solo lato lead in Phase 20
- D-04: In Phase 20 la UI espone solo il lato lead. La FK
client_idè nello schema ma non ha form o lista in questa fase — si aggiunge in futuro se serve la pagina/admin/clients/[id]. - D-05: I transcript sono listati in ordine
call_date DESCnel dettaglio lead (chiamata più recente in cima).
Claude's Discretion
Le seguenti aree non sono state discusse — Claude ha flessibilità:
- Metadati: No tipo enum —
titlelibero (optional) è sufficiente. Il testo del transcript parla da solo. - Placement UI: Nuova sezione "Transcript" collassabile in
LeadDetail, dopo la sezione Attività esistente. Stessa convenzione visiva (Card + lista). Form/modal per aggiungere seguendo il patternLogActivityModal. - Nessun limite di lunghezza:
contentètextPostgreSQL (illimitato). Textarea nel form senza troncatura.
<canonical_refs>
Canonical References
Downstream agents MUST read these before planning or implementing.
Requirements & Roadmap
.planning/ROADMAP.md— Phase 20 goal, success criteria, schema spec (client_transcriptsconlead_id/client_id, testo, data, titolo/tipo, created_at).planning/REQUIREMENTS.md— KB-01 (schema additivo transcript), KB-02 (UI incolla/elenca)
Schema & Migrations
src/db/schema.ts— pattern tabelle append-only CRM:activities(lead_id, type, notes, activity_date),reminders(lead_id, due_date). La nuovaclient_transcriptssegue questo pattern.src/db/migrations/0008_offer_tier_schema.sql— ultimo esempio di SQL migration a mano (struttura e convenzioni da seguire)src/db/migrations/0005_phase_10_crm_leads_activities_reminders.sql— migration originale diactivitiesereminders(pattern più vicino alla nuova tabella)
UI & Components
src/components/admin/leads/LeadDetail.tsx— struttura UI esistente del dettaglio lead (dove va inserita la sezione Transcript)src/components/admin/leads/LogActivityModal.tsx— pattern modal per aggiungere dati CRM (da seguire per il form transcript)src/app/admin/leads/[id]/page.tsx— pattern page conPromise.allper fetch parallele (aggiungeregetTranscripts(id))
Query & Actions Layer
src/lib/lead-service.ts— pattern query layer CRM (getActivityLog,getUpcomingReminders— aggiungeregetTranscripts)src/app/admin/leads/actions.ts— pattern server actions conrequireAdminguard (da seguire peraddTranscript,deleteTranscript)
</canonical_refs>
<code_context>
Existing Code Insights
Reusable Assets
LogActivityModal.tsx— modal con form controllato (date picker + textarea + submit), pronto da clonare per il form transcriptactivities/reminderspattern inschema.ts— FKlead_idcononDelete: cascade,nanoid()PK,created_atdefaultNow — copia esatta perclient_transcriptsgetActivityLog(leadId)inlead-service.ts— query Drizzle conwhere(eq(activities.lead_id, leadId))eorderBy(desc(activities.activity_date))— pattern identico pergetTranscriptsCard,CardContent,CardHeader,CardTitleda shadcn/ui — già usati nel LeadDetail per ogni sezione
Established Patterns
- Migration a mano: ogni schema change è SQL scritto a mano (
CREATE TABLE IF NOT EXISTS, tipi Postgres espliciti, FK conON DELETE CASCADE). NON usaredrizzle-kit generate. - requireAdmin guard: tutte le server actions in
actions.tsiniziano conawait requireAdmin()— obbligatorio anche per le nuove actions transcript. revalidatePathdopo ogni mutation:revalidatePath(\/admin/leads/${leadId}`)`.- Promise.all fetch:
page.tsxdel dettaglio lead usaawait Promise.all([...])per fetch parallele — aggiungeregetTranscripts(id)nello stesso array.
Integration Points
src/app/admin/leads/[id]/page.tsx— aggiungeregetTranscripts(id)nelPromise.all, passaretranscriptsa<LeadDetail />src/components/admin/leads/LeadDetail.tsx— aggiungere proptranscriptse sezione "Transcript" dopo<ActivitySection>src/db/schema.ts— aggiungere definizioneclient_transcripts+ relazioni Drizzlesrc/lib/lead-service.ts— aggiungeregetTranscripts(leadId: string)src/app/admin/leads/actions.ts— aggiungereaddTranscript(leadId, data)edeleteTranscript(transcriptId)
</code_context>
## Specific Ideas- Il testo del transcript può essere molto lungo (trascrizioni complete di call). Il form deve avere una
<textarea>con altezza generosa (es. min-h-48 o più) senza limite di caratteri. - Il
call_dateè unadate(non timestamp) — l'admin sceglie il giorno della call, non l'ora. Nel DB:DATEtype PostgreSQL. - La lista transcript deve mostrare:
call_dateformattata (es. "12 giugno 2026"),titlese presente, anteprima delle prime righe delcontent, e un'azione "Elimina". Espansione/collapse del testo completo. - Phase 21 leggerà i transcript via
getTranscripts(leadId)— la query deve restituire tutti i campi inclusocontentcompleto.
- UI transcript per clienti (
/admin/clients/[id]): la FKclient_idè nella tabella, ma la UI lato cliente è deferred a una fase futura (post v2.2 o su richiesta). - Ricerca full-text sui transcript: fuori scope v2.2 — i transcript vengono letti dall'AI in blocco, non cercati dall'admin.
- Trascrizione automatica da audio: fuori scope — l'admin incolla manualmente il testo.
Phase: 20-Knowledge Base Cliente Context gathered: 2026-06-19