Commit Graph

14 Commits

Author SHA1 Message Date
simone 2e9bd2ab60 feat(portale): gli stati dei task si distinguono, e "in revisione" dice di chi e' la palla
Nella Timeline — la vista di default — lo stato di un task era solo un cerchietto
colorato: ambra col puntino da 1.5px per "in corso", violetto col puntino da 2px per
"in revisione". A 20px sono lo stesso oggetto. Solo "in revisione" aveva un title; gli
altri tre stati non avevano ne' testo, ne' tooltip, ne' aria-label — l'opposto della
regola UX 3 del design system, che chiede colore + testo, mai colore da solo.

Il punto pero' non era la somiglianza fra i due colori. "In revisione" non significa
quello che dice 5547e55, che lo descriveva come controllo qualita' interno: nel flusso
reale vuol dire "consegnato, aspetta l'OK del cliente". E' uno stato che richiede
un'azione, e per questo un cerchietto muto era il problema vero.

- Le quattro icone si distinguono per forma, non solo per colore, quindi reggono anche
  in bianco e nero e con un daltonismo: vuoto -> punto -> spunta vuota -> spunta piena.
  La spunta compare a lavoro finito e si riempie a lavoro confermato.
- Pill di testo solo su "in corso" e "in revisione". "Da fare" e' un cerchio vuoto e
  "fatto" ha il titolo barrato: etichettarli aggiungeva rumore, non informazione.
- Il conteggio dei task in attesa sta nell'header della fase, quindi si legge anche a
  card chiusa. Serve davvero: l'admin puo' forzare una fase su "completata" dalla
  select, e in quel caso la card parte collassata con dentro la richiesta.
- Legenda + micro-copy sopra entrambe le viste: chi revisiona, e che ogni pagina include
  un giro di revisione — l'informazione commerciale che il cliente non aveva da nessuna
  parte. Rimanda alla chat della fase, che esiste gia'.
- Colonne del kanban cliente colorate con le stesse tinte dell'icona in Timeline: prima
  erano quattro colonne grigie identiche.
- Icona aria-hidden + sr-only, cosi' lo screen reader annuncia lo stato anche sui due
  che non portano la pill.

La barra di avanzamento non e' stata toccata: un task in revisione conta come uno in
corso, cioe' zero. Cambia il tipo di lavoro, non l'avanzamento — gonfiare la percentuale
le avrebbe fatto dire una cosa che il contatore "x di y task" smentiva una riga sotto.

Visual e copy in un solo file, e la legenda si genera da TASK_STATUSES: un quinto stato
non lascera' indietro una lista scritta a mano. Stessa disciplina di 5547e55, nata
proprio perche' due liste fisse avevano fatto sparire dei task senza un errore.

Nessuna migration: e' solo UI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 14:24:35 +02:00
simone c3d2afa61f docs: modifica messaggi e firma in chat — STATUS, STATE, design system
La cosa da rileggere fra sei mesi: propagare una modifica richiede
insieme il filtro allargato a edited_at e il watermark del client sul
massimo dei due timestamp. Una sola delle due e o la modifica non
arriva, o arriva a ogni giro per sempre.

