Files
simone dc934fb04a docs(20): create phase plan — Knowledge Base Cliente transcript
3 piani: 20-01 migration BLOCKING, 20-02 schema+actions, 20-03 UI.
KB-01 e KB-02 coperti. Wave 1→2→3 sequenziali per vincolo migration-prima-del-codice.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 18:52:16 +02:00

10 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
20-knowledge-base-cliente 01 execute 1
src/db/migrations/0009_client_transcripts.sql
false
KB-01
truths artifacts key_links
Il file 0009_client_transcripts.sql esiste con DDL completo e idempotente
La tabella client_transcripts è presente nel database di produzione
Il codice schema-dipendente dei piani successivi non viene pushato prima che la migration sia applicata
path provides contains
src/db/migrations/0009_client_transcripts.sql DDL CREATE TABLE IF NOT EXISTS client_transcripts con tutti i campi D-01/D-02 CREATE TABLE IF NOT EXISTS client_transcripts
from to via pattern
src/db/migrations/0009_client_transcripts.sql database produzione SSH tunnel + psql/docker exec CREATE TABLE IF NOT EXISTS client_transcripts
Scrivere il file SQL della migration manuale per la tabella `client_transcripts` e applicarlo al database di produzione prima di pushare qualsiasi codice schema-dipendente.

Purpose: Il progetto ha drizzle-kit generate rotto (meta-snapshot fuori sync). Ogni schema change richiede SQL a mano applicato a prod via SSH PRIMA del codice dipendente — invariante bloccante LOCKED in CLAUDE.md.

Output: src/db/migrations/0009_client_transcripts.sql applicato a prod. Il checkpoint umano sblocca i piani 20-02 e 20-03.

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/ROADMAP.md @.planning/phases/20-knowledge-base-cliente/20-CONTEXT.md

Da 0005_phase_10_crm_leads_activities_reminders.sql:

CREATE TABLE IF NOT EXISTS "activities" (
  "id" text PRIMARY KEY NOT NULL,
  "lead_id" text NOT NULL,
  ...
  FOREIGN KEY ("lead_id") REFERENCES "leads"("id") ON DELETE cascade
);
CREATE INDEX IF NOT EXISTS "activities_lead_id" ON "activities"("lead_id");

Da 0008_offer_tier_schema.sql (header):

-- Phase 12: Offer Editor — additive schema ...
-- All statements additive/idempotent. No drops/truncates (Data Safety LOCKED).
Task 1: Scrivere src/db/migrations/0009_client_transcripts.sql src/db/migrations/0009_client_transcripts.sql - src/db/migrations/0008_offer_tier_schema.sql (pattern header + CREATE TABLE IF NOT EXISTS) - src/db/migrations/0005_phase_10_crm_leads_activities_reminders.sql (pattern FK + index per tabelle CRM) - .planning/phases/20-knowledge-base-cliente/20-CONTEXT.md (D-01 e D-02 — campi esatti) Creare il file `src/db/migrations/0009_client_transcripts.sql` con il seguente contenuto esatto:
-- Phase 20: Knowledge Base Cliente — tabella transcript datati per lead/cliente
-- Additive only. No drops/truncates (Data Safety LOCKED).
-- Applicare a prod via SSH tunnel PRIMA di pushare il codice dipendente (D-03).

