Due mancanze emerse provando la chat a canali in produzione.
**Modifica dei messaggi** (migration 0022, additiva, già applicata a
prod). Modello Slack/Discord: si corregge un proprio messaggio senza
limite di tempo, il testo precedente non si conserva, accanto all'ora
compare «modificato». Scelta deliberata, annotata in STATUS.md.
Il punto delicato non è la scrittura ma la propagazione: il poll chiede
`created_at > since` e una modifica non cambia `created_at`, quindi
l'altra parte vedrebbe il testo vecchio fino a un reload. Il filtro ora
guarda anche `edited_at`, e il watermark del client è il massimo fra i
due su tutti i messaggi — senza, il server rispedirebbe lo stesso
messaggio a ogni giro per sempre. Il merge per id già esistente fa il
resto, quindi niente duplicati.
Il non-letto resta ancorato a `created_at` di proposito: correggere un
refuso non deve riaccendere il pallino di un canale già letto.
Si modifica solo ciò di cui si è autori — il controllo è su `author`,
non solo sulla proprietà dell'entità, e lo rifà il server.
**Firma in chat.** Il nome era la stringa "iamcavalli" cablata nel
pannello: il cliente leggeva il marchio dove si aspetta una persona. Ora
arriva da `settings` (nessuna migration) con foto via URL esterno, che
rispetta il vincolo LOCKED #5 — l'upload su volume non esiste, la
deroga per l'audit è scritta in CLAUDE.md ma non è mai stata costruita.
Avatar rotto o assente ricade sul monogramma.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Il portale aveva una sola conversazione con un selettore di fase in un
dropdown: il cliente non vedeva dove c'era del non letto, e una risposta
admin poteva atterrare su un'entità diversa da quella della domanda.
Ora i messaggi si organizzano in canali — "Generale" più uno per fase —
derivati in un solo posto (src/lib/chat-channels.ts) così che le due
sponde concordino sulla stessa chiave. Task e deliverable non sono più
scrivibili ma lo storico non resta orfano: rientra nel canale della fase
proprietaria conservando il nome dell'entità come badge.
- migration 0021 (additiva, già applicata in prod): client_channel_reads
per il letto/non-letto per canale lato cliente, più il primo indice mai
esistito su comments (entity_id, created_at)
- GET/POST /api/client/chat: polling dei messaggi e ricevuta di lettura
- ChatPanel: tab per canale, pallino di non letto, modalità full-screen
- inbox admin: tab per canale con targeting dell'entità corretta in
risposta e snapshot di adminLastReadAt sul thread
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>