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>
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 |
|
false |
|
|
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.mdDa 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).
-- 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 opzionalecontent: text NOT NULL (D-02) — testo grezzo illimitatocall_date: date NOT NULL (D-02) — giorno della call, non timestampcreated_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.
Passi:
-
Aprire un terminale locale e avviare il tunnel SSH:
ssh -L 54321:localhost:54321 root@178.104.27.55Lasciare questo terminale aperto per tutta la durata.
-
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.sqlOppure, 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.localo nei secret Coolify.) -
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.
-
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_transcriptsesiste nel database di produzione \d client_transcriptsmostra 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.
- La tabella
<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> |
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>