CREATE TABLE IF NOT EXISTS client_transcripts (
  id          text PRIMARY KEY NOT NULL,
  lead_id     text REFERENCES leads(id) ON DELETE CASCADE,
  client_id   text REFERENCES clients(id) ON DELETE CASCADE,
  title       text,
  content     text NOT NULL,
  call_date   date NOT NULL,
  created_at  timestamp with time zone NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS client_transcripts_lead_id_idx
  ON client_transcripts (lead_id);

CREATE INDEX IF NOT EXISTS client_transcripts_client_id_idx
  ON client_transcripts (client_id);

CREATE INDEX IF NOT EXISTS client_transcripts_call_date_idx
  ON client_transcripts (call_date DESC);

Note sui campi (da D-01/D-02):

  • id: text PK NOT NULL — nanoid inserito dall'app, nessun DEFAULT SQL (pattern progetto)
  • lead_id: nullable FK → leads(id) ON DELETE CASCADE (D-01)
  • client_id: nullable FK → clients(id) ON DELETE CASCADE (D-01)
  • title: text nullable (D-02) — titolo libero opzionale
  • content: text NOT NULL (D-02) — testo grezzo illimitato
  • call_date: date NOT NULL (D-02) — giorno della call, non timestamp
  • created_at: timestamp with time zone NOT NULL DEFAULT now() (D-02)

Gli indici su lead_id, client_id e call_date ottimizzano le query per lead (Phase 20) e future query per client_id (Phase 21+). grep -c "CREATE TABLE IF NOT EXISTS client_transcripts" /Users/simonecavalli/Vault/IAMCAVALLI/src/db/migrations/0009_client_transcripts.sql <acceptance_criteria> - File src/db/migrations/0009_client_transcripts.sql esiste - Contiene CREATE TABLE IF NOT EXISTS client_transcripts - Contiene lead_id text REFERENCES leads(id) ON DELETE CASCADE - Contiene client_id text REFERENCES clients(id) ON DELETE CASCADE - Contiene content text NOT NULL - Contiene call_date date NOT NULL - Contiene created_at timestamp with time zone NOT NULL DEFAULT now() - Contiene 3 CREATE INDEX IF NOT EXISTS (lead_id_idx, client_id_idx, call_date_idx) - Nessun DROP o TRUNCATE nel file </acceptance_criteria> File SQL completo e idempotente scritto, pronto per applicazione a prod.

Task 2: [BLOCKING] Applicare migration 0009 al database di produzione via SSH - src/db/migrations/0009_client_transcripts.sql (verificare il contenuto prima di applicare) La migration va applicata a prod via SSH tunnel PRIMA di eseguire i piani 20-02 e 20-03. Il database di produzione è accessibile solo tramite tunnel SSH.

Passi:

  1. Aprire un terminale locale e avviare il tunnel SSH:

    ssh -L 54321:localhost:54321 root@178.104.27.55
    

    Lasciare questo terminale aperto per tutta la durata.

  2. In un altro terminale, applicare la migration con psql (il DATABASE_URL del progetto punta a 127.0.0.1:54321):

    cd /Users/simonecavalli/Vault/IAMCAVALLI
    psql "$(grep DATABASE_URL .env.local | cut -d= -f2-)" -f src/db/migrations/0009_client_transcripts.sql
    

    Oppure, se il DATABASE_URL non funziona direttamente, applicare via docker exec sul server:

    # Sul server (nella sessione SSH aperta al punto 1):
    docker exec -i <nome_container_postgres> psql -U <db_user> -d <db_name> < /path/to/0009_client_transcripts.sql
    

    (Il nome del container e le credenziali sono in .env.local o nei secret Coolify.)

  3. Verificare che la tabella esista:

    psql "$(grep DATABASE_URL .env.local | cut -d= -f2-)" -c "\d client_transcripts"
    

    Deve mostrare le colonne: id, lead_id, client_id, title, content, call_date, created_at.

  4. Chiudere il tunnel SSH solo dopo aver verificato il punto 3. Il file SQL 0009_client_transcripts.sql è stato scritto da Claude nel Task 1. Questo task richiede solo che tu applichi la migration a prod — nessun codice da scrivere. Eseguire in locale (con tunnel attivo):

    psql "$(grep DATABASE_URL .env.local | cut -d= -f2-)" -c "SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'client_transcripts' ORDER BY ordinal_position;"
    

    Risultato atteso: 7 righe con le colonne id, lead_id, client_id, title, content, call_date, created_at. Digita "migration applicata" dopo aver verificato che \d client_transcripts mostra le 7 colonne attese. <acceptance_criteria>

    • La tabella client_transcripts esiste nel database di produzione
    • \d client_transcripts mostra 7 colonne: id (text), lead_id (text, nullable), client_id (text, nullable), title (text, nullable), content (text, NOT NULL), call_date (date, NOT NULL), created_at (timestamptz, NOT NULL)
    • 3 indici presenti: client_transcripts_lead_id_idx, client_transcripts_client_id_idx, client_transcripts_call_date_idx </acceptance_criteria> Database di produzione aggiornato con la tabella client_transcripts. I piani 20-02 e 20-03 sono sbloccati.

<threat_model>

Trust Boundaries

Boundary Descrizione
developer → database prod SQL applicato manualmente via SSH tunnel autenticato

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-20-01 Tampering 0009_client_transcripts.sql mitigate Revisione manuale del contenuto prima dell'applicazione (Task 2 step 1); file in version control
T-20-02 Repudiation Applicazione migration prod accept L'operazione è tracciata nel git commit di questo piano; nessun audit log applicativo necessario per DDL
T-20-03 Denial of Service DROP/TRUNCATE accidentale mitigate Il file usa solo CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS; nessuna istruzione distruttiva presente
</threat_model>
```bash # Verificare che il file SQL esista e contenga i campi obbligatori grep -E "CREATE TABLE IF NOT EXISTS client_transcripts|content.*text NOT NULL|call_date.*date NOT NULL|lead_id.*REFERENCES leads|client_id.*REFERENCES clients" \ /Users/simonecavalli/Vault/IAMCAVALLI/src/db/migrations/0009_client_transcripts.sql

Verificare assenza di istruzioni distruttive

grep -i "drop|truncate" /Users/simonecavalli/Vault/IAMCAVALLI/src/db/migrations/0009_client_transcripts.sql | wc -l

Atteso: 0

</verification>

<success_criteria>
- `src/db/migrations/0009_client_transcripts.sql` esiste con DDL completo e idempotente (KB-01)
- La tabella `client_transcripts` è presente nel database di produzione con le 7 colonne di D-02
- Nessuna istruzione distruttiva nel file SQL
- Il checkpoint umano è stato completato e segnalato con "migration applicata"
</success_criteria>

<output>
Dopo il completamento del Task 2, creare `.planning/phases/20-knowledge-base-cliente/20-01-SUMMARY.md` con:
- Migration file creato: `src/db/migrations/0009_client_transcripts.sql`
- Migration applicata a prod: sì/no
- Colonne verificate: lista delle 7 colonne confermate
</output>