diff --git a/.planning/STATE.md b/.planning/STATE.md index 4a64760..6512c97 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,9 +3,9 @@ gsd_state_version: 1.0 milestone: v2.3 milestone_name: Email & Accesso status: executing -stopped_at: "v2.3 implementata e testata in locale; deploy BLOCCATO su RESEND_API_KEY + whitelist clienti" -last_updated: "2026-07-28T20:45:00.000Z" -last_activity: 2026-07-28 -- Phases 23/24/25 (OTP gate) implementate e verificate E2E; non ancora pushate +stopped_at: "v2.3 pronta e Coolify configurato; deploy BLOCCATO sul record DKIM di iamcavalli.net (chiave vecchia)" +last_updated: "2026-07-29T15:45:00.000Z" +last_activity: 2026-07-29 -- Coolify configurato + mailer verificato; deploy fermo sul record DKIM (azione utente) progress: total_phases: 3 completed_phases: 3 @@ -31,13 +31,32 @@ Plan: `~/.claude/plans/si-ma-abbiamo-un-jaunty-micali.md` Status: **Bloccata sul deploy**, non sul codice. Vedi "Blocchi al deploy" qui sotto. Last activity: 2026-07-28 — gate OTP completo, 9/9 test E2E passati contro il DB di produzione -### ⛔ Blocchi al deploy (2026-07-28) +### ⛔ Unico blocco residuo al deploy: record DKIM (2026-07-29) -Pushare così com'è **chiude fuori i clienti reali dal loro portale**. Prima del push servono, in quest'ordine: +**Il record DKIM di `iamcavalli.net` contiene una chiave vecchia**, diversa da quella che Resend si aspetta → dominio `status: failed`, invio da `no-reply@iamcavalli.net` rifiutato con 403. SPF (TXT + MX su `send`) sono verificati, solo il DKIM no. -1. **`RESEND_API_KEY` + `RESEND_FROM` su Coolify** (production). Senza, nessuno riceve il codice e il portale è inaccessibile a tutti. Serve un account Resend con dominio verificato. In `.env.local` i due nomi ci sono ma il valore della key è vuoto. -2. **Whitelist popolata per i 3 clienti reali.** La migration ha seedato `client_emails` da `clients.email`, ma solo 1 cliente su 4 aveva quel campo valorizzato (`mario@test.it`, cliente di test "Rossi Inc"). George Vlad / Protocollo Estetico, Gian Luca Caruso / Caruso Speaker e Gianfranco Barban / Teckell hanno **whitelist vuota** → gate senza via d'uscita. Da fare da `/admin/clients/` → sezione "Accessi al portale". -3. Solo dopo: push su `main` → auto-deploy Coolify → riverifica su `hub.iamcavalli.net`. +Da sostituire — TXT, nome `resend._domainkey`: + +``` +p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFHKhBLdT31CDeh5R0MWQM1XRmxwQrXS6TJXNa1Id9KP+nDPree4EWvTal7o440MUp4vwbW07AONoNjuIT8gMaC3a+e4396kQ9ewUpApa26azNf4k1092N6kSfNhfmU+oM5c/VYFEuPqp0yf1ar3M8w8WA4BELL4VBq29xk4/m4QIDAQAB +``` + +Finché non è sistemato, deployare renderebbe il portale inaccessibile a **tutti** i clienti (nessuno riceve il codice). Decisione dell'utente il 2026-07-29: **non pushare, si aspetta il DNS.** I token Hetzner/Cloudflare in `~/.coolify.env` sono vuoti → il DNS lo cambia l'utente a mano. + +Sequenza alla ripresa: + +1. Verificare propagazione: `dig +short TXT resend._domainkey.iamcavalli.net @8.8.8.8` deve restituire la chiave che inizia per `p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFHKhB…` +2. Ri-triggerare la verifica su Resend e controllare `status: verified` (`GET /domains/a2a80798-6f3a-42fe-8946-2c7f40f32c03`). +3. Test d'invio dal dominio reale verso un indirizzo qualsiasi. +4. Push su `main` → auto-deploy Coolify. +5. Popolare la whitelist dei 3 clienti reali da `/admin/clients/` → "Accessi al portale". L'utente ha detto che li re-invita, quindi non è bloccante: la migration ha seedato solo `mario@test.it` (cliente di test "Rossi Inc"), mentre Protocollo Estetico, Caruso Speaker e Teckell partono con whitelist vuota. +6. Riverifica su `hub.iamcavalli.net`. + +**Già fatto (2026-07-29):** + +- `RESEND_API_KEY` + `RESEND_FROM` **configurate su Coolify** (production e preview) via API — verificate presenti. +- **Mailer verificato funzionante**: `sendEmail()` con il template OTP reale ha restituito `{ok:true, id:…}` e Resend ha accettato l'email (consegna confermata verso `info@iamcavalli.net` usando `onboarding@resend.dev`, l'unica coppia mittente/destinatario permessa senza dominio verificato). +- Verificato che quando Resend rifiuta, la route risponde comunque con il messaggio neutro e logga l'errore lato server — il comportamento no-enumeration tiene anche a provider guasto. ### Cosa è stato consegnato in v2.3 (codice locale, buildato e testato) @@ -119,8 +138,10 @@ None yet. ### Blockers/Concerns -- **[BLOCCANTE] `RESEND_API_KEY` + `RESEND_FROM` su Coolify** — senza, il gate OTP deployato rende il portale inaccessibile a tutti i clienti. Stessa procedura di `ANTHROPIC_API_KEY` (2026-06-20). Serve un account Resend con dominio verificato. -- **[BLOCCANTE] Whitelist vuota per 3 clienti su 4** — vedi "Blocchi al deploy". Da popolare da `/admin/clients/` prima del push. +- **[BLOCCANTE] Record DKIM di `iamcavalli.net` con chiave vecchia** — vedi "Unico blocco residuo al deploy". Finché non è corretto, nessun invio dal dominio è possibile e deployare il gate chiuderebbe fuori tutti i clienti. +- ~~`RESEND_API_KEY` + `RESEND_FROM` su Coolify~~ — **fatto 2026-07-29**, production e preview. +- **Whitelist vuota per 3 clienti su 4** (non bloccante: l'utente li re-invita) — da popolare da `/admin/clients/` → "Accessi al portale". +- **Coolify API**: credenziali in `~/.coolify.env` (`export COOLIFY_URL/COOLIFY_TOKEN`, va sorgentato con `set -a; . ~/.coolify.env`). App ClientHub uuid `xsksow44g4kcoo8wocsgkscc`. Il POST su `/api/v1/applications//envs` **non accetta** il campo `is_build_time` (422): mandare solo `key`, `value`, `is_preview`. I token Hetzner/Cloudflare nel file sono **vuoti** → il DNS non è modificabile via API. - **Migrations (sempre valido)**: ogni fase con schema DEVE avere la migration applicata a prod PRIMA di pushare il codice dipendente. `drizzle-kit generate` rotto → SQL a mano. La 0015 è già applicata. Due strade: `cat migration.sql | ssh root@178.104.27.55 "docker exec -i xwkk0040w0kk0gsgcgog8owk psql -U clienthub -d clienthub -v ON_ERROR_STOP=1 --single-transaction"` (autoritativa, nessun tunnel), oppure tunnel `ssh -f -N -L 54321:localhost:54321 root@178.104.27.55` con `DATABASE_URL` riscritto a `127.0.0.1:54321` se serve puntarci il tooling locale. - **`.env.local` punta al DB di PRODUZIONE** (178.104.27.55:54321, richiede il tunnel). Non esiste un DB di sviluppo separato: qualsiasi test in locale scrive su dati reali. Verificare sempre i conteggi delle tabelle protette prima e dopo. - **Debito tecnico (non bloccante)**: tabelle legacy `service_catalog`/`offer_services`/`offer_micro_services` restano come deadweight; `createService`/`serviceSchema` dead code in `catalog/actions.ts`. @@ -141,7 +162,7 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-07-28T20:45:00.000Z -Stopped at: v2.3 implementata e verificata E2E in locale (9/9). **Non pushata**: mancano `RESEND_API_KEY` su Coolify e la whitelist dei 3 clienti reali. -Next: configurare Resend → popolare le whitelist → push su `main` → riverifica su `hub.iamcavalli.net`. +Last session: 2026-07-29T15:45:00.000Z +Stopped at: v2.3 implementata, verificata E2E (9/9) e mailer confermato funzionante. Coolify configurato. **Non pushata**: manca solo la correzione del record DKIM, che deve fare l'utente a mano. +Next: `dig +short TXT resend._domainkey.iamcavalli.net @8.8.8.8` → verifica Resend → push su `main` → whitelist dei 3 clienti → riverifica su `hub.iamcavalli.net`. Resume file: .planning/STATE.md