/** * Marketing: email templates + campaigns. * Source of truth: `db/migrations/0001_init.sql`. */ import { pgTable, uuid, text, integer, timestamp, index, } from "drizzle-orm/pg-core"; import { campaignStatusEnum } from "./enums"; import { brands } from "./brands"; export const emailTemplates = pgTable( "email_templates", { id: uuid("id").primaryKey().defaultRandom(), brandId: uuid("brand_id") .notNull() .references(() => brands.id, { onDelete: "cascade" }), name: text("name").notNull(), subject: text("subject").notNull(), bodyHtml: text("body_html").notNull(), createdAt: timestamp("created_at", { withTimezone: true }) .notNull() .defaultNow(), updatedAt: timestamp("updated_at", { withTimezone: true }) .notNull() .defaultNow(), }, (t) => ({ brandIdx: index("email_templates_brand_idx").on(t.brandId), }), ); export const campaigns = pgTable( "campaigns", { id: uuid("id").primaryKey().defaultRandom(), brandId: uuid("brand_id") .notNull() .references(() => brands.id, { onDelete: "cascade" }), templateId: uuid("template_id").references((): any => emailTemplates.id, { onDelete: "set null", }), name: text("name").notNull(), status: text("status", { enum: campaignStatusEnum }) .notNull() .default("draft"), scheduledFor: timestamp("scheduled_for", { withTimezone: true }), sentAt: timestamp("sent_at", { withTimezone: true }), recipientCount: integer("recipient_count").notNull().default(0), createdAt: timestamp("created_at", { withTimezone: true }) .notNull() .defaultNow(), updatedAt: timestamp("updated_at", { withTimezone: true }) .notNull() .defaultNow(), }, (t) => ({ brandIdx: index("campaigns_brand_idx").on(t.brandId), statusIdx: index("campaigns_status_idx").on(t.brandId, t.status), }), ); export type EmailTemplate = typeof emailTemplates.$inferSelect; export type NewEmailTemplate = typeof emailTemplates.$inferInsert; export type Campaign = typeof campaigns.$inferSelect; export type NewCampaign = typeof campaigns.$inferInsert;