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>
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>
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>
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>
Segue il mock design-reference/Client-Portal-Progress-Bar: "Step N" e lo
stato passano sulla stessa riga, il titolo fase resta sotto — due righe di
testo invece di tre — e il padding del contenitore scende da py-8 a py-3.
Altezza della sezione da ~147px a ~90px.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
I mock per pagina erano file HTML senza estensione, mentre CLAUDE.md li
descriveva come cartelle design-reference/pagina-*/ - un path che non
esisteva. Rinominati in pagina-*.html e aggiornati i riferimenti anche in
DESIGN-SYSTEM.md.
CLAUDE.md:
- puntatori corretti dopo il riordino di .planning/ (security/, STATE.md a
digest, REQUIREMENTS.md come backlog corrente)
- rimosso il paragrafo sui doc superseded: i file non esistono piu
- annotato che i mock sono scritti in slate-* raw perche precedono la
regola dei token: vanno tradotti, non copiati
- rese esplicite le eccezioni sanzionate alla regola dei token (colori di
stato di StatusBadge, verde brand della sidebar, HTML delle email)
- vincolo LOCKED #4: annotata l'unica deroga, getClientGate() legge
getServerSession per l'anteprima admin in sola lettura e solo con
?preview=1 (Phase 26). Testo approvato dall'utente
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rimossi i doppioni e gli artefatti accumulati, senza cancellare nulla di
definitivo: tutto cio' che serviva una revisione e' parcheggiato in cestino/
(gitignored), documentato in cestino/LEGGIMI.md.
- .planning/phases/01-10: 10 cartelle identiche byte-per-byte alle copie in
.planning/milestones/v1.0-phases e v2.0-phases. HANDOFF.md:33 documentava che
furono copiate e non spostate, lasciando la pulizia 'facoltativa in futuro'.
Verificata l'identita' con diff -rq prima di spostare ciascuna.
- scripts/: 13 script one-off gia' eseguiti (push-*, migrate-*, validate-*,
verify-12-03-*) piu' reset-and-import-services.ts, che cancella dati.
Restano i 3 riutilizzabili: seed, import-services-notion, import-service-offer-tags.
- CLAUDE-SECURITY-20260727-210226/: cartella di lavoro della run interrotta.
Cancellati subito, senza revisione: 6 .DS_Store, le due cache .impeccable/
(una era dentro src/) e tsconfig.tsbuildinfo.
.gitignore: aggiunti cestino/, .impeccable/ e CLAUDE-SECURITY-*/ per evitare
che si riformino.
src/ non e' stato toccato: la struttura e' dettata dall'App Router di Next.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- ServiceTable: contenitore bg-card/shadow-card, header uppercase muted, righe hover:bg-muted/40, footer "Visualizzazione di N servizi"
- CatalogSearch: usa il primitivo SearchInput
- page: sottotitolo sezione
- tokenizza OptionSelect ed EditableCell (accent-primary) — erano rimasti con hex hardcoded
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nuovo MessagesWidget nella colonna 1/3 della dashboard: riusa
getConversations() filtrando le conversazioni unread, mostra le prime 4
con anteprima e deep-link "Rispondi" a /admin/conversazioni?c=<clientId>.
Pill emerald "N Nuovi" + pallino pulsante, empty state quando non c'è nulla
in attesa. Stessa fonte di verità (clients.admin_last_read_at) del badge
sidebar. Aggiornato DESIGN-SYSTEM.md (inventory + note Conversazioni/dashboard)
e il mock design-reference/pagina-dashboard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Nuova pagina admin /admin/conversazioni: vista WhatsApp-style (lista
conversazioni a sinistra, thread + risposta a destra) che aggrega i
messaggi di tutti i clienti dalla tabella comments, cross-cliente.
- Migration additiva 0014: clients.admin_last_read_at per tracciare
letto/non-letto (pallini + badge in sidebar). Applicata a prod.
- conversations-queries.ts: aggregazione entity_id → cliente
(general/phase/task/deliverable), getConversations /
getConversationThread / getUnreadConversationsCount.
- Risposte admin salvate come commento "general" (visibili anche nella
chat cliente e nel CommentsTab della scheda).
- Voce di menu + badge non-letti (AdminSidebar/AdminShell/layout).
- Token semantici per dual light/dark; refresh manuale (no polling).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rewrite /admin/pipeline/[id] LeadDetail with token-based dual-theme layout:
bespoke header with inline StatusBadge, asymmetric 1/3 profile + 2/3 content
columns, and a unified reverse-chronological timeline merging activities and
transcripts (transcript node highlighted + expandable + deletable).
Restyle modal triggers (Registra Attività, Aggiungi Transcript, Modifica-as-icon)
to the mock outline style. Remove the confusing "Invia Preventivo" button (it only
linked a token + advanced stage, no email). Keep Converti in cliente for won leads.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Design system foundations: Plus Jakarta Sans font, shadow-card/radius
tokens in @theme, design-reference/DESIGN-SYSTEM.md with component inventory
- Collapsible admin shell (AdminShell): smooth w-64<->w-20 sidebar, new top
header with "Admin" + avatar placeholder, localStorage-persisted state
- Rename route /admin/leads -> /admin/pipeline (redirect stubs preserved),
nav label Lead -> Pipeline; DB table unchanged
- Reusable primitives: StatusBadge, SearchInput, SegmentedToggle (dual-theme)
- Luxury restyle of lead table, kanban (6 stages + @dnd-kit intact), PageHeader
- Tokenize editable-cell / option-multi-select for dark-mode legibility
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>