.planning/ documentava in dettaglio cio che era vecchio e per niente cio
che e in produzione: le fasi 11-22 (v2.1 e v2.2, chiuse a giugno) erano
ancora in phases/ mentre v1.0 e v2.0 stavano gia in milestones/, e il
lavoro degli ultimi due mesi - gate OTP e ciclo di vita dei retainer, cioe
quello che gira su hub.iamcavalli.net - non aveva nessuna cartella.
- phases/{11,12,14} -> milestones/v2.1-phases/, phases/{18..22} ->
milestones/v2.2-phases/. Ora phases/ contiene solo la milestone in
corso, che e quello che state.cjs conta per il progresso
- v2.1-ROADMAP.md ricostruito: era l'unica milestone senza archivio,
interrotta dal reset del 19/06 e mai chiusa formalmente
- v2.3-ROADMAP.md + v2.3-REQUIREMENTS.md: v2.3 e stata eseguita fuori dal
ciclo GSD, non esistono PLAN/SUMMARY per fase. L'archivio E la doc
- REQUIREMENTS.md riscritto per v2.4 con il backlog reale
- phases/13 e phases/26: SUMMARY ricostruiti da commit, migration e
STATUS.md. 26 e il primo numero libero
- research/: cancellate 4 varianti dello stesso PITFALLS e FEATURES/
SUMMARY, superati da PROJECT.md. Diverse anti-feature erano ormai
contraddette dai fatti (il Kanban e stato costruito in Phase 19,
l'email in v2.3, il time tracking esiste)
- cancellati UI-RULES.md e DESIGN-SYSTEM.md (CLAUDE.md li dichiara
superseded: impongono l'inverso della regola attuale) e HANDOFF.md,
fermo al 13/06
- SECURITY-*.md -> security/: audit chiuso, ma i report restano la doc di
cosa e stato ruotato e perche
- PROJECT.md/MILESTONES.md/ROADMAP.md allineati: milestone corrente v2.4,
sessione OTP 90gg non 30, migrazioni fino alla 0016
Co-Authored-By: Claude Opus 5 <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