Files
clienthub/.planning/PROJECT.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

12 KiB
Raw Blame History

ClientHub — Gestione Clienti & Dashboard

What This Is

Suite operativa per un consulente di personal branding, live su hub.iamcavalli.net (Coolify/Hetzner): un'area admin (/admin/*) per gestire clienti, progetti, offerte, preventivi e CRM, e una dashboard cliente via link segreto (/client/[token]) dove ogni cliente vede lo stato del suo progetto. Con la v2.2 ("Sales Loop") il focus è diventato il loop commerciale completo: lead in pipeline Kanban → transcript datati delle call → agente AI (Claude Opus 4.8) genera preventivo personalizzato leggendo transcript + offerta → deck pubblico 20+ slide navigabile a /preventivo/[slug] → cliente accetta tier A/B/C → vinto/perso nel CRM.

Core Value

Il cliente apre il link e vede esattamente a che punto è il suo progetto, cosa deve ancora succedere e cosa ha già approvato — senza dover scrivere email per chiedere aggiornamenti.

Current Milestone: v2.4 Post-vendita

Goal: Chiudere il ciclo di vita di ciò che è già venduto — un retainer deve poter finire, e l'admin deve poter vedere il portale con gli occhi del cliente.

Consegnato (in produzione):

  • Phase 13 — Ciclo di vita dei servizi ricorrenti (RET-01..05), prod 2026-08-01
  • Phase 26 — Anteprima admin del portale + toggle password sul login (PREV-01/02, AUTH-09), prod 2026-08-08

Backlog: RET-06 (canoni mensili tracciabili), SEND-01/02 (invio preventivo via email), PROP-03 (Stripe Payment Link), PROP-04 (auto-provisioning al "Vinto"), DEBT-01 (debito design). Elenco completo in REQUIREMENTS.md.

Requirements

Validated

Shipped in v1.0 (Phases 16, in produzione su hub.iamcavalli.net):

  • ✓ Ogni cliente ha un URL segreto univoco, nessun login (token rotatable + slug opzionale) — Phase 1/4
  • ✓ Dashboard cliente: brand, brief, fasi/task con stato, progress, multi-progetto — Phase 1/4
  • ✓ Il cliente approva deliverable (approved_at immutabile) e lascia commenti — Phase 2
  • ✓ Il cliente vede solo il totale accettato, mai i prezzi dei singoli servizi — Phase 2/3
  • ✓ Stato pagamenti acconto/saldo visibile al cliente — Phase 1
  • ✓ Link a documenti esterni + storico note/decisioni — Phase 1/2
  • ✓ Area admin completa: clienti, progetti, fasi, task, pagamenti, documenti — Phase 2/4
  • ✓ Catalogo servizi + quote builder admin (quote_items mai esposti al cliente) — Phase 3
  • ✓ Sistema offerte: macro/micro/servizi, assegnazione a progetti, forecast 12 mesi — Phase 5
  • ✓ Offerte attive visibili nella dashboard cliente (solo public_name) — Phase 5
  • ✓ UX admin: sidebar + dashboard operativa con KPI e activity feed — Phase 6

Shipped in v2.0 (Phases 710, in produzione su hub.iamcavalli.net):

  • ✓ Catalogo servizi unificato (tabella services) usato dal quote builder — Phase 7 (legacy service_catalog/offer_services ancora presenti, consolidamento finale spostato in v2.1)
  • ✓ Offerte con fasi ordinate (offer_phases/offer_phase_services) e builder preventivo admin — Phase 8
  • ✓ Preventivo pubblico /quote/[token]: stati draft→sent→viewed→accepted/rejected, accepted_at immutabile, raccolta email/note cliente — Phase 9
  • ✓ CRM pipeline lead: stati, activity log, reminder follow-up in dashboard — Phase 10

Validated in v2.1 (consegnato, in prod):

  • ✓ Catalogo services come vista database (inline edit, tag multi-select, quick-add, ricerca istantanea) + consolidamento legacy — Phase 11 (OFFER-07..10, OFFER-13)
  • ✓ Offer Editor: lista filtrabile/archiviabile + 3 tier A/B/C via matrice checkbox, totale live, prezzo pubblico manuale, tag 4-dimensioni, promessa di trasformazione — Phase 12 (OFFER-11, OFFER-15..18). 55 servizi reali + tag offerta caricati.
  • ✓ CRM custom Attio-style: /admin/leads ridisegnata come tabella inline-edit (status, next_action, ecc.) + tag multi-select con creazione al volo; FollowUpWidget interamente in italiano; LeadForm tipizzato senza useForm<any>; SendQuoteModal/assignQuoteToLead senza rami di codice irraggiungibili — Phase 14 (CRM-08, CRM-09, CRM-10, CRM-11, CRM-12)

