import { pgTable, serial, integer, text, boolean, timestamp, jsonb, uniqueIndex } from 'drizzle-orm/pg-core'; import { users } from 'officerdb/auth/schema'; export const emailAccounts = pgTable( 'email_accounts', { id: serial('id').primaryKey(), userId: integer('user_id') .notNull() .references(() => users.id, { onDelete: 'cascade' }), provider: text('provider').notNull(), email: text('email').notNull(), displayName: text('display_name'), imapHost: text('imap_host').notNull(), imapPort: integer('imap_port').notNull(), imapSecure: boolean('imap_secure').notNull().default(true), authType: text('auth_type').notNull(), /** * The account's IMAP/SMTP secret, AES-256-GCM ciphertext under the `email` secret-store purpose. * * `text`, not `jsonb`: this is an opaque blob and typing it as JSON would invite something to read it * as structure. It was plaintext jsonb in the platform — every query and the SMTP transport read the * app password directly — and that is the one thing this extraction deliberately did NOT carry over. * * Encrypted and decrypted in `queries.ts` alone, so nothing above it ever handles ciphertext, and one * leaked key opens this plugin's column rather than every plugin's. */ credentials: text('credentials').notNull(), enabled: boolean('enabled').notNull().default(true), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), status: text('status').notNull().default('connected'), /** * LEGACY, read-only. The sync position now lives in the account's own `emails.db` * (`sidecar/email/sync-meta.ts`), so the file is self-describing and an account can be moved to * another machine by copying it. * * Kept because it is the one-time backfill source for every account created before that move; the * first sync after it migrates these keys into SQLite and nothing writes here again. Dropping it * would strand any account that has not synced since. */ syncMeta: jsonb('sync_meta').notNull().default({}), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }, (table) => [uniqueIndex('uq_email_accounts_user_email').on(table.userId, table.email)], );