47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
|
|
import { pgTable, text, timestamp, index } from 'drizzle-orm/pg-core';
|
||
|
|
import { ports } from './ports';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Bounce-monitoring storage. The IMAP poller writes one row per parsed
|
||
|
|
* DSN (Delivery Status Notification) it finds in a monitored sender's
|
||
|
|
* inbox. Consumers (admin/bounces page, notifications worker, UI badges
|
||
|
|
* on document_sends rows) join in via `originalSendType` /
|
||
|
|
* `originalSendId`.
|
||
|
|
*/
|
||
|
|
export const emailBounces = pgTable(
|
||
|
|
'email_bounces',
|
||
|
|
{
|
||
|
|
id: text('id')
|
||
|
|
.primaryKey()
|
||
|
|
.$defaultFn(() => crypto.randomUUID()),
|
||
|
|
portId: text('port_id')
|
||
|
|
.notNull()
|
||
|
|
.references(() => ports.id, { onDelete: 'cascade' }),
|
||
|
|
/** The mailbox we polled to find this bounce. */
|
||
|
|
mailboxAddress: text('mailbox_address').notNull(),
|
||
|
|
/** The address that bounced (the original recipient). */
|
||
|
|
bouncedAddress: text('bounced_address').notNull(),
|
||
|
|
/** One of `document_send` / `notification` / `email_thread` / `null`. */
|
||
|
|
originalSendType: text('original_send_type'),
|
||
|
|
/** The id of the original send row, when resolvable. */
|
||
|
|
originalSendId: text('original_send_id'),
|
||
|
|
/** RFC 3464 DSN fields. Null when the upstream provider uses a
|
||
|
|
* non-RFC bounce format (some providers send HTML-only bounces). */
|
||
|
|
dsnAction: text('dsn_action'),
|
||
|
|
dsnStatus: text('dsn_status'),
|
||
|
|
dsnDiagnostic: text('dsn_diagnostic'),
|
||
|
|
receivedAt: timestamp('received_at', { withTimezone: true }).notNull().defaultNow(),
|
||
|
|
/** Full raw message for forensics. Trimmed to ~32KB before insert. */
|
||
|
|
rawMessage: text('raw_message'),
|
||
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
||
|
|
},
|
||
|
|
(table) => [
|
||
|
|
index('idx_email_bounces_port_received').on(table.portId, table.receivedAt),
|
||
|
|
index('idx_email_bounces_bounced_address').on(table.bouncedAddress),
|
||
|
|
index('idx_email_bounces_original_send').on(table.originalSendType, table.originalSendId),
|
||
|
|
],
|
||
|
|
);
|
||
|
|
|
||
|
|
export type EmailBounce = typeof emailBounces.$inferSelect;
|
||
|
|
export type NewEmailBounce = typeof emailBounces.$inferInsert;
|