docs: apre v2.5 "Audit" e rimette in pari roadmap e requisiti

La roadmap era ferma al 2026-08-08 e diceva ancora "nessuna fase aperta" mentre
v2.5 era gia' partita e Phase 27 era a meta'; REQUIREMENTS.md era ancora quello
di v2.4. STATE.md invece era corretto — segno che aggiornare solo quello non
basta. Da qui la divisione dei ruoli, ora esplicita in testa a ogni file:

- STATE.md        orientamento breve (99 righe): dove sta cosa, come funziona il
                  motore, i blocchi vivi. Niente narrativa.
- ROADMAP.md      tutte le fasi 1->30, con lo stato di ciascuna
- REQUIREMENTS.md i 25 requisiti di v2.5 (AUD-01..25) e il backlog
- STATUS.md       l'unica narrativa lunga: lezioni e note tecniche

v2.4 chiusa e archiviata in milestones/v2.4-REQUIREMENTS.md.

Decisione nuova: il documento di restituzione usa il design system dell'area
admin ("Quiet Luxury"), non una tipografia sua — token semantici, Plus Jakarta
Sans, Geist Mono per metriche e date, StatusBadge per gli impatti. Sostituisce
la deroga tipografica prevista dal piano. I font sono gia' self-hostati da
next/font/google, quindi la CSP font-src 'self' e' soddisfatta senza lavoro, e
il documento non aggiunge debito a DEBT-01 perche' nasce gia' a token.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 17:48:46 +02:00
parent 24213e7251
commit 8000d562dc
5 changed files with 278 additions and 104 deletions
+79 -29
View File
@@ -1,47 +1,97 @@
# Requirements: ClientHub v2.4 Post-vendita
# Requirements: ClientHub v2.5 Audit
**Definiti:** 2026-08-08 (ricostruiti a posteriori — v2.4 è partita senza requisiti scritti)
**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.
**Definiti:** 2026-08-16 (piano approvato) · **rivisti:** 2026-08-18 (motore)
**Core Value della milestone:** L'imprenditore paga un'analisi del suo sito e riceve un
documento che gli dice, con numeri misurati, cosa non funziona e cosa costa — non un
elenco di quaranta punti generato da un tool gratuito.
Milestone precedente: [v2.3 Email & Accesso](milestones/v2.3-ROADMAP.md), shipped 2026-07-29.
Milestone precedente: [v2.4 Post-vendita](milestones/v2.4-REQUIREMENTS.md), chiusa 2026-08-08.
## Consegnati
Piani di riferimento (fuori dal repo, in `~/.claude/plans/`):
`dovremmo-fare-una-cosa-woolly-puddle.md` (documento, editor, template) +
`vorrei-solo-farti-capire-radiant-valley.md` (motore — sostituisce §6/§7 del primo).
### Ciclo di vita dei servizi ricorrenti (Phase 13) — ✅ in produzione 2026-08-01
## Il prodotto
- [x] **RET-01**: Un'offerta ricorrente assegnata a un progetto ha uno stato (attivo / sospeso / cessato) e una data di fine opzionale
- [x] **RET-02**: L'admin può sospendere, riattivare e cessare un retainer dalla tab Offerte del progetto
- [x] **RET-03**: Il forecast a 12 mesi smette di sommare un retainer sospeso, cessato o oltre la sua `end_date`
- [x] **RET-04**: Lo storico del venduto (`getOffersSoldBreakdown`) **non** filtra per stato — escludere le cessate riscriverebbe il passato
- [x] **RET-05**: Il cliente vede stato, "attivo dal / fino al" e "canone mensile"; le offerte cessate non gli arrivano
Tre livelli venduti, che sono **configurazioni di un unico documento**, non tre documenti:
### Anteprima admin e login (Phase 26) — ✅ in produzione 2026-08-08
| Livello | Blocchi inclusi |
|---|---|
| **Radiografia** | 1, 2, 2b, 3, 4, 5, 8, 9 |
| **Prima/Dopo** | + 6 (il redesign), 6b (cosa il redesign non risolve) |
| **Rotta** | + 7 (le ottimizzazioni, con priorità e impegno in giornate) |
- [x] **PREV-01**: L'admin può aprire il portale di un cliente in sola lettura senza passare dal gate OTP (`?preview=1` + sessione Auth.js valida)
- [x] **PREV-02**: In anteprima approvazione e composer messaggi sono disattivati a livello di UI
- [x] **AUTH-09**: Il campo password del login admin ha un toggle mostra/nascondi
I blocchi non pertinenti **non esistono nel DOM**, non sono nascosti via CSS.
## Backlog v2.4+ (non pianificati)
## Requisiti
Ereditati dalle chiusure di milestone precedenti, nessuno in corso:
### Motore (Phase 27)
- [ ] **SEND-01 / SEND-02** — Invio del link `/preventivo/[slug]` via email dall'admin. Il mailer (`src/lib/mailer.ts`) è già pronto e in produzione dalla v2.3: manca solo il pulsante e l'action. *Rinviati il 2026-07-28.*
- [ ] **PROP-03** — Stripe Payment Link sul deck pubblico del preventivo. *Rinviato al kickoff v2.3.*
- [ ] **PROP-04** — Auto-provisioning di cliente / progetto / fasi al passaggio del lead a "Vinto". *Rinviato al kickoff v2.3.*
- [ ] **RET-06** — Canoni mensili tracciabili (agosto pagato / settembre no). **Serve una tabella nuova**: `payments` è protetta dai vincoli di Data Safety e la sua riscalatura è pensata per i piani una tantum. *Fuori scope di Phase 13.*
- [ ] **OFFER-14** — Sezioni analitiche stile Notion sull'offerta. *Rinviato al kickoff v2.1.*
- [ ] **ARCH-01** — Split del modulo "compartimento stagno" in un deploy separato. *Solo se il modulo cresce.*
- [ ] **DEBT-01** — Debito design: **~40 file, ~450 occorrenze** di palette Tailwind raw e hex literal al posto dei token semantici. I cluster: `/admin/projects/[id]` e i suoi tab (~182), `/admin/offers/[id]/edit` (~79), `/admin/clients/[id]` (~59), tutto `/quote/[token]` (~48, ed è rivolto al cliente), `ChatPanel` del portale (37), più `ui/dialog.tsx` che propaga il look vecchio a ogni modale. Esclusi perché legittimi: `AdminSidebar` (eccezione brand documentata), `src/lib/mailer.ts` (HTML email, niente CSS var), i colori di stato di `StatusBadge` (sanzionati dal design system, hanno già le varianti `dark:`). *Misurato il 2026-08-08 — la stima precedente di "11 pagine" era sottostimata.*
- [ ] **DEBT-02** — Tabelle legacy `service_catalog` / `offer_services` / `offer_micro_services` come deadweight; `createService` / `serviceSchema` dead code in `src/app/admin/catalog/actions.ts`.
- [x] **AUD-01**: Schema additivo per audit, finding, ottimizzazioni, rubrica, esiti, run e visite — *migration `0017_audits.sql`, in prod 2026-08-18*
- [x] **AUD-02**: La rubrica del motore (264 voci falsificabili) vive in `checklist_items`, non nel documento — *in prod 2026-08-18*
- [x] **AUD-03**: Le fonti raccolgono **rilevazioni, non stime**: PageSpeed (153 audit sul DOM renderizzato), CrUX (utenti reali), Wayback, RDAP, robots/sitemap/JSON-LD, header — *`src/lib/audit/sources/`, provato sul campo 2026-08-18, non ancora pushato*
- [x] **AUD-04**: Ogni fonte fallisce in modo **non fatale** e dice *perché*: "non ha risposto" e "ha risposto che non ci sono dati" sono informazioni diverse
- [x] **AUD-05**: Quando CrUX non ha dati di campo il documento lo **dice** ("i visitatori non sono abbastanza numerosi perché Google raccolga dati"), non lascia un buco — *`nota` in `crux.ts`; il caso "zero dati" resta da vedere su un sito vero*
- [ ] **AUD-06**: Ogni output di modello è validato con Zod, `safeParse`, fallimento duro — nessun loop di riparazione (precedente: `src/lib/proposal/schema.ts`)
- [ ] **AUD-07**: Quattro sub-agent in parallelo (checklist, visivo, storico, tecnico) più un sintetizzatore che **incrocia** le loro osservazioni in un solo finding con più evidenze indipendenti
- [ ] **AUD-08**: Massimo **10 finding**, ordinati per impatto su tre soli valori (`alto|medio|basso`); la sfumatura sta nell'ordine dentro il gruppo
- [ ] **AUD-09**: Disciplina sui numeri imposta nel prompt di sistema — un numero entra nel documento solo se misurato, e ogni numero consegnato è rintracciabile in `audit_runs.raw`
- [ ] **AUD-10**: Fan-out con tetto di concorrenza e retry con backoff sulle 429/529 di Anthropic
- [ ] **AUD-11**: Heartbeat a ogni passo su `audit_runs`; una run senza battito va in `error` e "Rilancia" riparte dall'ultimo passo completato *(un redeploy Coolify uccide un job in corso)*
### Storage immagini (Phase 28)
- [ ] **AUD-12**: Volume persistente Coolify su `/app/uploads`, lettura da `/api/uploads/[...path]` con guardia sul path traversal, whitelist MIME e limite di dimensione
- [ ] **AUD-13**: Due immagini caricate a mano per audit (hero **prima** e **dopo** del redesign, JPG ≤ 512 KB); due scritte dalla pipeline (screenshot mobile e desktop da PageSpeed)
### Editor admin (Phase 29)
- [ ] **AUD-14**: Creazione **manuale** di un audit (livello, profilo, URL, cliente/lead). L'ingresso Whop è predisposto nello schema (`origin`, `external_ref`) ma **non costruito**
- [ ] **AUD-15**: Editor a payload intero (modello: `admin/offers/actions.ts`) che **salva sempre, anche a metà** — tutti i campi di contenuto sono nullable, la validazione di completezza scatta solo alla consegna
- [ ] **AUD-16**: Riordino di finding e ottimizzazioni con `@dnd-kit/sortable`, con re-sync degli id dei figli
- [ ] **AUD-17**: Il **blocco 8 (La direzione) resta manuale, foglio bianco** — è il blocco che giustifica il prezzo; se diventa formula il cliente lo sente
- [ ] **AUD-18**: Il registro delle visite è visibile nell'editor, in ordine cronologico
### Documento pubblico (Phase 30)
- [ ] **AUD-19**: `/audit/[slug]` — pagina privata, `X-Robots-Tag: noindex, nofollow`, rate limit sul matcher di `proxy.ts`
- [ ] **AUD-20**: Il template è **congelato alla creazione** (`template_version`): migliorare il documento tocca gli audit successivi, mai quelli già consegnati
- [ ] **AUD-21**: PDF via **print CSS**, non libreria: interruzioni di pagina corrette, slider impilato in due immagini, **nessun marcatore di lavorazione sopravvissuto**
- [ ] **AUD-22**: In **scala di grigi** impatti e metriche restano distinguibili — il colore non può essere l'unico portatore di informazione
- [ ] **AUD-23**: Il documento usa **il design system dell'area admin** ("Quiet Luxury", `design-reference/DESIGN-SYSTEM.md`): token semantici, Plus Jakarta Sans per il testo, **Geist Mono per metriche, punteggi e date**, e i primitivi già esistenti (`StatusBadge` per gli impatti). *Decisione del 2026-08-18, sostituisce la deroga tipografica prevista dal piano.* Due conseguenze: i font sono già self-hostati da `next/font/google`, quindi la CSP `font-src 'self'` è soddisfatta senza lavoro; e il documento **non aggiunge debito a DEBT-01** perché nasce già a token.
- [ ] **AUD-24**: Tracciamento delle aperture (`view`) e delle stampe (`print`) via isola client + Server Action; **un admin loggato non viene contato** (altrimenti i numeri li inquiniamo noi rileggendo le bozze)
- [ ] **AUD-25**: L'IP non si salva in chiaro — SHA-256 di `ip + NEXTAUTH_SECRET`, come il digest del gate admin
## Vincoli che questa milestone tocca
- **LOCKED #5 (no file hosting)** — emendato limitatamente agli asset di audit, deroga già annotata in `CLAUDE.md`. Non estendere ad altre entità.
- **Nessun renderer headless, da nessuna parte.** Il VPS non regge Chromium (RAM), e non serve: gli audit Lighthouse arrivano già fatti sul DOM renderizzato.
## Backlog (ereditato, nessuno in corso)
- [ ] **SEND-01 / SEND-02** — Invio del link `/preventivo/[slug]` via email. Il mailer è già in produzione dalla v2.3: manca il pulsante e l'action. *Rinviati il 2026-07-28.*
- [ ] **PROP-03** — Stripe Payment Link sul deck pubblico del preventivo.
- [ ] **PROP-04** — Auto-provisioning cliente / progetto / fasi al passaggio del lead a "Vinto".
- [ ] **RET-06** — Canoni mensili tracciabili. **Serve una tabella nuova**: `payments` è protetta dai vincoli di Data Safety.
- [ ] **OFFER-14** — Sezioni analitiche stile Notion sull'offerta.
- [ ] **ARCH-01** — Split del modulo "compartimento stagno" in un deploy separato. *Solo se cresce.*
- [ ] **DEBT-01** — Debito design: ~40 file, ~450 occorrenze di palette raw/hex al posto dei token. Cluster in `/admin/projects/[id]` (~182), `/admin/offers/[id]/edit` (~79), `/admin/clients/[id]` (~59), `/quote/[token]` (~48, ed è rivolto al cliente), `ChatPanel` (37), `ui/dialog.tsx`. *Misurato il 2026-08-08.*
- [ ] **DEBT-02** — Tabelle legacy `service_catalog` / `offer_services` / `offer_micro_services`; `createService` / `serviceSchema` dead code.
## Rinviati esplicitamente da v2.5
- **Allegato tecnico** — seconda vista sugli stessi finding con registro da sviluppatore (selettori, file, stime). Renderebbe vera la promessa del blocco 9 *"il documento resta tuo e puoi darlo a chiunque lavorerà sul sito"*. Da valutare **dopo il primo audit consegnato**.
- **Affettare lo screenshot a pagina intera** — richiede `sharp`, da verificare su `node:20-alpine`. Non serve in fase 1: `final-screenshot` (250×498) è leggibile.
- **Ingresso via webhook Whop** — schema predisposto, costruzione in fase 2.
## Aperto, non un requisito
**Whitelist del portale vuota per 3 clienti su 4.** La migration 0015 ha seedato solo
`mario@test.it` (cliente di test). Protocollo Estetico, Caruso Speaker e Teckell hanno
whitelist vuota e finché lo è **il loro portale non è accessibile**. Si popola da
`/admin/clients/<id>`"Accessi al portale", poi va reinviato il link.
`mario@test.it`. Protocollo Estetico, Caruso Speaker e Teckell hanno whitelist vuota e
finché lo è **il loro portale non è accessibile**. Si popola da `/admin/clients/<id>`
"Accessi al portale", poi va reinviato il link.
## Fuori scope
- File hosting (vincolo LOCKED #5: i documenti restano URL esterni).
- Tabella utenti / multi-admin: l'auth resta una singola credenziale da env.
- File hosting per i documenti del portale cliente: restano URL esterni (LOCKED #5, non emendato per quelli).