Più il perché di due scelte che sembrano sviste: il non-letto resta su
created_at, e la foto è un URL esterno perché l'upload su volume non
esiste (la deroga LOCKED #5 è scritta ma mai costruita).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 22:44:30 +02:00
simone 0d7186ba03 docs: chat a canali — design system, STATUS, STATE
Il pattern che vale la pena rileggere: la chiave del canale è derivata,
non è una colonna, e sta in un modulo condiviso perché le due sponde
devono concordare al carattere. Più il perché del letto/non-letto
asimmetrico (tabella per il cliente, timestamp per l'admin).

Chiude anche il caveat in STATUS.md sulla risposta admin che finiva
sempre sul thread generale.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 17:53:33 +02:00
simone 53f1758f52 docs: l'\override è già stato usato in produzione
Guardando il DB: Caruso Speaker / B ha offer_value_override = 7500 a
fronte di un calcolo di 20.250. La 0020 non fa backfill, quindi quel
numero è stato messo a mano dal tab Offerte — updateOfferValueOverride è
provata sul campo, non più solo buildata.

Resta scoperta Rossi Inc / B: venduta a 7.000, il portale mostra 20.250.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:30:23 +02:00
simone d14f95c80d docs: verifica del giro 0020, e .env.local non è più utilizzabile
Cosa è stato verificato davvero: build e lint verdi, migration 0020
applicata a prod prima del push con la colonna riletta a conferma,
deploy atterrato (immagine taggata 44be190 = HEAD).

Cosa no, e ora è scritto: le pagine non sono state rese a runtime.
.env.local è scaduto su tre fronti — ADMIN_PASSWORD, NEXTAUTH_SECRET e
la password del DB — e l'host che dichiara (…:5432) è chiuso dal
firewall; il DB vero sta su 127.0.0.1:54321. Estrarre la password viva
dal container è bloccato dal classifier e non è stato aggirato. La nota
tecnica che dava per buone quelle credenziali diceva il falso.

Aggiunto come vedere se un deploy è atterrato: il tag dell'immagine in
docker ps è lo SHA del commit.

REQUIREMENTS: HUB-14 e HUB-15 registrati come fatti, HUB-16 apre la
verifica a mano che resta da fare, e il riallineamento di .env.local
entra fra le cose aperte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 13:05:39 +02:00
simone 44be190631 feat(portale): barra full-width, card offerta senza accordion, valore override
Barra di avanzamento a tutta larghezza (via il max-w-[1200px]).

Card offerta: rimosso l'accordion "Cosa è compreso". La lista servizi non
arriva più al client — client-view.ts legge dai servizi i soli prezzi — e
OffersSection perde il suo unico useState, quindi anche il "use client".

"Valore incluso" diventa "Valore dell'offerta" e accetta un override manuale
(migration 0020, project_offers.offer_value_override). Prima era sempre la
somma dei prezzi di catalogo del tier: in produzione mostrava €20.250 su
offerte vendute a 7.000 e 5.500. NULL torna al calcolo, 0 nasconde la riga.
Si gestisce dal tab Offerte del progetto, che affianca la cifra calcolata
per far vedere cosa si sta sostituendo.

La somma calcolata vive ora in src/lib/offer-value.ts, letta sia dal portale
sia dall'admin: duplicarla avrebbe fatto divergere le due viste.

"Prezzo finale" diventa "Investimento finale" (il ricorrente resta "Canone
mensile").

Migration 0020 applicata a prod prima del push. Override tutti NULL, quindi
il comportamento resta invariato finché non se ne imposta uno.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 07:54:55 +02:00
simone 4e3907d382 docs: tab pagamenti e riordino task in produzione
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 22:42:23 +02:00
simone df4671236a docs: distingue deployato da provato a mano
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:14:43 +02:00
simone 9a57e450fc docs: registra rinomina tassonomie e stato task "In revisione"
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 16:11:47 +02:00
simone 97cc6460a0 docs: registra le modifiche hub e mette v2.5 in pausa dichiarata
STATE.md diceva "Phase 27, nessun bloccante" mentre v2.5 e' ferma per scelta e
in produzione e' andato altro. Ora dice cosa e' vero: v2.5 in pausa, modifiche
hub in corso, blocchi A/B/C1 in produzione, e due bloccanti scritti con cosa
manca e chi li sblocca — le credenziali API di TidyCal e LEAD_WEBHOOK_SECRET
su Coolify, senza la quale la route rifiuta tutti (fallimento chiuso voluto).

Sta di nuovo sotto le 100 righe: ci e' rientrato togliendo cio' che STATUS.md
gia' racconta per esteso, non accorciando i bloccanti.

REQUIREMENTS.md guadagna HUB-01..13, con lo stato reale: otto fatti, cinque no.
Fra quelli aperti c'e' anche la conferma del payload Elementor, che oggi e'
gestito in modo difensivo e non verificato sul campo — distinguere "scritto" da
"visto funzionare" e' il punto della regola.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 10:13:50 +02:00
simone 8000d562dc 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>
2026-08-18 17:48:46 +02:00
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
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
simone 988f6f425a docs: add STATUS.md session handoff 2026-06-22 14:34:17 +02:00