Files
clienthub/.planning/milestones/v2.2-phases/20-knowledge-base-cliente/20-CONTEXT.md
T
simone f7eb7eec23 docs(planning): archivia v2.1/v2.2/v2.3 e documenta v2.4
.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>
2026-08-08 22:38:36 +02:00

7.0 KiB

Phase 20: Knowledge Base Cliente — Context

Gathered: 2026-06-19 Status: Ready for planning

## Phase Boundary

Aggiungere 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

## Implementation Decisions

Schema — client_transcripts

  • D-01: La tabella client_transcripts ha entrambe le FK nullable: lead_id (references leads, onDelete cascade) e client_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 DESC nel dettaglio lead (chiamata più recente in cima).

Claude's Discretion

Le seguenti aree non sono state discusse — Claude ha flessibilità:

  • Metadati: No tipo enum — title libero (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 pattern LogActivityModal.
  • Nessun limite di lunghezza: content è text PostgreSQL (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_transcripts con lead_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 nuova client_transcripts segue 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 di activities e reminders (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 con Promise.all per fetch parallele (aggiungere getTranscripts(id))

Query & Actions Layer

  • src/lib/lead-service.ts — pattern query layer CRM (getActivityLog, getUpcomingReminders — aggiungere getTranscripts)
  • src/app/admin/leads/actions.ts — pattern server actions con requireAdmin guard (da seguire per addTranscript, 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 transcript
  • activities / reminders pattern in schema.ts — FK lead_id con onDelete: cascade, nanoid() PK, created_at defaultNow — copia esatta per client_transcripts
  • getActivityLog(leadId) in lead-service.ts — query Drizzle con where(eq(activities.lead_id, leadId)) e orderBy(desc(activities.activity_date)) — pattern identico per getTranscripts
  • Card, CardContent, CardHeader, CardTitle da 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 con ON DELETE CASCADE). NON usare drizzle-kit generate.
  • requireAdmin guard: tutte le server actions in actions.ts iniziano con await requireAdmin() — obbligatorio anche per le nuove actions transcript.
  • revalidatePath dopo ogni mutation: revalidatePath(\/admin/leads/${leadId}`)`.
  • Promise.all fetch: page.tsx del dettaglio lead usa await Promise.all([...]) per fetch parallele — aggiungere getTranscripts(id) nello stesso array.

Integration Points

  • src/app/admin/leads/[id]/page.tsx — aggiungere getTranscripts(id) nel Promise.all, passare transcripts a <LeadDetail />
  • src/components/admin/leads/LeadDetail.tsx — aggiungere prop transcripts e sezione "Transcript" dopo <ActivitySection>
  • src/db/schema.ts — aggiungere definizione client_transcripts + relazioni Drizzle
  • src/lib/lead-service.ts — aggiungere getTranscripts(leadId: string)
  • src/app/admin/leads/actions.ts — aggiungere addTranscript(leadId, data) e deleteTranscript(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 è una date (non timestamp) — l'admin sceglie il giorno della call, non l'ora. Nel DB: DATE type PostgreSQL.
  • La lista transcript deve mostrare: call_date formattata (es. "12 giugno 2026"), title se presente, anteprima delle prime righe del content, e un'azione "Elimina". Espansione/collapse del testo completo.
  • Phase 21 leggerà i transcript via getTranscripts(leadId) — la query deve restituire tutti i campi incluso content completo.
## Deferred Ideas
  • UI transcript per clienti (/admin/clients/[id]): la FK client_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