Files
clienthub/STATUS.md
T
simone 0aad9caf46 docs: STATUS.md unico documento narrativo, STATE.md a digest
STATUS.md e .planning/STATE.md raccontavano la stessa storia in due posti
con date diverse, e STATE.md si contraddiceva: frontmatter fermo a
"milestone v2.3 / executing" quando v2.3 e shipped, l'anteprima admin data
per "NON committata" mentre e il commit 187550f deployato l'8 agosto,
Session Continuity ferma al 29/07 e la tabella Performance Metrics spezzata
a meta.

Il template GSD dice esplicitamente che STATE.md deve stare sotto le 100
righe ("a DIGEST, not an archive"): ne aveva 177, quasi tutte narrativa.

- STATUS.md assorbe la narrativa e diventa l'unico posto dove si racconta
  il progetto. Nuova sezione "Lezioni operative" per le trappole in cui si
  ricasca: il gate OTP non va nel layout App Router (il payload RSC
  trapela), ricreare il dominio Resend rigenera la chiave DKIM, .env.local
  non e allineato a produzione dal 28/07, Playwright non funziona contro
  npm run dev
- STATE.md sceso a 98 righe, con i campi che state.cjs legge davvero.
  Frontmatter corretto a v2.4, blocchi gia risolti (DKIM, env Coolify)
  rimossi, nulla risulta piu "non committato"
- il debito design era sottostimato: non 11 pagine ma ~40 file e ~450
  occorrenze. Esclusi perche legittimi AdminSidebar (eccezione brand),
  mailer.ts (HTML email) e i colori di stato di StatusBadge

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:38:49 +02:00

