Files
clienthub/.planning/milestones/v2.3-ROADMAP.md
T
simone f7eb7eec23 docs(planning): archivia v2.1/v2.2/v2.3 e documenta v2.4
.planning/ documentava in dettaglio cio che era vecchio e per niente cio
che e in produzione: le fasi 11-22 (v2.1 e v2.2, chiuse a giugno) erano
ancora in phases/ mentre v1.0 e v2.0 stavano gia in milestones/, e il
lavoro degli ultimi due mesi - gate OTP e ciclo di vita dei retainer, cioe
quello che gira su hub.iamcavalli.net - non aveva nessuna cartella.

- phases/{11,12,14} -> milestones/v2.1-phases/, phases/{18..22} ->
  milestones/v2.2-phases/. Ora phases/ contiene solo la milestone in
  corso, che e quello che state.cjs conta per il progresso
- v2.1-ROADMAP.md ricostruito: era l'unica milestone senza archivio,
  interrotta dal reset del 19/06 e mai chiusa formalmente
- v2.3-ROADMAP.md + v2.3-REQUIREMENTS.md: v2.3 e stata eseguita fuori dal
  ciclo GSD, non esistono PLAN/SUMMARY per fase. L'archivio E la doc
- REQUIREMENTS.md riscritto per v2.4 con il backlog reale
- phases/13 e phases/26: SUMMARY ricostruiti da commit, migration e
  STATUS.md. 26 e il primo numero libero
- research/: cancellate 4 varianti dello stesso PITFALLS e FEATURES/
  SUMMARY, superati da PROJECT.md. Diverse anti-feature erano ormai
  contraddette dai fatti (il Kanban e stato costruito in Phase 19,
  l'email in v2.3, il time tracking esiste)
- cancellati UI-RULES.md e DESIGN-SYSTEM.md (CLAUDE.md li dichiara
  superseded: impongono l'inverso della regola attuale) e HANDOFF.md,
  fermo al 13/06
- SECURITY-*.md -> security/: audit chiuso, ma i report restano la doc di
  cosa e stato ruotato e perche
- PROJECT.md/MILESTONES.md/ROADMAP.md allineati: milestone corrente v2.4,
  sessione OTP 90gg non 30, migrazioni fino alla 0016

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

4.1 KiB
Raw Blame History

Archivio milestone v2.3 — Email & Accesso

Fasi: 2325 · Aperta: 2026-06-21 · Shipped: 2026-07-29 (commit 27da969) Requisiti: v2.3-REQUIREMENTS.md

Nota di archivio. v2.3 è stata eseguita fuori dal ciclo GSD: non sono mai esistite cartelle phases/23, 24, 25 con PLAN/SUMMARY. Questo file è la documentazione della milestone — non cercare altrove.

Obiettivo

Aggiungere uno strato email all'app: gate OTP per il portale cliente e invio del link preventivo dall'admin, con un'unica integrazione Resend condivisa.

Il portale non doveva più essere apribile col solo link: chiunque avesse l'URL vedeva il progetto del cliente.

Fasi

Phase 23 — Resend Setup 2026-07-28

Goal: infrastruttura email condivisa. Requisiti: SEND-01, SEND-02 (poi ridotti — vedi sotto).

Consegnato: resend@6.18.1, src/lib/mailer.ts (Result tipizzato, mai un catch silenzioso), template OTP in italiano. RESEND_API_KEY e RESEND_FROM configurate su Coolify (production e preview).

Riduzione di scope del 2026-07-28: SEND-01/SEND-02 (invio del preventivo via email dall'admin) spostati al backlog. Il preventivo si manda a mano; l'automazione non serviva subito. Phase 23 si è ridotta alla sola infrastruttura Resend, che il gate OTP usa comunque.

Phase 24 — Schema + Whitelist Admin 2026-07-28

Goal: l'admin gestisce la whitelist email di ogni cliente; tabelle pronte per il gate. Requisiti: OTP-01. Dipende da: Phase 23.

Migration 0015_otp_access.sql, additiva pura, applicata a prod via SSH prima del codice dipendente: client_emails (whitelist, unique case-insensitive), otp_codes (hash del codice, mai il codice in chiaro), clients.sessions_valid_from (revoca in blocco). Conteggi pre/post identici sulle tabelle protette — clients 4 / projects 5 / payments 11 / phases 10.

UI: sezione "Accessi al portale" in /admin/clients/[id] — aggiungi/rimuovi email, "Revoca sessioni attive". Server actions in clients/[id]/actions.ts.

Phase 25 — OTP Gate + Sessione 2026-07-29

Goal: /client/[token]/* richiede verifica OTP prima di mostrare la dashboard. Requisiti: OTP-02..OTP-07. Dipende da: Phase 24.

Consegnato: src/lib/otp.ts (codice 6 cifre CSPRNG, hash SHA-256 con NEXTAUTH_SECRET+clientId, TTL 15 minuti, monouso, max 5 tentativi), src/lib/client-session.ts (cookie HMAC per-cliente ch_sess_<id>, httpOnly + secure + SameSite=lax, path=/client), src/lib/client-gate.ts, le route /api/client/otp/request|verify, il componente OtpGate.

Scostamento dalla spec del 21/06: sessione 90 giorni invece di 30 — rientro più fluido, compensato da OTP-08 (revoca in blocco lato admin).

Catena di dipendenze

Phase 23 (Resend SDK + env)
    └── Phase 24 (schema additivo: client_emails + otp_codes)
            └── Phase 25 (gate OTP + sessione cookie 90gg)

Copertura requisiti

Requisito Fase Esito
SEND-01, SEND-02 23 ⏭ Rinviati al backlog il 2026-07-28
OTP-01 24
OTP-02 … OTP-07 25
OTP-08 (revoca) 24

Verifica in produzione (2026-07-29, hub.iamcavalli.net)

Gate mostrato senza cookie e zero dati di progetto nell'HTML (12.487 byte); email fuori e dentro whitelist danno risposta identica e solo la seconda genera un OTP; codice sbagliato rifiutato, corretto accettato; cookie ch_sess_<id> con Secure + HttpOnly + SameSite=lax + Max-Age=7776000; rientro col cookie mostra la dashboard; la sessione di un cliente sull'URL di un altro mostra il gate. Nessun errore d'invio nei log del container. Dati di test rimossi, tabelle protette invariate.

Lezioni

Le due lezioni operative di questa milestone (il gate non va nel layout App Router; ricreare il dominio su Resend rigenera la chiave DKIM) sono in STATUS.md, sezione "Lezioni operative" — è lì che si vanno a cercare.

Strascico alla chiusura

La whitelist è stata seedata solo con mario@test.it (cliente di test). Tre clienti reali su quattro hanno whitelist vuota e finché lo è il loro portale non è accessibile. Voce aperta in STATUS.md.