Validated in v2.2 Sales Loop (shipped 2026-06-20):

  • ✓ Cleanup: Forecast + quote builder manuale rimossi; analytics fuse in Dashboard — Phase 18 (CLEAN-01..04)
  • ✓ Pipeline CRM Kanban 6 colonne con drag-drop; toggle Lista/Kanban; vinto/perso come cambio-colonna — Phase 19 (PIPE-01, PIPE-02)
  • ✓ Knowledge Base transcript: client_transcripts in prod; UI incolla/elenca nel dettaglio lead — Phase 20 (KB-01, KB-02)
  • ✓ Agente AI: Claude Opus 4.8, Zod schema 20+ sezioni, snapshot JSONB proposals, form admin — Phase 21 (AI-01, AI-02)
  • ✓ Deck pubblico /preventivo/[slug]: 20+ slide 100vh, keyboard nav; accept/reject accepted_at immutabile — Phase 22 (PUB-01, PUB-02)

Validated in v2.3 Email & Accesso (shipped 2026-07-29):

  • ✓ Gate OTP sul portale cliente: whitelist client_emails, codice 6 cifre via Resend, sessione firmata 90 giorni (non 30: modificata il 2026-07-28), revoca in blocco dall'admin — Phase 23/24/25 (OTP-01..08). Migr. 0015.
  • ✗ PUB-03 / SEND-01/02 (invio preventivo via email) non consegnato: rinviato al backlog il 2026-07-28. Il preventivo si manda a mano; l'infrastruttura Resend è comunque in prod.

Validated in v2.4 Post-vendita (in produzione):

  • ✓ Ciclo di vita dei servizi ricorrenti: project_offers.status + end_date, forecast che si ferma, comandi Sospendi/Riattiva/Cessa, stato visibile al cliente — Phase 13 (RET-01..05). Migr. 0016.
  • ✓ Anteprima admin in sola lettura del portale cliente + toggle password sul login — Phase 26 (PREV-01/02, AUTH-09).

Active

Nessun requisito in lavorazione. Il prossimo va scelto dal backlog in REQUIREMENTS.md.

Out of Scope

  • Fatturazione e invio fatture — la gestione contabile resta fuori, solo stato pagamenti
  • App mobile nativa — solo web responsive
  • Multi-utente con team — solo tu come admin per ora
  • Prezzi singoli visibili al cliente — vede solo il totale accettato
  • File hosting — documenti solo come URL esterni (v1 constraint, ancora valido)
  • Sezioni analitiche stile Notion (psicologia, rating, performance) — fuori v2.1, eventuale milestone futura
  • Deploy separati per modulo (architettura OMC multi-app) — non finché un modulo non cresce abbastanza da giustificarlo

