- Remove .notNull() from service_id to allow free-form items without catalog ref
- Add custom_label: text("custom_label") for free-form item label storage
- TypeScript compiles with zero errors (QuoteItem.service_id now string | null)
Schema:
- clients.archived boolean (default false)
- time_entries table (client_id, started_at, ended_at, duration_seconds)
Client management:
- /admin/clients/[id]/edit — form pre-compilato con nome, brand, brief
- ClientActions: Modifica / Archivia / Elimina con doppia conferma
- setClientArchived: toggle archiviazione senza perdere dati
- deleteClient: elimina con cascade, redirect a /admin
- Admin list: toggle "Mostra archiviati" via ?archived=1, righe archiviate opache
Time tracker:
- startTimer: crea sessione, ferma automaticamente quella precedente
- stopTimer: chiude sessione, calcola duration_seconds
- TimerCell: ▶/⏹ per ogni cliente, contatore live in secondi, totale cumulativo
- Una sola sessione attiva alla volta su tutta la lista
Analytics:
- Sezione "Fatturato" (invariata) + sezione "Tempo tracciato" separata
- Ore totali per anno + barre orizzontali per cliente
- getTotalTrackedHours, getTimeByClient queries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Connected to postgresql://178.104.27.55:5432/clienthub
- 10 tables created: clients, phases, tasks, deliverables, comments,
payments, documents, notes, service_catalog, quote_items
- UNIQUE constraint on clients.token active at DB level
- All FK constraints and CASCADE rules applied
- Verified via information_schema.tables query
- 10 tables: clients, phases, tasks, deliverables, comments, payments,
documents, notes, service_catalog, quote_items
- UNIQUE constraint on clients.token enforced at DB level
- All FK cascades correct (deliverables->tasks->phases->clients)
- approved_at: timestamp with time zone (nullable, immutable)
- drizzle.config.ts already correct from Plan 01 (no changes needed)
- clients: token as separate text field (notNull, unique, nanoid) — never PK
- accepted_total denormalized on clients — client API never touches quote_items
- deliverables.approved_at immutable timestamp (TIMESTAMPTZ) — audit trail
- payments: label (Acconto 50% / Saldo 50%), status (da_saldare/inviata/saldato)
- comments: polymorphic entity_type+entity_id pattern
- service_catalog + quote_items: admin-only, never exposed to client API
- Full relations defined for all FK chains
- TypeScript types exported: Client, Phase, Task, Deliverable, etc.
- ID strategy: text + nanoid() via $defaultFn (cryptographically secure, URL-safe)