From 4403b39e63f530a9a73a24b772382bb4be152fa1 Mon Sep 17 00:00:00 2001 From: Simone Cavalli Date: Sat, 22 Aug 2026 14:51:51 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20task=20cancellati=20e=20date=20dei=20pa?= =?UTF-8?q?gamenti=20=E2=80=94=20STATUS,=20STATE,=20design=20system?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STATUS.md: perché la pill sta su "Cancellata" e non su "Fatto" (sono entrambi barrati, e scambiarli significa credere consegnato ciò che non esiste), perché `due_date` è nullable, e le due verifiche che restano a mano — il riquadro "Prossimo pagamento" non compare finché nessuna rata ha una scadenza, e due `paid_at` storici valgono il primo del mese perché li ha scritti il vecchio selettore a mese. DESIGN-SYSTEM.md: la quinta forma, la regola della colonna Kanban che si nasconde solo da vuota, e la spec del box pagamenti. STATE.md: due decisioni nuove, e resta sotto le 100 righe accorpando le righe di tabella della stessa settimana. Co-Authored-By: Claude Opus 5 --- .planning/STATE.md | 19 ++++---- STATUS.md | 74 +++++++++++++++++++++++++++++++ design-reference/DESIGN-SYSTEM.md | 32 +++++++++---- 3 files changed, 108 insertions(+), 17 deletions(-) diff --git a/.planning/STATE.md b/.planning/STATE.md index f0d7049..e2ec626 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,9 +3,9 @@ gsd_state_version: 1.0 milestone: v2.5 milestone_name: Audit status: executing -stopped_at: "v2.5 in PAUSA. Modifiche hub: A, B, C1, rifiniture, chat a canali (0021) e modifica messaggi + firma (0022) in prod; C2 (TidyCal) bloccato sulle credenziali API. Stati dei task nel portale: in prod 2026-08-22, bundle verificato, mai visto a schermo. Niente della chat e' stato provato a mano: .env.local non autentica piu'." -last_updated: "2026-08-22T12:10:00.000Z" -last_activity: 2026-08-22 -- stati dei task leggibili nel portale cliente (icone, pill, legenda) +stopped_at: "v2.5 in PAUSA. Modifiche hub: A, B, C1, rifiniture, chat a canali (0021), modifica messaggi + firma (0022), stati task e date pagamenti (0023) in prod; C2 (TidyCal) bloccato sulle credenziali API. Nulla del portale e' stato visto a schermo: .env.local non autentica piu', serve ?preview=1 in prod. Il riquadro 'Prossimo pagamento' non compare finche' nessuna rata ha una due_date." +last_updated: "2026-08-22T15:20:00.000Z" +last_activity: 2026-08-22 -- stato task "cancellata" + scadenza e data di incasso dei pagamenti nel portale progress: total_phases: 4 completed_phases: 0 @@ -37,11 +37,10 @@ Phase 27 resta a metà — schema e fonti in prod, resto da scrivere. | C1 — `POST /api/webhooks/lead` | ✅ in produzione, provato contro il DB vero | | C2 — TidyCal | ⛔ **[BLOCCANTE]** vedi sotto | | C3 — Alleggerire l'hub | ⏸️ senza perimetro | -| Rifiniture — tassonomie, "In revisione", tab pagamenti, riordino task | ✅ in prod 2026-08-20 (migration `0019`) | +| Rifiniture — tassonomie, tab pagamenti, riordino task | ✅ in prod 2026-08-20 (`0019`) | | Portale cliente — stepper compatto/full-width, card offerta | ✅ in prod 2026-08-21 (`0020`); override provato su Caruso Speaker | -| Chat a canali — portale + inbox admin per canale | ✅ in prod 2026-08-21 (`0021`); build verde, **mai provata a mano** | -| Chat — modifica messaggi + firma admin da `settings` | ✅ in prod 2026-08-21 (`0022`); menzioni rimandate, manca l'attribuzione | -| Portale — stati task leggibili (forma + pill + legenda) | ✅ in prod 2026-08-22 (`2e9bd2a`, `8b54f48`); bundle verificato, **mai visto a schermo** | +| Chat — canali, modifica messaggi, firma admin | ✅ in prod 2026-08-21 (`0021`, `0022`); **mai provata a mano**; menzioni rimandate, manca l'attribuzione | +| Portale — stati task (forma, pill, legenda, «Cancellata») + date dei pagamenti | ✅ in prod 2026-08-22 (`2e9bd2a`, `8b54f48`, `fe76789`, migration `0023`); **mai visto a schermo**, nessuna `due_date` ancora inserita | | D — Whop → audit | ⏸️ dipende dal motore v2.5 | Progress: [███░░░░░░░] 25% (v2.5) @@ -72,6 +71,8 @@ Passo per passo in `STATUS.md` e in `…radiant-valley.md`. Log completo in `PROJECT.md`. Vive per il lavoro corrente: +- **[2026-08-22] Un task cancellato esce dai denominatori, non dalla lista** — resta visibile barrato (il cliente ha letto quella voce e deve capire che fine ha fatto) ma non conta, via un solo `countsTowardProgress()` in `task-status.ts`: contarlo terrebbe la fase sotto il 100% per sempre, contarlo come fatto racconterebbe una consegna mai avvenuta. Se in una fase restano solo cancellati torna «Da iniziare»: degenere, ma «Completata» mentirebbe. +- **[2026-08-22] Le date dei pagamenti sì, gli importi per riga no** — LOCKED #2 parla di cifre, non di date. Salvate a **mezzogiorno UTC** (a mezzanotte il giorno civile a Roma è già quello dopo) e contate sui giorni civili a Roma in `src/lib/payment-dates.ts`, lo stesso modulo del futuro promemoria email: mail e portale non devono contraddirsi su quanti giorni mancano. - **[2026-08-20] Gli importi scritti a mano non si ricalcolano** — `amount_locked` esclude la riga da `rescalePayments`, e lo scarto fra somma rate e totale si dichiara invece di aggiustarlo. Il backfill dell'ordine rate va per `percent DESC`, non per `ctid`: 3 progetti su 5 erano già scombinati e l'ordine fisico avrebbe fissato l'errore. - **[2026-08-20] Rinominare una fase rinomina anche le fasi dei progetti** — non c'è FK fra tassonomia e `phases`: `importOfferIntoProject` riconosce una fase solo dal titolo (`offer_phase_id` non viene mai popolata). Senza propagazione, il re-import di un'offerta crea una fase duplicata accanto a quella vecchia. È l'unico rename che scrive fuori dal catalogo, quindi l'unico con conferma. - **[2026-08-19] Prima l'hub, poi il motore** — le modifiche all'hub sono indipendenti e a basso rischio, il motore no. Il Whop → audit resta ultimo perché dipende dal motore. @@ -94,6 +95,6 @@ Log completo in `PROJECT.md`. Vive per il lavoro corrente: ## Session Continuity Last session: 2026-08-22 -Stopped at: **stati dei task leggibili nel portale cliente.** Nella Timeline lo stato era solo un cerchietto colorato — ambra e violetto indistinguibili a 20px, e tre stati su quattro senza alcun testo. Ora le quattro icone si distinguono per **forma** (vuoto → punto → spunta vuota → spunta piena), la pill di testo sta solo sui due stati ambigui, l'header della fase conta i task in attesa anche a card chiusa, e una legenda dice chi revisiona e che **ogni pagina include un giro di revisione**. La correzione che conta: **«In revisione» significa «aspetta l'OK del cliente», non controllo qualità interno** come scrive `5547e55` — è uno stato che *richiede un'azione*, e per questo non poteva restare muto. Barra di avanzamento invariata di proposito: cambia il tipo di lavoro, non l'avanzamento. Build, typecheck e lint verdi, nessuna migration. In produzione (`2e9bd2a`, `8b54f48`) col bundle verificato dentro il container, ma **mai visto a schermo**: il portale sta dietro il gate OTP e l'anteprima vuole una sessione admin. -Next: (1) verificare in prod con `?preview=1` su **Caruso Speaker, fase «3 - Esecuzione»** — l'unica dove «In corso» e «In revisione» convivono (4 + 2 su 11), quindi l'unica dove si vede se ora si distinguono; (2) provare la chat in prod: modificare un messaggio admin e vederlo cambiare da solo entro ~20s senza duplicarsi; (3) sbloccare TidyCal con token o documentazione; (4) `LEAD_WEBHOOK_SECRET` su Coolify, senza cui `/api/webhooks/lead` risponde 403 a tutti; (5) poi v2.5 da `src/lib/audit/schema.ts` + `agents/`. +Stopped at: **stato task «Cancellata» + date dei pagamenti nel portale** (`fe76789`, migration `0023` applicata a prod prima del push). Un task tolto dal lavoro ora ha dove stare: **X nel cerchio, titolo barrato**, pill «Cancellata» — l'unico stato chiuso con la pill, perché «Fatto» e «Cancellata» sono entrambi barrati e scambiarli significa credere consegnato ciò che non esiste. Esce da **tutti** i denominatori via `countsTowardProgress()`. Nel Kanban cliente la colonna compare solo se piena (mai nascosta se ha dentro qualcosa); nell'admin c'è sempre, ed è così che si cancella un task. Lato pagamenti: `payments.due_date` (nullable, più indice parziale per il futuro promemoria email), riquadro «Prossimo pagamento» con conto alla rovescia in parole e rosso se scaduto, «Scade il…» / «Pagato il…» su ogni riga, **zero importi**. Admin: campo Scadenza per rata, «Incassato nel mese» → «Incassato il» (giorno; le analytics raggruppano per mese e non se ne accorgono). Build, typecheck e lint verdi. +Next: (1) verificare in prod con `?preview=1` **entrambe** le cose: stati task su **Caruso Speaker, fase «3 - Esecuzione»** (l'unica con «In corso» e «In revisione» insieme, 4 + 2 su 11) e box pagamenti — ma prima **inserire una scadenza** dal tab Pagamenti, altrimenti il riquadro non compare per definizione; (2) due `paid_at` storici valgono il primo del mese (2026-03-01, 2026-01-01, scritti dal vecchio selettore a mese) e il cliente ora li legge come «Pagato il 1 mar 2026»: correggerli se il giorno vero era un altro; (3) provare la chat in prod: modificare un messaggio admin e vederlo cambiare da solo entro ~20s senza duplicarsi; (4) sbloccare TidyCal con token o documentazione; (5) `LEAD_WEBHOOK_SECRET` su Coolify, senza cui `/api/webhooks/lead` risponde 403 a tutti; (6) poi v2.5 da `src/lib/audit/schema.ts` + `agents/`. Resume file: None diff --git a/STATUS.md b/STATUS.md index e2f7b92..d39f653 100644 --- a/STATUS.md +++ b/STATUS.md @@ -303,6 +303,80 @@ e «In revisione» (2) convivono, su 11 task, quindi l'unica dove si vede se ora distinguono davvero. Da guardare anche col tema scuro: è lì che l'icona «In corso» prima non aveva varianti. +### Task cancellati e date dei pagamenti (2026-08-22) + +Due buchi che si vedevano solo aprendo il portale dalla parte del cliente. + +**Un task tolto dal lavoro non aveva dove stare.** L'admin poteva solo cancellarlo dal DB +— e allora il cliente non capiva perché una voce che aveva letto la settimana prima non +c'era più — oppure lasciarlo lì a fingersi «Da fare» per sempre. Ora `cancelled` è il +quinto stato: **X dentro il cerchio, titolo barrato**, e la pill «Cancellata». + +È l'unico stato *chiuso* che porta la pill, e non è un'incoerenza: «Fatto» e «Cancellata» +sono **entrambi barrati**, e scambiarli significa credere consegnato qualcosa che non +esiste. La forma da sola non basta a coprire quel rischio. + +Il lavoro vero, di nuovo, non era il nuovo stato ma i denominatori. Un task cancellato esce +da **tutti**: percentuale di fase, percentuale globale, board delle consegne, riepilogo +admin — attraverso un solo `countsTowardProgress()` in `src/lib/task-status.ts`, non cinque +`!== "cancelled"` sparsi in giro. Contarlo terrebbe la fase sotto il 100% per un lavoro che +nessuno farà mai; contarlo come fatto racconterebbe una consegna mai avvenuta. +`recomputePhaseStatus` lo ignora allo stesso modo: senza, cancellare l'ultima voce di una +fase la lasciava «In corso» per sempre. Se restano **solo** cancellati la fase torna «Da +iniziare» — è degenere, ma «Completata» al cliente racconterebbe una consegna che non c'è +stata. + +Nel Kanban cliente la colonna «Cancellate» compare **solo se ha dentro qualcosa**, così le +quattro che raccontano il lavoro si tengono la larghezza — ma mai se è piena, quindi nessun +task sparisce dalla board: era esattamente il bug che aveva fatto nascere `TASK_STATUSES`. +Nell'admin la colonna c'è sempre, ed è così che si cancella un task: trascinandocelo. + +**Il box pagamenti non sapeva dire quando si paga.** `payments` aveva `paid_at` — quando una +rata è stata incassata — e nient'altro: nessun campo per la scadenza. Il portale non poteva +rispondere alla domanda più ovvia del cliente, e non c'era niente su cui agganciare il +promemoria via email. **Migration `0023`**, additiva: `payments.due_date`, nullable senza +default, più un indice parziale su cui girerà la query del promemoria («le non saldate in +scadenza entro N giorni», che l'indice `(project_id, sort_order)` non copre). + +Nullable è una scelta: una rata senza data concordata è normale, e un default inventerebbe +una scadenza che nessuno ha pattuito. **Il portale mostra la data solo se c'è.** + +Cosa vede il cliente: + +- In cima al box, **«Prossimo pagamento»**: data lunga e conto alla rovescia in parole — + «tra 12 giorni», «domani», «oggi». Se è passata, il riquadro diventa rosso e dice + «Pagamento scaduto — scaduto da 3 giorni». Un arretrato batte sempre la rata del mese + prossimo: se c'è, *quello* è il prossimo pagamento. +- Su ogni riga, la sua data: **«Scade il…»** se aperta, **«Pagato il…»** se saldata. +- **Nessun importo per riga.** LOCKED #2 resta dov'era: le date non sono cifre. + +I giorni si contano in `src/lib/payment-dates.ts`, sui **giorni civili a Roma** e non sugli +istanti: il container gira a UTC, e «manca una settimana» non deve cambiare risposta a +seconda del fuso di chi renderizza. È lo stesso modulo che userà il promemoria email — +scritto ora proprio perché la mail e il portale non si contraddicano su quanti giorni +mancano. Le date si salvano a **mezzogiorno UTC**, non a mezzanotte: a mezzanotte UTC il +giorno civile a Roma è già quello dopo, e la data tornerebbe indietro di un giorno appena +riletta. + +Lato admin ogni rata ha ora il campo **Scadenza**, e «Incassato nel mese» è diventato +**«Incassato il»** — precisione al giorno, che le analytics non notano perché raggruppano +con `extract(month from paid_at)`. Il warning sul cambio schema rate conta anche le +scadenze: una rata «da saldare» con una data è già sotto gli occhi del cliente, e +sparirebbe in silenzio. + +**In produzione dal 2026-08-22** (`fe76789`). Migration `0023` applicata a prod **prima** +del push, come da procedura: `ALTER TABLE` + `CREATE INDEX`, 12 righe in tabella, nessuna +toccata. Build, typecheck e lint verdi — lint invariato, nessun problema nuovo nei file +toccati. + +⚠️ **Due cose da fare a mano.** (1) Il portale non l'ho visto a schermo: vale la stessa +verifica `?preview=1` della sezione precedente, e finché nessuna rata ha una `due_date` il +riquadro «Prossimo pagamento» **non compare per definizione** — va messa una scadenza dal +tab Pagamenti per vederlo. (2) Due `paid_at` storici valgono il **primo del mese** +(2026-03-01 e 2026-01-01): li ha scritti così il vecchio selettore a mese, e ora il cliente +li legge come «Pagato il 1 mar 2026». Se il giorno vero era un altro, si corregge dal nuovo +campo. + ### v2.5 — Audit (Phases 27–30), in pausa Il servizio di analisi sito (tre livelli: **Radiografia / Prima-Dopo / Rotta**) diventa diff --git a/design-reference/DESIGN-SYSTEM.md b/design-reference/DESIGN-SYSTEM.md index 49efc32..3764807 100644 --- a/design-reference/DESIGN-SYSTEM.md +++ b/design-reference/DESIGN-SYSTEM.md @@ -389,16 +389,32 @@ The `/client/[token]` portal was migrated to the same "Quiet Luxury" tokens `bg-muted`/`text-muted-foreground` (upcoming) — each with a `dark:` variant. - **Phase cards** (`PhaseCard`): `rounded-xl border-border-light bg-card shadow-card`, progress bar colored per status (emerald/amber/`bg-border`). -- **Stato dei task** (`TaskStatusIndicator`): le quattro forme si distinguono +- **Stato dei task** (`TaskStatusIndicator`): le cinque forme si distinguono **senza colore** — `todo` cerchio vuoto `border-border`, `in_progress` cerchio + punto ambra, `in_review` cerchio + **spunta vuota** violetta, `done` cerchio pieno - + spunta emerald. La spunta compare a lavoro finito e si riempie a lavoro confermato. - La pill di testo compare **solo** su `in_progress` e `in_review`; `todo` e `done` si - leggono dalla forma e dal titolo barrato. Colori come le altre pill del portale (soft - tint `-50/700` + variante `dark:`), tutti raccolti in `TASK_STATUS_VISUALS` e mai - riscritti nei componenti: le stesse tinte colorano le colonne del Kanban cliente e la - legenda, che si genera da `TASK_STATUSES`. L'icona è `aria-hidden` e lo stato viaggia - in uno `sr-only`, così lo screen reader lo annuncia anche sui due senza pill. + + spunta emerald, `cancelled` cerchio spento + **X**. La spunta compare a lavoro + finito e si riempie a lavoro confermato; la X è l'unica forma che non è un passo + avanti. La pill di testo compare su `in_progress`, `in_review` e `cancelled`; + `todo` e `done` si leggono dalla forma e dal titolo. **`done` e `cancelled` sono + entrambi barrati**, ed è proprio per questo che `cancelled` porta la pill: la + differenza fra consegnato e tolto dal lavoro è troppo importante per affidarla al + solo disegno dentro il cerchio. Colori come le altre pill del portale (soft tint + `-50/700` + variante `dark:`, tinta `muted` per la cancellata), tutti raccolti in + `TASK_STATUS_VISUALS` e mai riscritti nei componenti: le stesse tinte colorano le + colonne del Kanban cliente e la legenda, che si genera da `TASK_STATUSES`. L'icona + è `aria-hidden` e lo stato viaggia in uno `sr-only`, così lo screen reader lo + annuncia anche su quelli senza pill. + La colonna «Cancellate» del Kanban cliente è l'unica che **si nasconde da vuota** + (le altre quattro si tengono la larghezza) — mai se è piena: nessun task deve + sparire dalla board. +- **Box pagamenti** (`PaymentStatus`): sopra le righe, un riquadro «Prossimo + pagamento» con data lunga e conto alla rovescia in parole («tra 12 giorni», + «domani», «oggi»); se la scadenza è passata diventa rosso e dice «Pagamento + scaduto — scaduto da N giorni». Ogni riga porta la sua data sotto l'etichetta: + «Scade il…» se aperta, «Pagato il…» se saldata, **nulla** se in gestionale la data + non c'è — il portale non inventa scadenze. Nessun importo per riga (LOCKED #2): + le date non sono cifre. I giorni si contano in `src/lib/payment-dates.ts` sui + giorni civili a Roma, non sugli istanti. - Sidebar cards (`OffersSection`, `PaymentStatus`, `DocumentsSection`, `NotesSection`, `TranscriptsSection`) all follow `rounded-xl border-border-light bg-card shadow-card`.