feat(schema): berths.archived_at + clients.source_inquiry_id + email_bounces
Step 3 schema additions per PRE-DEPLOY-PLAN § 1.4. berths.archived_at (+ archived_by, archive_reason) — soft-delete column so retired moorings can be hidden from the public feed and admin lists without losing historical interest joins. Partial index `idx_berths_active` on (port_id) WHERE archived_at IS NULL keeps the active-only list path fast. Already wired: - /api/public/berths and /api/public/berths/[mooringNumber] now filter out archived rows. - berths.service.listBerths defaults to active-only with an ?includeArchived=true escape hatch for the archive bin. clients.source_inquiry_id — text column with ON DELETE SET NULL FK to website_submissions(id). Preserves the linkage from a website inquiry to the client that came out of the "Convert to client" triage flow (P-4.5). Drives the conversion-funnel-by-source chart (Step 6). The Drizzle column ships without `.references()` to avoid the cross-file circular import; the FK lives in the migration SQL. email_bounces table — bounce-monitoring storage. The DSN poller worker (forthcoming, depends on this table existing) writes one row per parsed bounce; consumers join via (original_send_type, original_send_id). Three secondary indexes cover the expected access patterns (port + recent bounces; lookup by bounced address; lookup by original send). Schema additions plus the migration SQL are ready for `pnpm db:push` (or the migration runner once its journal is backfilled — separate concern, journal currently stops at 0042 despite migrations through 0065 existing on disk). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,12 @@ export const clients = pgTable(
|
||||
timezone: text('timezone'),
|
||||
source: text('source'), // website, manual, referral, broker
|
||||
sourceDetails: text('source_details'),
|
||||
/** When this client came out of a "Convert inquiry to client" triage
|
||||
* step, points back at the originating `website_submissions` row.
|
||||
* Drives the conversion-funnel-by-source chart. Migration 0065
|
||||
* installs the FK with ON DELETE SET NULL — Drizzle doesn't reflect
|
||||
* it here to avoid the cross-file circular import. */
|
||||
sourceInquiryId: text('source_inquiry_id'),
|
||||
archivedAt: timestamp('archived_at', { withTimezone: true }),
|
||||
/** Better-auth user id of the operator who archived this client. */
|
||||
archivedBy: text('archived_by'),
|
||||
|
||||
Reference in New Issue
Block a user