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).
+43 -9
View File
@@ -7,7 +7,8 @@
-**v2.1 Offer Studio + CRM** — Phases 11, 12, 14 (chiusa per reset 2026-06-19) — [archive](milestones/v2.1-ROADMAP.md)
-**v2.2 Sales Loop** — Phases 1822 (shipped 2026-06-20) — [archive](milestones/v2.2-ROADMAP.md)
-**v2.3 Email & Accesso** — Phases 2325 (shipped 2026-07-29) — [archive](milestones/v2.3-ROADMAP.md)
- 🔨 **v2.4 Post-vendita** — Phases 13 + 26 (entrambe in produzione)
- **v2.4 Post-vendita** — Phases 13 + 26 (entrambe in produzione, 2026-08-01 / 2026-08-08)
- 🔨 **v2.5 Audit** — Phases 2730 — documento di restituzione del servizio di analisi sito
## Phases
@@ -47,22 +48,50 @@ Archivio completo: [milestones/v2.3-ROADMAP.md](milestones/v2.3-ROADMAP.md)
</details>
### 🔨 v2.4 — Post-vendita (Phases 13 + 26)
### v2.4 — Post-vendita (Phases 13 + 26)
- [x] **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. ✅ **prod 2026-08-01** (`5177a37`) — [13-SUMMARY.md](phases/13-ciclo-vita-servizi-ricorrenti/13-SUMMARY.md)
- [x] **Phase 26: Anteprima admin del portale + toggle password**`?preview=1` con sessione Auth.js valida apre il portale di un cliente in sola lettura, senza gate OTP. ✅ **prod 2026-08-08** (`09a5b1f`, `187550f`) — [26-SUMMARY.md](phases/26-anteprima-admin-e-login/26-SUMMARY.md)
**Nessuna fase aperta.** Il prossimo lavoro va scelto dal backlog in
[REQUIREMENTS.md](REQUIREMENTS.md) — i candidati principali sono RET-06 (canoni
mensili tracciabili, richiede una tabella nuova perché `payments` è protetta) e
DEBT-01 (debito design, ~40 file).
### 🔨 v2.5 — Audit (Phases 2730) · *in corso*
Il servizio di analisi sito (tre livelli: **Radiografia / Prima-Dopo / Rotta**) diventa
un documento privato su `/audit/[slug]`, generato da un motore multi-agente e rifinito a
mano prima della consegna. Piano approvato il 2026-08-16, motore ripianificato il
2026-08-18.
- [ ] **Phase 27: Motore di analisi***in corso, ~50%*
- [x] Migration `0017_audits.sql` (7 tabelle additive) — **applicata in prod 2026-08-18**
- [x] `checklist_items` seminata, 264 voci — **in prod**
- [x] `src/lib/audit/sources/` — 5 moduli, **provati sul campo su giojello.com** (73 s, tutte le fonti hanno risposto). *Scritti, non pushati.*
- [ ] `src/lib/audit/schema.ts` + `agents/` (checklist, visual, history, technical, synthesis) con validazione Zod dura
- [ ] `src/lib/audit/pipeline.ts` con heartbeat su `audit_runs`
- [ ] **Phase 28: Storage immagini** — volume persistente Coolify, `ImageUploadField`, `/api/uploads/[...path]` con guardia sul path traversal. ⚠️ **Checkpoint bloccante: il volume va creato in Coolify PRIMA del deploy**, altrimenti gli upload si perdono a ogni redeploy.
- [ ] **Phase 29: Editor admin** — lista audit, editor a payload intero (modello: `admin/offers/actions.ts`), riordino finding e ottimizzazioni con `@dnd-kit/sortable`, registro visite
- [ ] **Phase 30: Pagina pubblica + PDF + tracciamento**`/audit/[slug]`, blocchi condizionali per livello, print CSS per il PDF, `<AuditVisitTracker>` che non conta le aperture da admin loggato
> I nomi di 2830 sono **derivati dalle sezioni §7/§8/§9 del piano approvato**, non ancora
> passati da `/gsd-plan-phase`. La numerazione riprende da 27 perché 1517 sono state
> abbandonate o ri-scopate.
**Ingresso Whop**: predisposto nello schema (`origin`, `external_ref`), **non costruito**
è fase 2, fuori da v2.5.
## Progress
Tutte le fasi del progetto, dalla 1 alla 30. La numerazione è **progressiva e mai
riusata**: i buchi (1517) sono fasi abbandonate o ri-scopate, non fasi mancanti.
| 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 |
| 1. Foundation & Client Dashboard | v1.0 | | ✅ Done | 2026-06 |
| 2. Admin Area & Interactive Features | v1.0 | | ✅ Done | 2026-06 |
| 3. Service Catalog & Quote Builder | v1.0 | — | ✅ Done | 2026-06 |
| 4. Progetti — Multi-Project per Cliente | v1.0 | — | ✅ Done | 2026-06 |
| 5. Offer System | v1.0 | — | ✅ Done | 2026-06 |
| 6. UX Overhaul — Sidebar + Dashboard | v1.0 | 24/24 tot. | ✅ Done | 2026-06-10 |
| 7. Claude AI Onboarding (v2) | v2.0 | — | ✅ Done | 2026-06 |
| 810. Unified Catalog → CRM Pipeline | v2.0 | 12/12 tot. | ✅ 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 |
| 14. CRM Attio-style & Fix | v2.1 | 3/3 | ✅ Done | 2026-06-14 |
@@ -78,7 +107,12 @@ DEBT-01 (debito design, ~40 file).
| 25. OTP Gate + Sessione | v2.3 | 1/1 | ✅ Done | 2026-07-29 |
| 13. Ciclo di vita servizi ricorrenti | v2.4 | 1/1 | ✅ Done | 2026-08-01 |
| 26. Anteprima admin + login | v2.4 | 1/1 | ✅ Done | 2026-08-08 |
| 27. Motore di analisi | v2.5 | 0/1 | 🔨 In corso (~50%) | — |
| 28. Storage immagini | v2.5 | 0/1 | ⏳ Da pianificare | — |
| 29. Editor admin | v2.5 | 0/1 | ⏳ Da pianificare | — |
| 30. Pagina pubblica + PDF | v2.5 | 0/1 | ⏳ Da pianificare | — |
---
*Roadmap aggiornata: 2026-08-08 — v2.3 archiviata, v2.4 documentata a posteriori*
*Roadmap aggiornata: 2026-08-18 — v2.4 chiusa, v2.5 "Audit" aperta (era assente: la roadmap
è rimasta ferma al 2026-08-08 mentre v2.5 partiva e Phase 27 arrivava a metà).*
+62 -61
View File
@@ -1,98 +1,99 @@
---
gsd_state_version: 1.0
milestone: v2.4
milestone_name: Post-vendita
milestone: v2.5
milestone_name: Audit
status: executing
stopped_at: "Phase 13 e 26 in produzione. Nessun lavoro in sospeso: il prossimo va scelto dal backlog in REQUIREMENTS.md."
last_updated: "2026-08-08T20:30:00.000Z"
last_activity: 2026-08-08 -- riordino della documentazione di progetto
stopped_at: "Phase 27 a metà: schema in prod, fonti scritte e provate sul campo. Prossimo: src/lib/audit/schema.ts + agents/."
last_updated: "2026-08-18T17:45:00.000Z"
last_activity: 2026-08-18 -- fonti del motore scritte e verificate su sito reale
progress:
total_phases: 2
completed_phases: 2
total_plans: 2
completed_plans: 2
percent: 100
total_phases: 4
completed_phases: 0
total_plans: 4
completed_plans: 0
percent: 25
---
# Project State
> Digest per i comandi `/gsd-*`. La narrativa completa — cosa è stato fatto, cosa
> manca, le lezioni operative — sta in **`STATUS.md`** alla radice del repo.
> Questo file resta sotto le 100 righe di proposito.
> **Digest breve, per orientarsi.** Narrativa e lezioni → **`STATUS.md`** (root);
> requisiti → **`REQUIREMENTS.md`**; tutte le fasi → **`ROADMAP.md`**.
> Questo file resta sotto le 100 righe: lo impone il template GSD.
## Project Reference
See: .planning/PROJECT.md (updated 2026-08-08)
**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 focus:** Milestone **v2.4 "Post-vendita"** — tutto ciò che era pianificato è in produzione. Nessuna fase aperta.
See: .planning/PROJECT.md · **Core value:** il cliente apre il link e vede a che punto è
il suo progetto, senza scrivere email. · **Current focus:** milestone **v2.5 "Audit"**
il servizio di analisi sito diventa un documento privato su `/audit/[slug]`.
## Current Position
Phase: 2 of 2 (Phase 13 Ciclo di vita servizi ricorrenti · Phase 26 Anteprima admin)
Plan: 2 of 2 in current milestone
Status: Phase complete — nessuna fase aperta, prossimo lavoro da scegliere dal backlog
Last activity: 2026-08-08 — riordino della documentazione (`.planning/` e doc di root)
Phase: 27 of 30 — Motore di analisi
Plan: schema e fonti fatti; agent, sintetizzatore e pipeline da scrivere
Status: nessun bloccante — prossimo passo `src/lib/audit/schema.ts` + `agents/`
Last activity: 2026-08-18 — `src/lib/audit/sources/` scritto e provato su giojello.com
Progress: [██████████] 100%
Progress: [███░░░░░░░] 25%
Entrambe le fasi sono **in produzione e verificate**:
## Dove sta cosa
- Phase 13 → `5177a37`, migr. 0016, prod 2026-08-01 · [13-SUMMARY.md](phases/13-ciclo-vita-servizi-ricorrenti/13-SUMMARY.md)
- Phase 26 → `09a5b1f` + `187550f`, prod 2026-08-08 · [26-SUMMARY.md](phases/26-anteprima-admin-e-login/26-SUMMARY.md)
| Cosa | Dove | Stato |
|---|---|---|
| Schema audit (7 tabelle) | `src/db/migrations/0017_audits.sql` + `src/db/schema.ts` | **in produzione** |
| Rubrica del motore, 264 voci | tabella `checklist_items`, sorgente `scripts/data/checklist.json` | **in produzione** |
| Fonti del motore (5 moduli) | `src/lib/audit/sources/` | scritto e provato, **non in prod** |
| Agent, sintetizzatore, pipeline | `src/lib/audit/{schema,agents,pipeline}.ts` | **da scrivere** |
| Editor admin e pagina pubblica | `src/app/admin/audit/`, `src/app/audit/[slug]/` | **da scrivere** |
| L'unico audit prodotto finora | `spike-audit-giojello.com.json` (root, **gitignorato**) | spike del 2026-08-16, **zero rilevazioni** |
| I due piani della milestone | `~/.claude/plans/``…woolly-puddle.md` (documento) + `…radiant-valley.md` (motore) | **fuori dal repo** |
## Come funziona il motore
Si incolla un URL. Nessun browser headless da nessuna parte.
1. **Raccolta in parallelo** (`sources/`, nessun LLM): PageSpeed, CrUX, Wayback, RDAP, robots/sitemap/JSON-LD, header. Ogni fonte fallisce in modo non fatale e dice *perché*.
2. **Quattro sub-agent in parallelo** (`agents/`): checklist, visivo, storico, tecnico. Producono osservazioni, non finding.
3. **Sintetizzatore** che le **incrocia**: quattro osservazioni deboli su temi diversi diventano un finding solo con quattro evidenze indipendenti. Massimo 10, per impatto.
4. **Editor admin** per rifinire, poi consegna su `/audit/[slug]`.
Vincolo che regge tutto: **un numero entra solo se misurato**, e dev'essere rintracciabile in `audit_runs.raw`.
## Performance Metrics
**Velocity:** 21 plans completati in totale — 7 (v2.1) + 9 (v2.2) + 3 (v2.3) + 2 (v2.4).
**Recent Trend:** — · v2.3 e v2.4 sono state eseguite fuori dal ciclo GSD, quindi non cronometrate.
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 13 | 1 | — | — |
| 26 | 1 | — | — |
*Updated after each plan completion*
**Velocity:** 21 plans completati (v2.1v2.4). Phase 27: spike ~1h, schema ~1h, fonti ~2h.
## Accumulated Context
### Decisions
Log completo in PROJECT.md (Key Decisions). Rilevanti per il lavoro corrente:
Log completo in `PROJECT.md`. Vive per il lavoro corrente:
- **[Phase 26, 2026-08-08] Deviazione consapevole dal vincolo LOCKED #4** — una route `/client/*` ora legge anche la sessione Auth.js per l'anteprima admin. Non indebolisce il gate per i clienti; annotata in `CLAUDE.md`.
- **[Phase 26] L'anteprima è in sola lettura a livello UI, non API** — le route `/api/client/*` autenticano sul token nel body. L'obiettivo è impedire l'incidente, non difendersi da sé stessi.
- **[Phase 13] Storico di vendita ≠ forecast** — `getOffersSoldBreakdown` non filtra per stato: escludere le offerte cessate riscriverebbe il fatturato passato.
- **[v2.3, 2026-07-28] Sessione OTP a 90 giorni invece di 30** — rientro più fluido, compensato dalla revoca in blocco lato admin (OTP-08).
- **[2026-08-18] Il documento usa il design system dell'area admin** — token semantici, Plus Jakarta Sans, Geist Mono per metriche e date, `StatusBadge` per gli impatti. Sostituisce la deroga tipografica del piano; i font sono già self-hostati da `next/font/google`, quindi la CSP è soddisfatta senza lavoro.
- **[2026-08-18] Nessun renderer headless** — PageSpeed dà 153 audit sul DOM renderizzato, cioè le osservazioni visive che prima richiedevano screenshot a mano.
- **[2026-08-18] Laboratorio ≠ campo, e la differenza è il risultato** — Lighthouse dà 7 ms di risposta server, CrUX dà TTFB p75 3.553 ms. Da qui il nome `risposta_server_ms`: con lo stesso nome il sintetizzatore li tratterebbe come un numero solo.
- **[2026-08-17] Il VPS non regge Chromium** — RAM, non disco. È la ragione per cui l'opzione headless non torna.
- **[2026-08-16] La checklist alimenta il MOTORE, non il documento** — se diventa il rendering della checklist, torna a sembrare un audit automatico gratuito.
- **[2026-08-16] Immagini** — le due del redesign le carica l'utente, le due dello stato di fatto le scrive la pipeline. Emenda LOCKED #5 solo per gli asset di audit.
### Pending Todos
[From .planning/todos/pending/ — ideas captured during sessions]
None yet.
### Pending Todos — nessuno (`.planning/todos/` non esiste)
### Blockers/Concerns
- **Whitelist portale vuota per 3 clienti su 4** (non bloccante: l'utente li re-invita) — da popolare da `/admin/clients/<id>` → "Accessi al portale".
- **`.env.local` punta al DB di PRODUZIONE** e non è allineato a Coolify per `ADMIN_PASSWORD` / `NEXTAUTH_SECRET` (ruotati il 2026-07-28). Nessun DB di sviluppo separato: ogni prova locale scrive su dati reali.
- **Ogni fase con schema** DEVE avere la migration applicata a prod PRIMA del push del codice dipendente. `drizzle-kit generate` è rotto → SQL a mano. Procedura in `CLAUDE.md`.
- **Debito design (DEBT-01)** — ~40 file, ~450 occorrenze di palette raw/hex. Misurato il 2026-08-08. Dettaglio in `STATUS.md`.
- **Il copy fisso del template v1 non ha una fonte nel repo** — il prototipo Giojello non c'è. Lo *stile* ora viene dal design system, ma testi e gerarchia dei blocchi vanno recuperati prima di Phase 30.
- **Il caso "zero dati CrUX" non è ancora stato visto** su un sito vero (test 5 del piano).
- **Il 52% della checklist non è verificabile da HTML statico** — quanto ne recuperino gli audit Lighthouse non è ancora misurato (test 3 del piano).
- **Whitelist portale vuota per 3 clienti su 4** — si popola da `/admin/clients/<id>`.
- **`.env.local` punta al DB di PRODUZIONE**, non allineato a Coolify per `ADMIN_PASSWORD` / `NEXTAUTH_SECRET`.
- **Ogni fase con schema**: migration applicata a prod **prima** del push del codice.
- **Debito design (DEBT-01)** — ~40 file, ~450 occorrenze. Dettaglio in `STATUS.md`.
## Deferred Items
| Category | Item | Status | Deferred At |
|----------|------|--------|-------------|
| v2.4 | RET-06 — Canoni mensili tracciabili (serve tabella nuova) | Backlog | 2026-08-01 |
| v2.4 | SEND-01/02 — Invio link preventivo via email (mailer già pronto) | Backlog | 2026-07-28 |
| v2.4+ | PROP-03 — Stripe Payment Link sul deck | Backlog | v2.3 kickoff |
| v2.4+ | PROP-04 — Auto-provisioning cliente/progetto/fasi al "Vinto" | Backlog | v2.3 kickoff |
| Design | DEBT-01 — Migrazione a token semantici | Backlog | 2026-07-28 |
| Tech debt | DEBT-02 — Tabelle legacy catalogo + dead code | Backlog | v2.1 |
| v2+ | OFFER-14 — Sezioni analitiche stile Notion | Backlog | v2.1 kickoff |
| v2+ | ARCH-01 — Split modulo in deploy separato | Backlog (solo se cresce) | v2.1 kickoff |
Vedi `REQUIREMENTS.md` § Backlog e § Rinviati esplicitamente da v2.5.
## Session Continuity
Last session: 2026-08-08 20:30
Stopped at: Riordino della documentazione — milestone chiuse archiviate, v2.4 documentata, STATUS.md unico documento narrativo.
Next: Popolare la whitelist dei 3 clienti reali, oppure attaccare DEBT-01 (debito design).
Last session: 2026-08-18
Stopped at: `src/lib/audit/sources/` (5 moduli) scritto e **provato sul campo su giojello.com** — giro completo 73 s, tutte le fonti hanno risposto. Build e lint puliti.
Next: (1) `src/lib/audit/schema.ts` + `agents/` con validazione Zod dura; (2) `pipeline.ts` con heartbeat su `audit_runs`; (3) volume Coolify prima del deploy; (4) editor e pagina.
Resume file: None
+47
View File
@@ -0,0 +1,47 @@
# Requirements: ClientHub v2.4 Post-vendita
**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.
Milestone precedente: [v2.3 Email & Accesso](milestones/v2.3-ROADMAP.md), shipped 2026-07-29.
## Consegnati
### Ciclo di vita dei servizi ricorrenti (Phase 13) — ✅ in produzione 2026-08-01
- [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
### Anteprima admin e login (Phase 26) — ✅ in produzione 2026-08-08
- [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
## Backlog v2.4+ (non pianificati)
Ereditati dalle chiusure di milestone precedenti, nessuno in corso:
- [ ] **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`.
## 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.
## Fuori scope
- File hosting (vincolo LOCKED #5: i documenti restano URL esterni).
- Tabella utenti / multi-admin: l'auth resta una singola credenziale da env.
+47 -5
View File
@@ -1,6 +1,6 @@
# ClientHub (IAMCAVALLI) — Status
_Ultimo aggiornamento: 2026-08-08_
_Ultimo aggiornamento: 2026-08-18_
Questo è **l'unico documento narrativo** del progetto: a che punto siamo, cosa manca,
cosa abbiamo imparato. `.planning/STATE.md` è il digest che leggono i comandi
@@ -11,17 +11,43 @@ cosa abbiamo imparato. `.planning/STATE.md` è il digest che leggono i comandi
In produzione su `hub.iamcavalli.net` (Coolify/Hetzner, deploy automatico su push a
`main` via Gitea). Build verde, `npm audit` pulito.
Milestone **v2.4 "Post-vendita"** — Phase 13 e Phase 26 consegnate e in produzione.
Nessun lavoro in sospeso non committato.
Milestone **v2.5 "Audit"** in corso — Phase 27 a metà. In produzione c'è **solo lo
schema** dell'audit: nessuna pagina, né admin né pubblica.
| Milestone | Fasi | Stato |
|---|---|---|
| v2.4 Post-vendita | 13, 26 | 🔨 in corso — consegnato tutto ciò che era pianificato |
| v2.5 Audit | 2730 | 🔨 in corso — Phase 27 ~50% |
| v2.4 Post-vendita | 13, 26 | ✅ chiusa 2026-08-08, entrambe in produzione |
| v2.3 Email & Accesso | 2325 | ✅ shipped 2026-07-29, verificata E2E |
| v2.2 Sales Loop | 1822 | ✅ shipped 2026-06-20 |
| v2.1 Offer Studio + CRM | 11, 12, 14 | ✅ chiusa per reset 2026-06-19 |
| v1.0 + v2.0 | 110 | ✅ shipped giugno 2026 |
## In corso
### v2.5 — Audit (Phases 2730)
Il servizio di analisi sito (tre livelli: **Radiografia / Prima-Dopo / Rotta**) diventa
un documento privato su `/audit/[slug]`, generato da un motore multi-agente e rifinito a
mano prima della consegna. I tre livelli sono **configurazioni di un unico documento**:
i blocchi non pertinenti non esistono nel DOM.
Fatto finora (Phase 27, ~50%):
- **[prod 2026-08-18] Schema.** Migration `0017_audits.sql`, 7 tabelle additive, più
`checklist_items` seminata con 264 voci. Nessuna UI le legge ancora.
- **[non pushato] Le fonti del motore.** `src/lib/audit/sources/` — PageSpeed, CrUX,
Wayback, RDAP, robots/sitemap/JSON-LD, header. Provate sul campo su giojello.com:
giro completo in 73 s, tutte e cinque hanno risposto.
Manca: agent + sintetizzatore + pipeline, storage immagini, editor admin, pagina
pubblica. Dettaglio in [`.planning/ROADMAP.md`](.planning/ROADMAP.md) e
[`.planning/REQUIREMENTS.md`](.planning/REQUIREMENTS.md).
⚠️ **I due piani della milestone stanno in `~/.claude/plans/`, fuori dal repo**
(`…woolly-puddle.md` per il documento, `…radiant-valley.md` per il motore). Senza quei
file la milestone non è ricostruibile.
## Fatto
### v2.4 — Post-vendita
@@ -105,6 +131,21 @@ cui si ricasca.
`/api/v1/applications/<uuid>/envs`: mandare solo `key`, `value`, `is_preview`.
- **Playwright non funziona contro `npm run dev`**: la CSP blocca `eval` e i client
component non si idratano. Serve il build di produzione.
- **Le API di Google cambiano forma sotto i piedi, e in silenzio.** Scrivendo
`src/lib/audit/sources/` due estrazioni dedotte dalla documentazione hanno restituito
valori vuoti *senza errore*: `largest-contentful-paint-element` non esiste più (ora è
`lcp-breakdown-insight`, con `subpart`/`duration` e senza percentuali) e
`configSettings.screenEmulation` non esiste affatto nelle risposte pubbliche. Trovate
solo perché le fonti sono state fatte girare su un sito vero prima di costruirci sopra.
**Ogni estrazione da un'API di terzi va vista funzionare, non dedotta dai docs.**
- **Laboratorio e campo misurano cose diverse, e la differenza *è* il risultato.** Su
giojello.com Lighthouse dà `server-response-time` **7 ms** e CrUX dà TTFB p75 **3.553
ms con l'1% di visite nel verde**: il server risponde in fretta al datacenter Google e
lento a tutti gli altri. Due numeri con lo stesso nome verrebbero fusi in uno — da qui
`risposta_server_ms` invece di `ttfb_ms`.
- **I punteggi PageSpeed ballano fra un giro e l'altro**: performance mobile 52 e poi 64
sullo stesso sito a 30 minuti di distanza. Nei documenti consegnati un punteggio va
sempre con la sua data, mai presentato come una costante del sito.
## Note tecniche
@@ -141,7 +182,8 @@ cui si ricasca.
| src/app/admin/projects/project-actions.ts | `importOfferIntoProject`, `setProjectOfferLifecycle`, piani pagamento |
| src/components/admin/tabs/OffersTab.tsx | Tab Offerte + comandi ciclo di vita |
| src/lib/admin-queries.ts / client-view.ts | I due layer separati: admin vs proiezioni client-safe |
| src/db/migrations/ | 0011 (email/phone), 0012 (offer_type), 0015 (OTP), 0016 (ciclo di vita) |
| src/lib/audit/sources/ | Le 5 fonti del motore audit (nessun LLM) — `fetch` espone anche gli helper di rete condivisi |
| src/db/migrations/ | 0011 (email/phone), 0012 (offer_type), 0015 (OTP), 0016 (ciclo di vita), 0017 (audit) |
## Dove sta il resto