From cf97834c8205e9ae7be64291a84cf79fa94e0751 Mon Sep 17 00:00:00 2001 From: ryan Date: Sun, 5 Apr 2026 17:31:58 +0000 Subject: [PATCH] feat: customer contacts table, branded mail-from on root domain - Add customer_contacts table for storing contacts per customer - Save initial user as primary contact during provisioning - Use "Store Name via LunarFront " as mail-from (root domain is verified with Resend, no per-customer DNS needed) Co-Authored-By: Claude Opus 4.6 (1M context) --- src/db/manager.ts | 12 ++++++++++++ src/routes/customers.ts | 10 +++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/db/manager.ts b/src/db/manager.ts index 1f6fa7d..6dba8b1 100644 --- a/src/db/manager.ts +++ b/src/db/manager.ts @@ -40,6 +40,18 @@ export async function migrate() { `; await db`CREATE INDEX IF NOT EXISTS customer_size_snapshots_slug_date ON customer_size_snapshots (slug, recorded_at DESC)`; await db`ALTER TABLE users ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`; + await db` + CREATE TABLE IF NOT EXISTS customer_contacts ( + id SERIAL PRIMARY KEY, + slug TEXT NOT NULL REFERENCES customers(slug) ON DELETE CASCADE, + email TEXT NOT NULL, + first_name TEXT NOT NULL, + last_name TEXT NOT NULL, + is_primary BOOLEAN NOT NULL DEFAULT false, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + ) + `; + await db`CREATE INDEX IF NOT EXISTS customer_contacts_slug ON customer_contacts (slug)`; await db` ALTER TABLE customers ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT '', diff --git a/src/routes/customers.ts b/src/routes/customers.ts index e3a00a1..c42f338 100644 --- a/src/routes/customers.ts +++ b/src/routes/customers.ts @@ -142,7 +142,7 @@ export async function customerRoutes(app: FastifyInstance) { "spaces-prefix": `${slug}/`, "encryption-key": encryptionKey, "resend-api-key": config.resendApiKey, - "mail-from": `noreply@${slug}.lunarfront.tech`, + "mail-from": `${body.name} via LunarFront `, "business-name": body.name, ...(body.initialUser ? { "initial-user-email": body.initialUser.email, @@ -159,6 +159,14 @@ export async function customerRoutes(app: FastifyInstance) { await setStep("chart", "done"); await db`UPDATE customers SET status = 'provisioned', updated_at = NOW() WHERE slug = ${slug}`; + + // Save initial user as primary contact + if (body.initialUser) { + await db` + INSERT INTO customer_contacts (slug, email, first_name, last_name, is_primary) + VALUES (${slug}, ${body.initialUser.email}, ${body.initialUser.firstName}, ${body.initialUser.lastName}, true) + `; + } } catch (err) { const failedStep = Object.entries(steps).find(([, v]) => v === "pending")?.[0]; if (failedStep) await setStep(failedStep, "failed");