feat: customer contacts table, branded mail-from on root domain
Some checks failed
Build & Release / build (push) Has been cancelled

- Add customer_contacts table for storing contacts per customer
- Save initial user as primary contact during provisioning
- Use "Store Name via LunarFront <noreply@lunarfront.tech>" as mail-from
  (root domain is verified with Resend, no per-customer DNS needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ryan
2026-04-05 17:31:58 +00:00
parent b2e89bec33
commit cf97834c82
2 changed files with 21 additions and 1 deletions

View File

@@ -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`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`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` await db`
ALTER TABLE customers ALTER TABLE customers
ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT '', ADD COLUMN IF NOT EXISTS name TEXT NOT NULL DEFAULT '',

View File

@@ -142,7 +142,7 @@ export async function customerRoutes(app: FastifyInstance) {
"spaces-prefix": `${slug}/`, "spaces-prefix": `${slug}/`,
"encryption-key": encryptionKey, "encryption-key": encryptionKey,
"resend-api-key": config.resendApiKey, "resend-api-key": config.resendApiKey,
"mail-from": `noreply@${slug}.lunarfront.tech`, "mail-from": `${body.name} via LunarFront <noreply@lunarfront.tech>`,
"business-name": body.name, "business-name": body.name,
...(body.initialUser ? { ...(body.initialUser ? {
"initial-user-email": body.initialUser.email, "initial-user-email": body.initialUser.email,
@@ -159,6 +159,14 @@ export async function customerRoutes(app: FastifyInstance) {
await setStep("chart", "done"); await setStep("chart", "done");
await db`UPDATE customers SET status = 'provisioned', updated_at = NOW() WHERE slug = ${slug}`; 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) { } catch (err) {
const failedStep = Object.entries(steps).find(([, v]) => v === "pending")?.[0]; const failedStep = Object.entries(steps).find(([, v]) => v === "pending")?.[0];
if (failedStep) await setStep(failedStep, "failed"); if (failedStep) await setStep(failedStep, "failed");