Files
clienthub/.planning/ROADMAP.md
T
simone 5177a3700a feat(offers): ciclo di vita dei servizi ricorrenti (v2.4 Phase 13)
Un retainer, una volta assegnato, non si poteva fermare: project_offers
aveva solo start_date e il forecast sommava il canone a ogni mese
dell'orizzonte da li in poi, per sempre. Un cliente che disdiceva
continuava a gonfiare il forecast a 12 mesi e a vedersi l'abbonamento
attivo nel portale.

- migration 0016 (gia applicata a prod): project_offers.status
  (attivo|sospeso|cessato, CHECK) + end_date. Additiva pura, default
  'attivo' cosi le righe esistenti conservano il comportamento di prima
- forecast: i retainer si fermano a end_date, sospesi e cessati escono.
  getOffersSoldBreakdown NON filtra per stato: e uno storico di vendita,
  escludere le cessate riscriverebbe il passato
- offersAcceptedTotal esclude le cessate (default del piano pagamenti)
- admin: comandi Sospendi/Riattiva/Cessa + data fine nella tab Offerte,
  solo per i ricorrenti. setProjectOfferLifecycle valida con Zod e filtra
  anche per project_id, cosi un id arbitrario non tocca altri progetti
- portale: "Attivo dal", "fino al", badge In pausa, "Canone mensile"
  invece di "Prezzo finale"; le cessate non arrivano al client
- fix: un retainer sospeso continuava a intestare i pagamenti "Totale
  Pagamento Mensile" e a sovrascrivere l'importo

Igiene nello stesso giro:
- STATUS.md riscritto: era fermo al 22 giugno e diceva che node/docker non
  sono disponibili sul server e che le migrazioni si applicano da locale
  con uno script postgres.js — il contrario della procedura reale
- rimossi ChatSection/CommentList/CommentForm, senza importatori (308 righe)
- overrides postcss>=8.5.18 e sharp>=0.35.0: 3 CVE high transitive di Next
  senza fix upstream. npm audit ora pulito, build verde

Verifica: forecast controllato sui dati veri in 5 scenari (baseline
invariata, end_date, sospeso, cessato, ripristino); portale verificato nei
4 stati; tab admin verificata con Playwright sul build di produzione
(i comandi non compaiono sulle una tantum). Dati di test ripuliti,
tabelle protette invariate 4/5/11/10.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 18:18:28 +02:00

8.1 KiB
Raw Blame History

Roadmap: ClientHub

Milestones

  • v1.0 Client Portal & Offer System — Phases 16 (shipped 2026-06-10) — archive
  • v2.0 Business Operations Suite — Phases 710 (shipped 2026-06-13) — archive
  • v2.1 Offer Studio + CRM — Phases 1114 parziale (chiuso 2026-06-19, reset → v2.2)
  • v2.2 Sales Loop — Phases 1822 (shipped 2026-06-20) — archive
  • v2.3 Email & Accesso — Phases 2325 (shipped 2026-07-29)
  • 🔨 v2.4 Post-vendita — Phase 13 (in corso)

Phases

v1.0 + v2.0 + v2.1 (Phases 117) — SHIPPED / CHIUSE

Vedi archivi:

  • milestones/v1.0-ROADMAP.md — Phases 16
  • milestones/v2.0-ROADMAP.md — Phases 710
  • Phases 11, 12, 14 — Offer Studio + CRM Attio (shipped in prod)
  • Phases 13, 15, 16, 17 — congelate/abbandonate/ri-scopate in v2.2
v2.2 Sales Loop (Phases 1822) — SHIPPED 2026-06-20
  • Phase 18: Cleanup & Consolidamento (3/3 plans) — completed 2026-06-19
  • Phase 19: Pipeline CRM Kanban (1/1 plan) — completed 2026-06-19
  • Phase 20: Knowledge Base Cliente (3/3 plans) — completed 2026-06-20
  • Phase 21: Agente AI — generazione preventivo (1/1 plan) — completed 2026-06-20
  • Phase 22: Pagina pubblica preventivo (1/1 plan, PUB-03 deferred) — completed 2026-06-20

Archivio completo: milestones/v2.2-ROADMAP.md

🔨 v2.3 — Email & Accesso (Phases 2325)

  • Phase 23: Resend Setup — SDK Resend + src/lib/mailer.ts + template OTP (l'invio preventivo è stato rinviato a v2.4 il 2026-07-28)
  • Phase 24: Schema + Whitelist Admin — Tabelle client_emails e otp_codes, admin UI gestione whitelist + revoca sessioni
  • Phase 25: OTP Gate + Sessione — Gate OTP completo, sessione 90gg, rate limiting, no enumeration

Shipped 2026-07-29 (commit 27da969), verificata end-to-end su hub.iamcavalli.net. SEND-01/02 rinviati a backlog.

🔨 v2.4 — Post-vendita (Phase 13)

  • Phase 13: Ciclo di vita dei servizi ricorrentiproject_offers.status + end_date (migr. 0016), forecast che si ferma davvero, comandi Sospendi/Riattiva/Cessa nella tab Offerte, stato dell'abbonamento visibile al cliente.

Fuori scope di questo giro, rimandato: tracciamento dei canoni mese per mese (serve una tabella nuova — payments è protetta e la sua riscalatura è pensata per i piani una tantum).

Phase Details

Phase 23: Resend Setup + Invio Preventivo

Goal: Admin può inviare il link /preventivo/[slug] via email con un click dall'admin UI Depends on: Nothing — primo uso di Resend, nessuna dipendenza DB Requirements: SEND-01, SEND-02 Success Criteria (what must be TRUE):

  1. Admin fa click su "Invia preventivo" nel dettaglio lead/preventivo e l'email parte senza uscire dall'app
  2. Il destinatario riceve un'email in italiano con nome cliente e link cliccabile al deck pubblico
  3. L'invio usa Resend con le variabili d'ambiente configurate su Coolify (RESEND_API_KEY, RESEND_FROM)
  4. In caso di errore Resend, l'admin vede un messaggio di errore chiaro nell'UI (non un crash silenzioso) Plans: TBD UI hint: yes

Phase 24: Schema + Whitelist Admin

Goal: Admin può gestire la whitelist email di ogni cliente, con le tabelle DB pronte per l'OTP gate Depends on: Phase 23 (Resend SDK già installato e variabili d'ambiente configurate) Requirements: OTP-01 Success Criteria (what must be TRUE):

  1. Admin può aggiungere una o più email alla whitelist di un cliente dalla pagina dettaglio cliente
  2. Admin può rimuovere un'email dalla whitelist di un cliente
  3. Le tabelle client_emails e otp_codes esistono in produzione (migration additive applicata via SSH prima del codice)
  4. La migration non tocca nessuna delle tabelle protette (clients, projects, payments, phases) Plans: TBD UI hint: yes