158 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ClientHub (IAMCAVALLI) — Status
_Ultimo aggiornamento: 2026-08-08_
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
`/gsd-*` — non raddoppia questo file, ci rimanda.
## Stato attuale
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 | Fasi | Stato |
|---|---|---|
| v2.4 Post-vendita | 13, 26 | 🔨 in corso — consegnato tutto ciò che era pianificato |
| 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 |
## Fatto
### v2.4 — Post-vendita
- **[Phase 13, prod 2026-08-01] Ciclo di vita dei servizi ricorrenti.**
`project_offers.status` (attivo/sospeso/cessato) + `end_date` (migr. 0016). Prima
un retainer non poteva finire e il forecast lo sommava a ogni mese in eterno.
Comandi Sospendi/Riattiva/Cessa nella tab Offerte; il cliente vede stato, "attivo
dal" e canone mensile. Dettaglio: [`.planning/phases/13-…/13-SUMMARY.md`](.planning/phases/13-ciclo-vita-servizi-ricorrenti/13-SUMMARY.md)
- **[Phase 26, prod 2026-08-08] Anteprima admin del portale + toggle password.**
`?preview=1` più una sessione Auth.js valida apre il portale di un cliente in
**sola lettura**, senza passare dal gate OTP. Deviazione consapevole dal vincolo
LOCKED #4, annotata in `CLAUDE.md`. Dettaglio: [`.planning/phases/26-…/26-SUMMARY.md`](.planning/phases/26-anteprima-admin-e-login/26-SUMMARY.md)
### v2.3 — Email & Accesso
- **Gate OTP sul portale cliente**: whitelist email per cliente (`client_emails`),
codice a 6 cifre via Resend, sessione firmata 90 giorni, revoca in blocco
dall'admin (`clients.sessions_valid_from`). Migr. 0015. Verificato E2E in
produzione. Archivio: [`v2.3-ROADMAP.md`](.planning/milestones/v2.3-ROADMAP.md)
### Prima di v2.3
- **[2026-07] Audit di sicurezza chiuso**: 4 vulnerabilità risolte e deployate, slug
clienti ruotati a 12 char CSPRNG, `INTERNAL_SECRET` e `ADMIN_PASSWORD` configurati
su Coolify. Report in [`.planning/security/`](.planning/security/).
- **Design system "Quiet Luxury"**: dashboard, liste (Clienti/Offerte/Catalogo/
Preventivi/Progetti), Conversazioni, Impostazioni, Pipeline+Kanban, dettaglio Lead
e portale cliente base sono a token semantici e dual-theme.
- **Tassonomie centralizzate** in Impostazioni (modello Notion, pool persistenti
`src/lib/taxonomy.ts`).
- **Lead → Cliente**: `clients.email/phone` + `leads.archived` (migr. 0011).
`convertLeadToClient` riusa `createClientCore`, porta i transcript, archivia il
lead mantenendo "won".
- **Offerta → Fasi/Task**: `importOfferIntoProject` crea fasi raggruppando i servizi
del tier per `services.fase`.
- **Offerte (modello + UI)**: `offer_macros.offer_type` ('una_tantum'|'retainer') +
toggle "Modalità" nell'editor (migr. 0012). Tab Offerte a 2 step.
## Da fare
- [ ] **Whitelist portale**: dei 4 clienti solo uno ha email autorizzate. Chi ha la
whitelist vuota **non entra nel proprio portale** — si popola da
`/admin/clients/<id>` → "Accessi al portale", poi va reinviato il link.
- [ ] **Fasi/Task dall'offerta** funzionano solo se i servizi hanno il campo **Fase**
valorizzato nel Catalogo (altrimenti finiscono in "Generale").
- [ ] **Debito design (DEBT-01)**: **~40 file, ~450 occorrenze** di palette Tailwind
raw e hex literal invece 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` (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), i colori di stato di `StatusBadge` (sanzionati dal design system,
hanno già le varianti `dark:`).
- [ ] Micro legacy "Mantenimento" senza tier: valutare se rimuoverlo/normalizzarlo.
- [ ] **Backlog**: canoni mensili tracciabili (RET-06 — serve una tabella nuova),
PROP-03 (Stripe sul deck), PROP-04 (auto-provisioning al "Vinto"), SEND-01/02
(invio preventivo via email — il mailer è già pronto). Elenco completo in
[`.planning/REQUIREMENTS.md`](.planning/REQUIREMENTS.md).
## Lezioni operative
Cose imparate a caro prezzo. Non sono documentazione di feature: sono trappole in
cui si ricasca.
- **Il gate OTP non va nel layout.** Prima implementazione: gate in
`client/[token]/layout.tsx` che rendeva `<OtpGate/>` al posto di `{children}`.
**Non protegge nulla.** Nell'App Router il segmento `page` è renderizzato in
parallelo al layout: la dashboard spariva a schermo ma fasi, task e pagamenti
restavano leggibili nel payload RSC dell'HTML (46.907 byte → 17.594 dopo il fix).
Il gate sta in cima alla `page`, prima di ogni query, via `getClientGate()`.
**Ogni nuova route sotto `/client/[token]/` deve fare lo stesso.**
- **Ricreare il dominio su Resend rigenera la chiave DKIM.** Se il dominio torna
`failed`, non fidarsi di valori DKIM annotati in passato: rileggerli da
`GET /domains` e confrontarli con
`dig +short TXT resend._domainkey.iamcavalli.net @8.8.8.8`.
- **`.env.local` non è allineato a produzione.** `ADMIN_PASSWORD` e
`NEXTAUTH_SECRET` sono stati ruotati il 2026-07-28 **solo su Coolify**. Per
costruire firme o hash validi in prod vanno letti da Coolify, non da `.env.local`.
- **L'API Coolify rifiuta `is_build_time`** con 422 sul POST a
`/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.
## Note tecniche
- **Il DB di `.env.local` È la produzione** (178.104.27.55). Non esiste un database
di sviluppo separato: qualunque cosa si esegua in locale scrive su dati reali.
Verificare i conteggi delle tabelle protette prima e dopo ogni prova.
- **Migrazioni**: SQL scritto a mano in `src/db/migrations/` (`drizzle-kit generate`
è rotto — vanno tenuti in sync `schema.ts` e l'SQL). Si applicano **da locale via
SSH + docker exec**, senza tunnel — procedura completa in `CLAUDE.md`. Il tunnel
`ssh -f -N -L 54321:localhost:54321` serve solo per puntare il tooling locale
(es. `npx tsx`) al DB di prod.
- **Ordine di deploy con schema**: applicare la migrazione a prod **prima** del push
(il deploy fa girare subito il codice nuovo).
- **Coolify API**: credenziali in `~/.coolify.env` (formato `export VAR=…`, va
sorgentato). App uuid `xsksow44g4kcoo8wocsgkscc`.
- **`overrides` in package.json** forzano `postcss >= 8.5.18` e `sharp >= 0.35.0`:
le versioni che Next si porta dietro hanno CVE high e non c'è fix upstream. Se un
aggiornamento di Next rompe qualcosa, è il primo posto dove guardare.
- `offer_micros` non ha `created_at` (no "tier più vecchio" affidabile).
- **Debito tecnico non bloccante**: tabelle legacy `service_catalog` /
`offer_services` / `offer_micro_services` come deadweight; `createService` /
`serviceSchema` dead code in `src/app/admin/catalog/actions.ts`.
## File chiave
| File | Scopo |
|---|---|
| src/proxy.ts | Middleware (Next 16 lo chiama `proxy`, non `middleware`) |
| src/lib/client-gate.ts | Gate OTP — va chiamato in cima a ogni page sotto `/client/[token]/` |
| src/lib/otp.ts, client-session.ts | Codici OTP e cookie di sessione 90gg |
| src/lib/mailer.ts | Unico punto di invio email (Resend) |
| src/lib/forecast-queries.ts | Forecast 12 mesi — rispetta stato e `end_date` dei retainer |
| src/lib/taxonomy.ts | Pool tassonomie (Impostazioni) |
| 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) |
## Dove sta il resto
| Cosa | Dove |
|---|---|
| Regole per Claude, procedure deploy/DB, vincoli LOCKED | `CLAUDE.md` |
| Digest di stato per i comandi `/gsd-*` | `.planning/STATE.md` |
| Requisiti e backlog della milestone corrente | `.planning/REQUIREMENTS.md` |
| Roadmap e storico milestone | `.planning/ROADMAP.md`, `.planning/MILESTONES.md` |
| Archivi delle milestone chiuse | `.planning/milestones/` |
| Fasi della milestone in corso | `.planning/phases/` |
| Report dell'audit di sicurezza (chiuso) | `.planning/security/` |
| Design system e mock per pagina | `design-reference/` |