diff --git a/.env.development b/.env.development index f782ea9e0..9b95deea9 100644 --- a/.env.development +++ b/.env.development @@ -509,3 +509,35 @@ GPU_SERVER_LAN_URL=http://192.168.178.11 # Vision Model for Food + Planta (local, replaces Google Gemini) VISION_MODEL=ollama/gemma3:12b + +# ============================================ +# MANA-MAIL SERVICE (Port 3042) +# ============================================ +# Stalwart + Broadcast (Newsletter) config. Stalwart settings come from +# the Stalwart admin panel; these are the Mana-side knobs. + +# mana-mail DB uses mana_platform (shared). Dev fallback in code is fine; +# override here for staging/prod. +MANA_MAIL_DATABASE_URL=postgresql://mana:devpassword@localhost:5432/mana_platform + +# Stalwart JMAP/admin — align with your local Stalwart container +STALWART_JMAP_URL=http://localhost:8080 +STALWART_ADMIN_USER=admin +STALWART_ADMIN_PASSWORD=ChangeMe123! +MAIL_DOMAIN=mana.how + +# ─── Broadcast (Newsletter) ──────────────────────────────── +# HMAC secret for tracking-token signing. Tokens appear in public URLs +# (open pixel, click redirect, unsubscribe link). CHANGE IN PROD. +# Use `openssl rand -hex 32` or similar for a real secret. +BROADCAST_TRACKING_SECRET=dev-broadcast-tracking-secret-NOT-for-prod + +# How many recipients a single campaign may have. Hard cap. +BROADCAST_MAX_RECIPIENTS_PER_CAMPAIGN=5000 + +# Per-user rate limit — not currently enforced, reserved for M-Phase2. +BROADCAST_MAX_RECIPIENTS_PER_HOUR=500 + +# Milliseconds to sleep between JMAP submits during bulk-send. +# 150ms ≈ 6/sec ≈ 360/min. Protects Stalwart + downstream relays. +BROADCAST_SEND_THROTTLE_MS=150 diff --git a/scripts/generate-env.mjs b/scripts/generate-env.mjs index 86e84debd..a26e89d3c 100644 --- a/scripts/generate-env.mjs +++ b/scripts/generate-env.mjs @@ -122,6 +122,32 @@ const APP_CONFIGS = [ }, }, + // Mana Mail Service (Hono + Bun, Port 3042) + // Stalwart proxy + 1:1 send via JMAP + broadcast (newsletter) via bulk-send. + { + path: 'services/mana-mail/.env', + vars: { + PORT: (env) => env.MANA_MAIL_PORT || '3042', + DATABASE_URL: (env) => + env.MANA_MAIL_DATABASE_URL || 'postgresql://mana:devpassword@localhost:5432/mana_platform', + MANA_AUTH_URL: (env) => env.MANA_AUTH_URL || 'http://localhost:3001', + MANA_SERVICE_KEY: (env) => env.MANA_SERVICE_KEY || 'dev-service-key', + BASE_URL: (env) => env.MANA_MAIL_BASE_URL || 'http://localhost:3042', + CORS_ORIGINS: (env) => env.CORS_ORIGINS || 'http://localhost:5173', + STALWART_JMAP_URL: (env) => env.STALWART_JMAP_URL || 'http://localhost:8080', + STALWART_ADMIN_USER: (env) => env.STALWART_ADMIN_USER || 'admin', + STALWART_ADMIN_PASSWORD: (env) => env.STALWART_ADMIN_PASSWORD || 'ChangeMe123!', + MAIL_DOMAIN: (env) => env.MAIL_DOMAIN || 'mana.how', + // Broadcast / newsletter config — generated secrets rotate at deploy. + BROADCAST_TRACKING_SECRET: (env) => + env.BROADCAST_TRACKING_SECRET || 'dev-broadcast-tracking-secret-NOT-for-prod', + BROADCAST_MAX_RECIPIENTS_PER_CAMPAIGN: (env) => + env.BROADCAST_MAX_RECIPIENTS_PER_CAMPAIGN || '5000', + BROADCAST_MAX_RECIPIENTS_PER_HOUR: (env) => env.BROADCAST_MAX_RECIPIENTS_PER_HOUR || '500', + BROADCAST_SEND_THROTTLE_MS: (env) => env.BROADCAST_SEND_THROTTLE_MS || '150', + }, + }, + // Chat Server (Hono/Bun) { path: 'apps/chat/apps/server/.env', diff --git a/services/mana-mail/drizzle.config.ts b/services/mana-mail/drizzle.config.ts index 3cda276e1..c78e175cb 100644 --- a/services/mana-mail/drizzle.config.ts +++ b/services/mana-mail/drizzle.config.ts @@ -7,5 +7,8 @@ export default defineConfig({ dbCredentials: { url: process.env.DATABASE_URL || 'postgresql://mana:devpassword@localhost:5432/mana_platform', }, - schemaFilter: ['mail'], + // Scope to just the schemas mana-mail owns. Other services (mana-auth, + // mana-research) manage their own pgSchemas; pushing all would + // accidentally drop foreign rows on each service's next migration. + schemaFilter: ['mail', 'broadcast'], });