Phase 25: OTP Gate + Sessione

Goal: Il portale /client/[token]/* richiede verifica OTP email prima di mostrare la dashboard Depends on: Phase 24 (tabelle client_emails e otp_codes in prod) Requirements: OTP-02, OTP-03, OTP-04, OTP-05, OTP-06, OTP-07 Success Criteria (what must be TRUE):

  1. Cliente senza sessione OTP valida vede una schermata "inserisci la tua email" al posto della dashboard
  2. Inserita un'email in whitelist, il cliente riceve il codice OTP via Resend; inserendo il codice corretto ottiene accesso con cookie valido 30 giorni
  3. Un'email non in whitelist non riceve OTP — il messaggio d'errore mostrato è identico a quello per email valide (no enumeration)
  4. Un codice OTP non utilizzato entro 15 minuti viene rifiutato; il cliente deve richiederne uno nuovo
  5. Tentativi ripetuti sugli endpoint OTP vengono bloccati dal rate limiter (no brute force) Plans: TBD

Progress

Phase Milestone Plans Status Completed
16. Foundation → UX Overhaul v1.0 24/24 Done 2026-06-10
710. Unified Catalog → CRM Pipeline v2.0 12/12 Done 2026-06-13
11. Catalog Database-View UX v2.1 4/4 Done 2026-06-13
12. Offer Editor Tier A/B/C v2.1 5/5 Done 2026-06-18
13. Workspace Servizi Attivi v2.1 Congelata
14. CRM Attio-style & Fix v2.1 3/3 Done 2026-06-14
15. Dashboard Revenue Stats v2.1 Abbandonata
1617. Proposal AI originale v2.1 Ri-scopata in v2.2
18. Cleanup & Consolidamento v2.2 3/3 Done 2026-06-19
19. Pipeline CRM Kanban v2.2 1/1 Done 2026-06-19
20. Knowledge Base Cliente v2.2 3/3 Done 2026-06-20
21. Agente AI Preventivo v2.2 1/1 Done 2026-06-20
22. Pagina Pubblica + Deck v2.2 1/1 Done 2026-06-20
23. Resend Setup v2.3 1/1 Done 2026-07-28
24. Schema + Whitelist Admin v2.3 1/1 Done 2026-07-28
25. OTP Gate + Sessione v2.3 1/1 Done 2026-07-29
13. Ciclo di vita servizi ricorrenti v2.4 1/1 🔨 In corso

Requirement Coverage (v2.3)

Requirement Phase
SEND-01 Phase 23
SEND-02 Phase 23
OTP-01 Phase 24
OTP-02 Phase 25
OTP-03 Phase 25
OTP-04 Phase 25
OTP-05 Phase 25
OTP-06 Phase 25
OTP-07 Phase 25

Mapped: 9/9. No orphans.


Dependency Chain (v2.3)

Phase 23 (Resend config + SDK)
    └── Phase 24 (schema DB additive: client_emails + otp_codes)
            └── Phase 25 (OTP gate + sessione cookie 30gg)

Phase 23 first: Resend SDK e variabili d'ambiente sono infrastruttura condivisa con Phase 25 (email OTP). Phase 24 before Phase 25: le tabelle client_emails e otp_codes devono essere in prod (via SSH migration) prima del gate.


Implementation Notes (v2.3)

Migration constraint: client_emails e otp_codes sono nuove tabelle — migration additiva pura. SQL a mano (drizzle-kit generate rotto da Phase 8). Applicare via SSH tunnel PRIMA di pushare il codice dipendente.

OTP middleware layer: Il token middleware esistente (proxy.ts → /api/internal/validate-token) rimane invariato. Il gate OTP è uno strato aggiuntivo dopo la validazione del token, non un suo rimpiazzo.

Resend shared infra: La stessa istanza Resend client e le stesse variabili d'ambiente (RESEND_API_KEY, RESEND_FROM) servono sia Phase 23 (email preventivo) sia Phase 25 (email OTP). Configurare una volta in Phase 23, riusare in Phase 25.

Security invariants (Phase 25, come consegnata): rate limiting su entrambi gli endpoint OTP; risposta identica per email in whitelist e non; OTP 6 cifre, scade 15 minuti, monouso (consumed_at al primo uso), max 5 tentativi; cookie HttpOnly + Secure + SameSite=Lax, MaxAge 90 giorni (non 30: modificato il 2026-07-28, compensato dalla revoca admin), per-cliente. Il gate sta in cima alla page, non nel layout — vedi la lezione in STATE.md.


Roadmap created: 2026-06-21 — v2.3 Email & Accesso