Context

  • Produzione: hub.iamcavalli.net su Coolify (Hetzner), Postgres self-hosted, deploy via webhook Gitea (NON Vercel)
  • Stack: Next.js 16 App Router, Drizzle ORM, Auth.js v4 (admin), token middleware (clienti), Tailwind v4, shadcn/ui, @dnd-kit già in deps
  • Tutto sotto la stessa app: /admin/* (sessione Auth.js) + /client/[token]/* (token) + /preventivo/[slug] (pubblico)
  • La sidebar admin include: Dashboard, Leads (con toggle Lista/Kanban), Offerte, Catalogo, Preventivi (con CTA globale "Genera preventivo")
  • Stack v2.2: @anthropic-ai/sdk@0.105.0 (Claude Opus 4.8), @dnd-kit (Kanban), nanoid (slug proposals)
  • DB live: migrazioni applicate a prod fino alla 0016; proposals con content jsonb snapshot; client_transcripts per lead; client_emails/otp_codes per il gate OTP
  • Migrations sono manuali: SQL a mano applicato via SSH + docker exec PRIMA di pushare il codice schema-dipendente (procedura in CLAUDE.md); drizzle-kit generate rotto da Phase 8
  • ANTHROPIC_API_KEY in Coolify — aggiunta 2026-06-20 via PHP artisan; costo ~$0.44/preventivo (Opus 4.8)
  • Il flusso commerciale reale: call con lead → transcript incollato → genera preventivo AI → deck pubblica → cliente sceglie tier → vinto/perso

Constraints

  • Data Safety (LOCKED): migration solo additive su clients, projects, payments, phases — qualsiasi consolidamento di catalogo va pianificato senza drop/truncate
  • Architettura (LOCKED): clients.token separato e rotatable; quote_items mai esposti via client API; deliverables.approved_at immutabile; no file hosting
  • Compartimenti stagni: un'unica app Next.js, moduli isolati (route group + service layer propri) su Postgres condiviso; migrations solo additive; niente deploy separati per ora (modello OMC adattato)
  • NO database esterno / Excel come fonte dati: Postgres resta l'unica fonte di verità — il problema è la UX, non il dato
  • Numerazione fasi: progressiva e mai riusata — v1.0 16, v2.0 710, v2.1 1117 (13/15/16/17 mai eseguite), v2.2 1822, v2.3 2325, v2.4 13 (ripresa dal congelamento) + 26

Key Decisions

Decision Rationale Outcome
Link segreto senza login per i clienti Massima semplicità — nessun account da creare, zero friction ✓ Good
Dashboard prima del flusso Claude Clienti attivi ora, la visibilità al cliente è il valore immediato ✓ Good
Preventivo: cliente vede solo il totale Il dettaglio dei prezzi è informazione commerciale riservata ✓ Good
Suite unica sotto /admin/* invece di 3 app separate Stesso DB, stesso deploy, auth unica — overhead di 3 app ingiustificato per singolo admin ✓ Confermato — formalizzato come "compartimenti stagni" (2026-06-12)
Catalogo servizi unificato (una tabella services) Due cataloghi paralleli (service_catalog + offer_services) duplicano manutenzione prezzi ✓ Good — tabella services live da Phase 7, consolidamento legacy in v2.1
Tier offerte indipendenti (A/B/C separati, stesso tag) Più semplice di un meccanismo di ereditarietà; ogni tier configurato a sé ✓ Good — usato in deck slide Pricing/StagesRecap/Comparison
Prezzi pacchetti per-preventivo, non da catalogo Permette di alzare i prezzi nel tempo senza toccare il catalogo ✓ Good — public_price per tier, snapshot in proposals.content
Al "Vinto" le fasi dell'offerta sono COPIATE nel progetto Il progetto resta modificabile senza toccare il template offerta — Pending (PROP-04, backlog)
NO DB esterno/Excel, Postgres unica fonte Lezione 2026-06-11: due fonti disallineate hanno causato il crash Phase 10 ✓ Good
Catalogo/Offerte UX = database view custom (non Notion-clone) Notion troppo complesso per v1; serve velocità, non sezioni analitiche ✓ Good — confermato in v2.1
Tab "Preventivo" rimossa, "Offerte" → "Servizi attivi" Preventivo Builder è l'unico flusso; accepted_total già coperto da Payments ✓ Confermato — zero perdita funzionale verificata (2026-06-13)
Ordine: Offer Studio (UX dato) prima, Proposal AI (AI) dopo L'AI è l'ultimo miglio, serve un dato pulito e veloce da gestire prima ✓ Good — strategia validata: catalogo+offerte puliti → AI in v2.2
Output AI = JSON strutturato Zod → template fisso Coerenza visiva garantita; zero rischio HTML rotto dall'AI ✓ Good — 20+ sezioni Zod validate, deck sempre coerente
proposals.content = JSONB snapshot immutabile Prezzi e profilo consulente "bloccati" al momento della generazione ✓ Good — invariante di audit, coerente con accepted_at
Email Resend (PUB-03) deferred Scope minimo funziona; link condiviso manualmente per ora — Pending — rinviata di nuovo il 2026-07-28, il mailer però è in prod
Il gate OTP sta in cima alla page, mai nel layout Nell'App Router il page è renderizzato in parallelo al layout: gattare nel layout lascia i dati nel payload RSC ✓ Good — verificato: 46.907 → 17.594 byte di HTML
Sessione OTP a 90 giorni invece di 30 Rientro più fluido per il cliente, compensato dalla revoca in blocco lato admin (OTP-08) ✓ Good — in prod dal 2026-07-29
Storico di vendita ≠ forecast getOffersSoldBreakdown non filtra per stato: escludere le offerte cessate riscriverebbe il fatturato passato ✓ Good — Phase 13
Anteprima admin del portale in sola lettura Le API client autenticano sul token nel body, non sulla sessione: un click distratto approverebbe un deliverable, e approved_at è immutabile (LOCKED #3) ✓ Good — protezione a livello UI, deviazione da LOCKED #4 accettata (Phase 26)

Evolution

This document evolves at phase transitions and milestone boundaries.

After each phase transition (via /gsd-transition):

  1. Requirements invalidated? → Move to Out of Scope with reason
  2. Requirements validated? → Move to Validated with phase reference
  3. New requirements emerged? → Add to Active
  4. Decisions to log? → Add to Key Decisions
  5. "What This Is" still accurate? → Update if drifted

After each milestone (via /gsd-complete-milestone):

  1. Full review of all sections
  2. Core Value check — still the right priority?
  3. Audit Out of Scope — reasons still valid?
  4. Update Context with current state

Last updated: 2026-08-08 — v2.3 archiviata, v2.4 Post-vendita corrente (Phase 13 + 26 in produzione)