diff --git a/.planning/phases/20-knowledge-base-cliente/20-CONTEXT.md b/.planning/phases/20-knowledge-base-cliente/20-CONTEXT.md new file mode 100644 index 0000000..c7fe33b --- /dev/null +++ b/.planning/phases/20-knowledge-base-cliente/20-CONTEXT.md @@ -0,0 +1,111 @@ +# 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 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`) + + + + +## 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 `` +- `src/components/admin/leads/LeadDetail.tsx` — aggiungere prop `transcripts` e sezione "Transcript" dopo `` +- `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)` + + + + +## Specific Ideas + +- Il testo del transcript può essere molto lungo (trascrizioni complete di call). Il form deve avere una `