From 85000ad82b0ceaf772949447b9839b1a2aa7eb0e Mon Sep 17 00:00:00 2001 From: "Wei S." <5291640+wayneshn@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:16:14 +0100 Subject: [PATCH 1/2] Retention policy schema/types (#325) --- .../backend/src/database/schema/compliance.ts | 110 +++++++++++++++--- packages/backend/src/helpers/deletionGuard.ts | 11 +- packages/backend/src/hooks/RetentionHook.ts | 36 ++++++ .../src/services/ArchivedEmailService.ts | 12 +- packages/types/src/index.ts | 1 + packages/types/src/license.types.ts | 5 + packages/types/src/retention.types.ts | 33 ++++++ 7 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 packages/backend/src/hooks/RetentionHook.ts create mode 100644 packages/types/src/retention.types.ts diff --git a/packages/backend/src/database/schema/compliance.ts b/packages/backend/src/database/schema/compliance.ts index dca199c..2019df6 100644 --- a/packages/backend/src/database/schema/compliance.ts +++ b/packages/backend/src/database/schema/compliance.ts @@ -5,11 +5,15 @@ import { jsonb, pgEnum, pgTable, + primaryKey, text, timestamp, uuid, + varchar, } from 'drizzle-orm/pg-core'; +import { archivedEmails } from './archived-emails'; import { custodians } from './custodians'; +import { users } from './users'; // --- Enums --- @@ -33,6 +37,36 @@ export const retentionPolicies = pgTable('retention_policies', { updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }); +export const retentionLabels = pgTable('retention_labels', { + id: uuid('id').defaultRandom().primaryKey(), + name: varchar('name', { length: 255 }).notNull(), + retentionPeriodDays: integer('retention_period_days').notNull(), + description: text('description'), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + +export const emailRetentionLabels = pgTable('email_retention_labels', { + emailId: uuid('email_id') + .references(() => archivedEmails.id, { onDelete: 'cascade' }) + .notNull(), + labelId: uuid('label_id') + .references(() => retentionLabels.id, { onDelete: 'cascade' }) + .notNull(), + appliedAt: timestamp('applied_at', { withTimezone: true }).notNull().defaultNow(), + appliedByUserId: uuid('applied_by_user_id').references(() => users.id), +}, (t) => [ + primaryKey({ columns: [t.emailId, t.labelId] }), +]); + +export const retentionEvents = pgTable('retention_events', { + id: uuid('id').defaultRandom().primaryKey(), + eventName: varchar('event_name', { length: 255 }).notNull(), + eventType: varchar('event_type', { length: 100 }).notNull(), + eventTimestamp: timestamp('event_timestamp', { withTimezone: true }).notNull(), + targetCriteria: jsonb('target_criteria').notNull(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), +}); + export const ediscoveryCases = pgTable('ediscovery_cases', { id: uuid('id').primaryKey().defaultRandom(), name: text('name').notNull().unique(), @@ -44,18 +78,31 @@ export const ediscoveryCases = pgTable('ediscovery_cases', { }); export const legalHolds = pgTable('legal_holds', { - id: uuid('id').primaryKey().defaultRandom(), - caseId: uuid('case_id') - .notNull() - .references(() => ediscoveryCases.id, { onDelete: 'cascade' }), - custodianId: uuid('custodian_id').references(() => custodians.id, { onDelete: 'cascade' }), - holdCriteria: jsonb('hold_criteria'), + id: uuid('id').defaultRandom().primaryKey(), + name: varchar('name', { length: 255 }).notNull(), reason: text('reason'), - appliedByIdentifier: text('applied_by_identifier').notNull(), - appliedAt: timestamp('applied_at', { withTimezone: true }).notNull().defaultNow(), - removedAt: timestamp('removed_at', { withTimezone: true }), + isActive: boolean('is_active').notNull().default(true), + // Optional link to ediscovery cases for backward compatibility or future use + caseId: uuid('case_id').references(() => ediscoveryCases.id, { onDelete: 'set null' }), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }); +export const emailLegalHolds = pgTable( + 'email_legal_holds', + { + emailId: uuid('email_id') + .references(() => archivedEmails.id, { onDelete: 'cascade' }) + .notNull(), + legalHoldId: uuid('legal_hold_id') + .references(() => legalHolds.id, { onDelete: 'cascade' }) + .notNull(), + }, + (t) => [ + primaryKey({ columns: [t.emailId, t.legalHoldId] }), + ], +); + export const exportJobs = pgTable('export_jobs', { id: uuid('id').primaryKey().defaultRandom(), caseId: uuid('case_id').references(() => ediscoveryCases.id, { onDelete: 'set null' }), @@ -70,20 +117,51 @@ export const exportJobs = pgTable('export_jobs', { // --- Relations --- -export const ediscoveryCasesRelations = relations(ediscoveryCases, ({ many }) => ({ - legalHolds: many(legalHolds), - exportJobs: many(exportJobs), +export const retentionPoliciesRelations = relations(retentionPolicies, ({ many }) => ({ + // Add relations if needed })); -export const legalHoldsRelations = relations(legalHolds, ({ one }) => ({ +export const retentionLabelsRelations = relations(retentionLabels, ({ many }) => ({ + emailRetentionLabels: many(emailRetentionLabels), +})); + +export const emailRetentionLabelsRelations = relations(emailRetentionLabels, ({ one }) => ({ + label: one(retentionLabels, { + fields: [emailRetentionLabels.labelId], + references: [retentionLabels.id], + }), + email: one(archivedEmails, { + fields: [emailRetentionLabels.emailId], + references: [archivedEmails.id], + }), + appliedByUser: one(users, { + fields: [emailRetentionLabels.appliedByUserId], + references: [users.id], + }), +})); + +export const legalHoldsRelations = relations(legalHolds, ({ one, many }) => ({ + emailLegalHolds: many(emailLegalHolds), ediscoveryCase: one(ediscoveryCases, { fields: [legalHolds.caseId], references: [ediscoveryCases.id], }), - custodian: one(custodians, { - fields: [legalHolds.custodianId], - references: [custodians.id], +})); + +export const emailLegalHoldsRelations = relations(emailLegalHolds, ({ one }) => ({ + legalHold: one(legalHolds, { + fields: [emailLegalHolds.legalHoldId], + references: [legalHolds.id], }), + email: one(archivedEmails, { + fields: [emailLegalHolds.emailId], + references: [archivedEmails.id], + }), +})); + +export const ediscoveryCasesRelations = relations(ediscoveryCases, ({ many }) => ({ + legalHolds: many(legalHolds), + exportJobs: many(exportJobs), })); export const exportJobsRelations = relations(exportJobs, ({ one }) => ({ diff --git a/packages/backend/src/helpers/deletionGuard.ts b/packages/backend/src/helpers/deletionGuard.ts index 996b274..3d118c1 100644 --- a/packages/backend/src/helpers/deletionGuard.ts +++ b/packages/backend/src/helpers/deletionGuard.ts @@ -1,7 +1,16 @@ import { config } from '../config'; import i18next from 'i18next'; -export function checkDeletionEnabled() { +interface DeletionOptions { + allowSystemDelete?: boolean; +} + +export function checkDeletionEnabled(options?: DeletionOptions) { + // If system delete is allowed (e.g. by retention policy), bypass the config check + if (options?.allowSystemDelete) { + return; + } + if (!config.app.enableDeletion) { const errorMessage = i18next.t('Deletion is disabled for this instance.'); throw new Error(errorMessage); diff --git a/packages/backend/src/hooks/RetentionHook.ts b/packages/backend/src/hooks/RetentionHook.ts new file mode 100644 index 0000000..96406f6 --- /dev/null +++ b/packages/backend/src/hooks/RetentionHook.ts @@ -0,0 +1,36 @@ +import { logger } from '../config/logger'; + +export type DeletionCheck = (emailId: string) => Promise; + +export class RetentionHook { + private static checks: DeletionCheck[] = []; + + /** + * Registers a function that checks if an email can be deleted. + * The function should return true if deletion is allowed, false otherwise. + */ + static registerCheck(check: DeletionCheck) { + this.checks.push(check); + } + + /** + * Verifies if an email can be deleted by running all registered checks. + * If ANY check returns false, deletion is blocked. + */ + static async canDelete(emailId: string): Promise { + for (const check of this.checks) { + try { + const allowed = await check(emailId); + if (!allowed) { + logger.info(`Deletion blocked by retention check for email ${emailId}`); + return false; + } + } catch (error) { + logger.error(`Error in retention check for email ${emailId}:`, error); + // Fail safe: if a check errors, assume we CANNOT delete to be safe + return false; + } + } + return true; + } +} diff --git a/packages/backend/src/services/ArchivedEmailService.ts b/packages/backend/src/services/ArchivedEmailService.ts index ccf322d..fe2168c 100644 --- a/packages/backend/src/services/ArchivedEmailService.ts +++ b/packages/backend/src/services/ArchivedEmailService.ts @@ -20,6 +20,7 @@ import type { Readable } from 'stream'; import { AuditService } from './AuditService'; import { User } from '@open-archiver/types'; import { checkDeletionEnabled } from '../helpers/deletionGuard'; +import { RetentionHook } from '../hooks/RetentionHook'; interface DbRecipients { to: { name: string; address: string }[]; @@ -197,9 +198,16 @@ export class ArchivedEmailService { public static async deleteArchivedEmail( emailId: string, actor: User, - actorIp: string + actorIp: string, + options: { systemDelete?: boolean } = {} ): Promise { - checkDeletionEnabled(); + checkDeletionEnabled({ allowSystemDelete: options.systemDelete }); + + const canDelete = await RetentionHook.canDelete(emailId); + if (!canDelete) { + throw new Error('Deletion blocked by retention policy (Legal Hold or similar).'); + } + const [email] = await db .select() .from(archivedEmails) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f1eda70..a0b08aa 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -13,3 +13,4 @@ export * from './audit-log.enums'; export * from './integrity.types'; export * from './jobs.types'; export * from './license.types'; +export * from './retention.types'; diff --git a/packages/types/src/license.types.ts b/packages/types/src/license.types.ts index ee850a0..afbbd7b 100644 --- a/packages/types/src/license.types.ts +++ b/packages/types/src/license.types.ts @@ -64,6 +64,10 @@ export interface LicenseStatusPayload { lastCheckedAt?: string; /** The current plan seat limit from the license server. */ planSeats: number; + /** ISO 8601 UTC timestamp of the license expiration date. */ + expirationDate?: string; + /** Optional message from the license server (e.g. regarding account status). */ + message?: string; } /** @@ -78,6 +82,7 @@ export interface ConsolidatedLicenseStatus { remoteStatus: 'VALID' | 'INVALID' | 'UNKNOWN'; gracePeriodEnds?: string; lastCheckedAt?: string; + message?: string; // Calculated values activeSeats: number; isExpired: boolean; diff --git a/packages/types/src/retention.types.ts b/packages/types/src/retention.types.ts new file mode 100644 index 0000000..056e3dc --- /dev/null +++ b/packages/types/src/retention.types.ts @@ -0,0 +1,33 @@ +export interface RetentionPolicy { + id: string; + name: string; + priority: number; + conditions: Record; // JSON condition logic + retentionPeriodDays: number; + isActive: boolean; + createdAt: string; // ISO Date string +} + +export interface RetentionLabel { + id: string; + name: string; + retentionPeriodDays: number; + description?: string; + createdAt: string; // ISO Date string +} + +export interface RetentionEvent { + id: string; + eventName: string; + eventType: string; // e.g., 'EMPLOYEE_EXIT' + eventTimestamp: string; // ISO Date string + targetCriteria: Record; // JSON criteria + createdAt: string; // ISO Date string +} + +export interface LegalHold { + id: string; + name: string; + reason?: string; + isActive: boolean; +} From b5f95760f40a8c681d9fcd9daa35c35e0c076474 Mon Sep 17 00:00:00 2001 From: "Wei S." <5291640+wayneshn@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:19:29 +0100 Subject: [PATCH 2/2] schema generation files (#326) * Retention policy schema/types * schema generate --- .../migrations/0024_careful_black_panther.sql | 51 + .../migrations/meta/0024_snapshot.json | 1551 +++++++++++++++++ .../database/migrations/meta/_journal.json | 353 ++-- 3 files changed, 1782 insertions(+), 173 deletions(-) create mode 100644 packages/backend/src/database/migrations/0024_careful_black_panther.sql create mode 100644 packages/backend/src/database/migrations/meta/0024_snapshot.json diff --git a/packages/backend/src/database/migrations/0024_careful_black_panther.sql b/packages/backend/src/database/migrations/0024_careful_black_panther.sql new file mode 100644 index 0000000..5f68f0c --- /dev/null +++ b/packages/backend/src/database/migrations/0024_careful_black_panther.sql @@ -0,0 +1,51 @@ +CREATE TABLE "email_legal_holds" ( + "email_id" uuid NOT NULL, + "legal_hold_id" uuid NOT NULL, + CONSTRAINT "email_legal_holds_email_id_legal_hold_id_pk" PRIMARY KEY("email_id","legal_hold_id") +); +--> statement-breakpoint +CREATE TABLE "email_retention_labels" ( + "email_id" uuid NOT NULL, + "label_id" uuid NOT NULL, + "applied_at" timestamp with time zone DEFAULT now() NOT NULL, + "applied_by_user_id" uuid, + CONSTRAINT "email_retention_labels_email_id_label_id_pk" PRIMARY KEY("email_id","label_id") +); +--> statement-breakpoint +CREATE TABLE "retention_events" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "event_name" varchar(255) NOT NULL, + "event_type" varchar(100) NOT NULL, + "event_timestamp" timestamp with time zone NOT NULL, + "target_criteria" jsonb NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "retention_labels" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "name" varchar(255) NOT NULL, + "retention_period_days" integer NOT NULL, + "description" text, + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "legal_holds" DROP CONSTRAINT "legal_holds_custodian_id_custodians_id_fk"; +--> statement-breakpoint +ALTER TABLE "legal_holds" DROP CONSTRAINT "legal_holds_case_id_ediscovery_cases_id_fk"; +--> statement-breakpoint +ALTER TABLE "legal_holds" ALTER COLUMN "case_id" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "legal_holds" ADD COLUMN "name" varchar(255) NOT NULL;--> statement-breakpoint +ALTER TABLE "legal_holds" ADD COLUMN "is_active" boolean DEFAULT true NOT NULL;--> statement-breakpoint +ALTER TABLE "legal_holds" ADD COLUMN "created_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint +ALTER TABLE "legal_holds" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint +ALTER TABLE "email_legal_holds" ADD CONSTRAINT "email_legal_holds_email_id_archived_emails_id_fk" FOREIGN KEY ("email_id") REFERENCES "public"."archived_emails"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "email_legal_holds" ADD CONSTRAINT "email_legal_holds_legal_hold_id_legal_holds_id_fk" FOREIGN KEY ("legal_hold_id") REFERENCES "public"."legal_holds"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "email_retention_labels" ADD CONSTRAINT "email_retention_labels_email_id_archived_emails_id_fk" FOREIGN KEY ("email_id") REFERENCES "public"."archived_emails"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "email_retention_labels" ADD CONSTRAINT "email_retention_labels_label_id_retention_labels_id_fk" FOREIGN KEY ("label_id") REFERENCES "public"."retention_labels"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "email_retention_labels" ADD CONSTRAINT "email_retention_labels_applied_by_user_id_users_id_fk" FOREIGN KEY ("applied_by_user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "legal_holds" ADD CONSTRAINT "legal_holds_case_id_ediscovery_cases_id_fk" FOREIGN KEY ("case_id") REFERENCES "public"."ediscovery_cases"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "legal_holds" DROP COLUMN "custodian_id";--> statement-breakpoint +ALTER TABLE "legal_holds" DROP COLUMN "hold_criteria";--> statement-breakpoint +ALTER TABLE "legal_holds" DROP COLUMN "applied_by_identifier";--> statement-breakpoint +ALTER TABLE "legal_holds" DROP COLUMN "applied_at";--> statement-breakpoint +ALTER TABLE "legal_holds" DROP COLUMN "removed_at"; \ No newline at end of file diff --git a/packages/backend/src/database/migrations/meta/0024_snapshot.json b/packages/backend/src/database/migrations/meta/0024_snapshot.json new file mode 100644 index 0000000..f752132 --- /dev/null +++ b/packages/backend/src/database/migrations/meta/0024_snapshot.json @@ -0,0 +1,1551 @@ +{ + "id": "d713dd13-babf-4b31-9c4c-76a3a5fd731a", + "prevId": "2747b009-4502-4e19-a725-1c5e9807c52b", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.archived_emails": { + "name": "archived_emails", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ingestion_source_id": { + "name": "ingestion_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_email": { + "name": "user_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_id_header": { + "name": "message_id_header", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sender_name": { + "name": "sender_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sender_email": { + "name": "sender_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "recipients": { + "name": "recipients", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "storage_path": { + "name": "storage_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_hash_sha256": { + "name": "storage_hash_sha256", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "is_indexed": { + "name": "is_indexed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "has_attachments": { + "name": "has_attachments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_on_legal_hold": { + "name": "is_on_legal_hold", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "thread_id_idx": { + "name": "thread_id_idx", + "columns": [ + { + "expression": "thread_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "archived_emails_ingestion_source_id_ingestion_sources_id_fk": { + "name": "archived_emails_ingestion_source_id_ingestion_sources_id_fk", + "tableFrom": "archived_emails", + "tableTo": "ingestion_sources", + "columnsFrom": [ + "ingestion_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.attachments": { + "name": "attachments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "content_hash_sha256": { + "name": "content_hash_sha256", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_path": { + "name": "storage_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ingestion_source_id": { + "name": "ingestion_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "source_hash_idx": { + "name": "source_hash_idx", + "columns": [ + { + "expression": "ingestion_source_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "content_hash_sha256", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "attachments_ingestion_source_id_ingestion_sources_id_fk": { + "name": "attachments_ingestion_source_id_ingestion_sources_id_fk", + "tableFrom": "attachments", + "tableTo": "ingestion_sources", + "columnsFrom": [ + "ingestion_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email_attachments": { + "name": "email_attachments", + "schema": "", + "columns": { + "email_id": { + "name": "email_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attachment_id": { + "name": "attachment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "email_attachments_email_id_archived_emails_id_fk": { + "name": "email_attachments_email_id_archived_emails_id_fk", + "tableFrom": "email_attachments", + "tableTo": "archived_emails", + "columnsFrom": [ + "email_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "email_attachments_attachment_id_attachments_id_fk": { + "name": "email_attachments_attachment_id_attachments_id_fk", + "tableFrom": "email_attachments", + "tableTo": "attachments", + "columnsFrom": [ + "attachment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "email_attachments_email_id_attachment_id_pk": { + "name": "email_attachments_email_id_attachment_id_pk", + "columns": [ + "email_id", + "attachment_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_logs": { + "name": "audit_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "previous_hash": { + "name": "previous_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "actor_identifier": { + "name": "actor_identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_ip": { + "name": "actor_ip", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action_type": { + "name": "action_type", + "type": "audit_log_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "target_type": { + "name": "target_type", + "type": "audit_log_target_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "current_hash": { + "name": "current_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ediscovery_cases": { + "name": "ediscovery_cases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "created_by_identifier": { + "name": "created_by_identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "ediscovery_cases_name_unique": { + "name": "ediscovery_cases_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email_legal_holds": { + "name": "email_legal_holds", + "schema": "", + "columns": { + "email_id": { + "name": "email_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "legal_hold_id": { + "name": "legal_hold_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "email_legal_holds_email_id_archived_emails_id_fk": { + "name": "email_legal_holds_email_id_archived_emails_id_fk", + "tableFrom": "email_legal_holds", + "tableTo": "archived_emails", + "columnsFrom": [ + "email_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "email_legal_holds_legal_hold_id_legal_holds_id_fk": { + "name": "email_legal_holds_legal_hold_id_legal_holds_id_fk", + "tableFrom": "email_legal_holds", + "tableTo": "legal_holds", + "columnsFrom": [ + "legal_hold_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "email_legal_holds_email_id_legal_hold_id_pk": { + "name": "email_legal_holds_email_id_legal_hold_id_pk", + "columns": [ + "email_id", + "legal_hold_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.email_retention_labels": { + "name": "email_retention_labels", + "schema": "", + "columns": { + "email_id": { + "name": "email_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "label_id": { + "name": "label_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "applied_at": { + "name": "applied_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "applied_by_user_id": { + "name": "applied_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "email_retention_labels_email_id_archived_emails_id_fk": { + "name": "email_retention_labels_email_id_archived_emails_id_fk", + "tableFrom": "email_retention_labels", + "tableTo": "archived_emails", + "columnsFrom": [ + "email_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "email_retention_labels_label_id_retention_labels_id_fk": { + "name": "email_retention_labels_label_id_retention_labels_id_fk", + "tableFrom": "email_retention_labels", + "tableTo": "retention_labels", + "columnsFrom": [ + "label_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "email_retention_labels_applied_by_user_id_users_id_fk": { + "name": "email_retention_labels_applied_by_user_id_users_id_fk", + "tableFrom": "email_retention_labels", + "tableTo": "users", + "columnsFrom": [ + "applied_by_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "email_retention_labels_email_id_label_id_pk": { + "name": "email_retention_labels_email_id_label_id_pk", + "columns": [ + "email_id", + "label_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.export_jobs": { + "name": "export_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "case_id": { + "name": "case_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "format": { + "name": "format", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "query": { + "name": "query", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by_identifier": { + "name": "created_by_identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "export_jobs_case_id_ediscovery_cases_id_fk": { + "name": "export_jobs_case_id_ediscovery_cases_id_fk", + "tableFrom": "export_jobs", + "tableTo": "ediscovery_cases", + "columnsFrom": [ + "case_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.legal_holds": { + "name": "legal_holds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "case_id": { + "name": "case_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "legal_holds_case_id_ediscovery_cases_id_fk": { + "name": "legal_holds_case_id_ediscovery_cases_id_fk", + "tableFrom": "legal_holds", + "tableTo": "ediscovery_cases", + "columnsFrom": [ + "case_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.retention_events": { + "name": "retention_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_name": { + "name": "event_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "event_timestamp": { + "name": "event_timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "target_criteria": { + "name": "target_criteria", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.retention_labels": { + "name": "retention_labels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "retention_period_days": { + "name": "retention_period_days", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.retention_policies": { + "name": "retention_policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "retention_period_days": { + "name": "retention_period_days", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "action_on_expiry": { + "name": "action_on_expiry", + "type": "retention_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "is_enabled": { + "name": "is_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "conditions": { + "name": "conditions", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "retention_policies_name_unique": { + "name": "retention_policies_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custodians": { + "name": "custodians", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "ingestion_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "custodians_email_unique": { + "name": "custodians_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ingestion_sources": { + "name": "ingestion_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "ingestion_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "credentials": { + "name": "credentials", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "ingestion_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending_auth'" + }, + "last_sync_started_at": { + "name": "last_sync_started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_sync_finished_at": { + "name": "last_sync_finished_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_sync_status_message": { + "name": "last_sync_status_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_state": { + "name": "sync_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "ingestion_sources_user_id_users_id_fk": { + "name": "ingestion_sources_user_id_users_id_fk", + "tableFrom": "ingestion_sources", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "policies": { + "name": "policies", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + }, + "roles_slug_unique": { + "name": "roles_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_roles_user_id_role_id_pk": { + "name": "user_roles_user_id_role_id_pk", + "columns": [ + "user_id", + "role_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'local'" + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.system_settings": { + "name": "system_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.retention_action": { + "name": "retention_action", + "schema": "public", + "values": [ + "delete_permanently", + "notify_admin" + ] + }, + "public.ingestion_provider": { + "name": "ingestion_provider", + "schema": "public", + "values": [ + "google_workspace", + "microsoft_365", + "generic_imap", + "pst_import", + "eml_import", + "mbox_import" + ] + }, + "public.ingestion_status": { + "name": "ingestion_status", + "schema": "public", + "values": [ + "active", + "paused", + "error", + "pending_auth", + "syncing", + "importing", + "auth_success", + "imported" + ] + }, + "public.audit_log_action": { + "name": "audit_log_action", + "schema": "public", + "values": [ + "CREATE", + "READ", + "UPDATE", + "DELETE", + "LOGIN", + "LOGOUT", + "SETUP", + "IMPORT", + "PAUSE", + "SYNC", + "UPLOAD", + "SEARCH", + "DOWNLOAD", + "GENERATE" + ] + }, + "public.audit_log_target_type": { + "name": "audit_log_target_type", + "schema": "public", + "values": [ + "ApiKey", + "ArchivedEmail", + "Dashboard", + "IngestionSource", + "Role", + "SystemSettings", + "User", + "File" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/backend/src/database/migrations/meta/_journal.json b/packages/backend/src/database/migrations/meta/_journal.json index de1ed47..d03485d 100644 --- a/packages/backend/src/database/migrations/meta/_journal.json +++ b/packages/backend/src/database/migrations/meta/_journal.json @@ -1,174 +1,181 @@ { - "version": "7", - "dialect": "postgresql", - "entries": [ - { - "idx": 0, - "version": "7", - "when": 1752225352591, - "tag": "0000_amusing_namora", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1752326803882, - "tag": "0001_odd_night_thrasher", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1752332648392, - "tag": "0002_lethal_quentin_quire", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1752332967084, - "tag": "0003_petite_wrecker", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1752606108876, - "tag": "0004_sleepy_paper_doll", - "breakpoints": true - }, - { - "idx": 5, - "version": "7", - "when": 1752606327253, - "tag": "0005_chunky_sue_storm", - "breakpoints": true - }, - { - "idx": 6, - "version": "7", - "when": 1753112018514, - "tag": "0006_majestic_caretaker", - "breakpoints": true - }, - { - "idx": 7, - "version": "7", - "when": 1753190159356, - "tag": "0007_handy_archangel", - "breakpoints": true - }, - { - "idx": 8, - "version": "7", - "when": 1753370737317, - "tag": "0008_eminent_the_spike", - "breakpoints": true - }, - { - "idx": 9, - "version": "7", - "when": 1754337938241, - "tag": "0009_late_lenny_balinger", - "breakpoints": true - }, - { - "idx": 10, - "version": "7", - "when": 1754420780849, - "tag": "0010_perpetual_lightspeed", - "breakpoints": true - }, - { - "idx": 11, - "version": "7", - "when": 1754422064158, - "tag": "0011_tan_blackheart", - "breakpoints": true - }, - { - "idx": 12, - "version": "7", - "when": 1754476962901, - "tag": "0012_warm_the_stranger", - "breakpoints": true - }, - { - "idx": 13, - "version": "7", - "when": 1754659373517, - "tag": "0013_classy_talkback", - "breakpoints": true - }, - { - "idx": 14, - "version": "7", - "when": 1754831765718, - "tag": "0014_foamy_vapor", - "breakpoints": true - }, - { - "idx": 15, - "version": "7", - "when": 1755443936046, - "tag": "0015_wakeful_norman_osborn", - "breakpoints": true - }, - { - "idx": 16, - "version": "7", - "when": 1755780572342, - "tag": "0016_lonely_mariko_yashida", - "breakpoints": true - }, - { - "idx": 17, - "version": "7", - "when": 1755961566627, - "tag": "0017_tranquil_shooting_star", - "breakpoints": true - }, - { - "idx": 18, - "version": "7", - "when": 1756911118035, - "tag": "0018_flawless_owl", - "breakpoints": true - }, - { - "idx": 19, - "version": "7", - "when": 1756937533843, - "tag": "0019_confused_scream", - "breakpoints": true - }, - { - "idx": 20, - "version": "7", - "when": 1757860242528, - "tag": "0020_panoramic_wolverine", - "breakpoints": true - }, - { - "idx": 21, - "version": "7", - "when": 1759412986134, - "tag": "0021_nosy_veda", - "breakpoints": true - }, - { - "idx": 22, - "version": "7", - "when": 1759701622932, - "tag": "0022_complete_triton", - "breakpoints": true - }, - { - "idx": 23, - "version": "7", - "when": 1760354094610, - "tag": "0023_swift_swordsman", - "breakpoints": true - } - ] -} + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1752225352591, + "tag": "0000_amusing_namora", + "breakpoints": true + }, + { + "idx": 1, + "version": "7", + "when": 1752326803882, + "tag": "0001_odd_night_thrasher", + "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1752332648392, + "tag": "0002_lethal_quentin_quire", + "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1752332967084, + "tag": "0003_petite_wrecker", + "breakpoints": true + }, + { + "idx": 4, + "version": "7", + "when": 1752606108876, + "tag": "0004_sleepy_paper_doll", + "breakpoints": true + }, + { + "idx": 5, + "version": "7", + "when": 1752606327253, + "tag": "0005_chunky_sue_storm", + "breakpoints": true + }, + { + "idx": 6, + "version": "7", + "when": 1753112018514, + "tag": "0006_majestic_caretaker", + "breakpoints": true + }, + { + "idx": 7, + "version": "7", + "when": 1753190159356, + "tag": "0007_handy_archangel", + "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1753370737317, + "tag": "0008_eminent_the_spike", + "breakpoints": true + }, + { + "idx": 9, + "version": "7", + "when": 1754337938241, + "tag": "0009_late_lenny_balinger", + "breakpoints": true + }, + { + "idx": 10, + "version": "7", + "when": 1754420780849, + "tag": "0010_perpetual_lightspeed", + "breakpoints": true + }, + { + "idx": 11, + "version": "7", + "when": 1754422064158, + "tag": "0011_tan_blackheart", + "breakpoints": true + }, + { + "idx": 12, + "version": "7", + "when": 1754476962901, + "tag": "0012_warm_the_stranger", + "breakpoints": true + }, + { + "idx": 13, + "version": "7", + "when": 1754659373517, + "tag": "0013_classy_talkback", + "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1754831765718, + "tag": "0014_foamy_vapor", + "breakpoints": true + }, + { + "idx": 15, + "version": "7", + "when": 1755443936046, + "tag": "0015_wakeful_norman_osborn", + "breakpoints": true + }, + { + "idx": 16, + "version": "7", + "when": 1755780572342, + "tag": "0016_lonely_mariko_yashida", + "breakpoints": true + }, + { + "idx": 17, + "version": "7", + "when": 1755961566627, + "tag": "0017_tranquil_shooting_star", + "breakpoints": true + }, + { + "idx": 18, + "version": "7", + "when": 1756911118035, + "tag": "0018_flawless_owl", + "breakpoints": true + }, + { + "idx": 19, + "version": "7", + "when": 1756937533843, + "tag": "0019_confused_scream", + "breakpoints": true + }, + { + "idx": 20, + "version": "7", + "when": 1757860242528, + "tag": "0020_panoramic_wolverine", + "breakpoints": true + }, + { + "idx": 21, + "version": "7", + "when": 1759412986134, + "tag": "0021_nosy_veda", + "breakpoints": true + }, + { + "idx": 22, + "version": "7", + "when": 1759701622932, + "tag": "0022_complete_triton", + "breakpoints": true + }, + { + "idx": 23, + "version": "7", + "when": 1760354094610, + "tag": "0023_swift_swordsman", + "breakpoints": true + }, + { + "idx": 24, + "version": "7", + "when": 1772842674479, + "tag": "0024_careful_black_panther", + "breakpoints": true + } + ] +} \ No newline at end of file