5177a3700a
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>
157 lines
8.1 KiB
Markdown
157 lines
8.1 KiB
Markdown
# Roadmap: ClientHub
|
||
|
||
## Milestones
|
||
|
||
- ✅ **v1.0 Client Portal & Offer System** — Phases 1–6 (shipped 2026-06-10) — [archive](milestones/v1.0-ROADMAP.md)
|
||
- ✅ **v2.0 Business Operations Suite** — Phases 7–10 (shipped 2026-06-13) — [archive](milestones/v2.0-ROADMAP.md)
|
||
- ✅ **v2.1 Offer Studio + CRM** — Phases 11–14 parziale (chiuso 2026-06-19, reset → v2.2)
|
||
- ✅ **v2.2 Sales Loop** — Phases 18–22 (shipped 2026-06-20) — [archive](milestones/v2.2-ROADMAP.md)
|
||
- ✅ **v2.3 Email & Accesso** — Phases 23–25 (shipped 2026-07-29)
|
||
- 🔨 **v2.4 Post-vendita** — Phase 13 (in corso)
|
||
|
||
## Phases
|
||
|
||
<details>
|
||
<summary>✅ v1.0 + v2.0 + v2.1 (Phases 1–17) — SHIPPED / CHIUSE</summary>
|
||
|
||
Vedi archivi:
|
||
- `milestones/v1.0-ROADMAP.md` — Phases 1–6
|
||
- `milestones/v2.0-ROADMAP.md` — Phases 7–10
|
||
- Phases 11, 12, 14 — Offer Studio + CRM Attio (shipped in prod)
|
||
- Phases 13, 15, 16, 17 — congelate/abbandonate/ri-scopate in v2.2
|
||
|
||
</details>
|
||
|
||
<details>
|
||
<summary>✅ v2.2 Sales Loop (Phases 18–22) — SHIPPED 2026-06-20</summary>
|
||
|
||
- [x] Phase 18: Cleanup & Consolidamento (3/3 plans) — completed 2026-06-19
|
||
- [x] Phase 19: Pipeline CRM Kanban (1/1 plan) — completed 2026-06-19
|
||
- [x] Phase 20: Knowledge Base Cliente (3/3 plans) — completed 2026-06-20
|
||
- [x] Phase 21: Agente AI — generazione preventivo (1/1 plan) — completed 2026-06-20
|
||
- [x] Phase 22: Pagina pubblica preventivo (1/1 plan, PUB-03 deferred) — completed 2026-06-20
|
||
|
||
Archivio completo: [milestones/v2.2-ROADMAP.md](milestones/v2.2-ROADMAP.md)
|
||
|
||
</details>
|
||
|
||
### 🔨 v2.3 — Email & Accesso (Phases 23–25)
|
||
|
||
- [x] **Phase 23: Resend Setup** — SDK Resend + `src/lib/mailer.ts` + template OTP *(l'invio preventivo è stato rinviato a v2.4 il 2026-07-28)*
|
||
- [x] **Phase 24: Schema + Whitelist Admin** — Tabelle `client_emails` e `otp_codes`, admin UI gestione whitelist + revoca sessioni
|
||
- [x] **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 ricorrenti** — `project_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 |
|
||
|-------|-----------|-------|--------|-----------|
|
||
| 1–6. Foundation → UX Overhaul | v1.0 | 24/24 | ✅ Done | 2026-06-10 |
|
||
| 7–10. 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 | — |
|
||
| 16–17. 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*
|