/** * Field-level override history for interests + their linked clients. * * Every time a field on an interest or its linked client is overridden * via an explicit channel (today: supplemental-info form submission; * future: form-templates, AI-assisted extraction acceptance), a row * lands here. Distinct from `audit_logs` — that table tracks every * CRUD event for compliance; this one tracks only deliberate overrides * so the Interest + Client "Field history" panels can surface them * compactly. */ import { pgTable, text, jsonb, timestamp, index } from 'drizzle-orm/pg-core'; import { sql } from 'drizzle-orm'; import { ports } from './ports'; import { interests } from './interests'; import { clients } from './clients'; export const interestFieldHistory = pgTable( 'interest_field_history', { id: text('id') .primaryKey() .$defaultFn(() => crypto.randomUUID()), portId: text('port_id') .notNull() .references(() => ports.id), interestId: text('interest_id').references(() => interests.id, { onDelete: 'cascade' }), /** Denormalized for fast lookup on the Client detail "Field history" * panel — overrides that come in via a supplemental-info form * carry both interest + client refs. Direct-edit overrides may * only carry one. */ clientId: text('client_id').references(() => clients.id, { onDelete: 'cascade' }), /** Dotted path of the field that was overridden. Examples: * 'client.fullName' * 'interest.desiredLengthFt' * 'client.address.streetAddress' * The Field history panel formats this for display. */ fieldPath: text('field_path').notNull(), oldValue: jsonb('old_value'), newValue: jsonb('new_value').notNull(), /** Provenance: 'supplemental_form' | 'rep_edit' | 'system_inferred' | * 'ai_extraction' (future). Drives the "Submitted via X" copy. */ source: text('source').notNull(), /** Optional FK to the form_submissions row that triggered the * override. Lets the UI link back to the original submission. */ submissionId: text('submission_id'), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), createdBy: text('created_by'), }, (table) => [ index('idx_ifh_interest_created') .on(table.portId, table.interestId, table.createdAt) .where(sql`${table.interestId} IS NOT NULL`), index('idx_ifh_client_created') .on(table.portId, table.clientId, table.createdAt) .where(sql`${table.clientId} IS NOT NULL`), ], ); export type InterestFieldHistory = typeof interestFieldHistory.$inferSelect; export type NewInterestFieldHistory = typeof interestFieldHistory.$inferInsert;