SMTP per-shop configurabile dalle Impostazioni (password cifrata AES-256-GCM)

- Settings: smtpHost/Port/User/Pass(cifrata)/Secure/From. Vuoto -> provider
  default dell'app (env); compilato -> invio dal SMTP del merchant.
- crypto.server: encrypt/decrypt AES-256-GCM (chiave APP_ENCRYPTION_KEY).
- mailer: SmtpConfig + buildTransport(smtp) per-shop o env; mailFrom override.
  Sia ricevuta cliente sia notifica merchant usano lo SMTP del merchant.
- proxy: costruisce SmtpConfig (decifra pass), passa ai due invii.
- admin: nuovo tab 'Email (SMTP)'; password mai ri-mostrata (vuoto = invariata).
- Migrazione smtp_settings. APP_ENCRYPTION_KEY: dev in .env, prod = fly secret.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
This commit is contained in:
2026-07-07 17:28:46 +02:00
parent ad9f76b6be
commit 3bb7a30c1d
7 changed files with 218 additions and 12 deletions

View File

@@ -0,0 +1,7 @@
-- AlterTable
ALTER TABLE "Settings" ADD COLUMN "smtpFrom" TEXT,
ADD COLUMN "smtpHost" TEXT,
ADD COLUMN "smtpPass" TEXT,
ADD COLUMN "smtpPort" INTEGER,
ADD COLUMN "smtpSecure" BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN "smtpUser" TEXT;

View File

@@ -63,6 +63,12 @@ model Settings {
returnInstructions String? // deprecato: sostituito da opTextShipped
opTextUnfulfilled String?
opTextShipped String?
smtpHost String?
smtpPort Int?
smtpUser String?
smtpPass String? // cifrato AES-256-GCM (mai in chiaro)
smtpSecure Boolean @default(false)
smtpFrom String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt