feat: add client_addresses table for multi-address storage

Adds client_addresses table with cascade deletes, port scoping, primary address flag, and indexes. Updates clientsRelations and portsRelations, adds clientAddressesRelations. Generates migration 0000_narrow_longshot.sql.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-14 12:44:11 -04:00
parent f659073b8f
commit 59dd418542
5 changed files with 8105 additions and 7 deletions

View File

@@ -0,0 +1,956 @@
CREATE TABLE "berth_maintenance_log" (
"id" text PRIMARY KEY NOT NULL,
"berth_id" text NOT NULL,
"port_id" text NOT NULL,
"category" text NOT NULL,
"description" text NOT NULL,
"cost" numeric,
"cost_currency" text DEFAULT 'USD',
"responsible_party" text,
"performed_date" date NOT NULL,
"photo_file_ids" text[],
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "berth_map_data" (
"id" text PRIMARY KEY NOT NULL,
"berth_id" text NOT NULL,
"svg_path" text,
"x" numeric,
"y" numeric,
"transform" text,
"font_size" numeric,
"extra_data" jsonb DEFAULT '{}'::jsonb,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "berth_map_data_berth_id_unique" UNIQUE("berth_id")
);
--> statement-breakpoint
CREATE TABLE "berth_recommendations" (
"id" text PRIMARY KEY NOT NULL,
"interest_id" text NOT NULL,
"berth_id" text NOT NULL,
"match_score" numeric,
"match_reasons" jsonb,
"source" text DEFAULT 'ai' NOT NULL,
"created_by" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "berth_tags" (
"berth_id" text NOT NULL,
"tag_id" text NOT NULL,
CONSTRAINT "berth_tags_berth_id_tag_id_pk" PRIMARY KEY("berth_id","tag_id")
);
--> statement-breakpoint
CREATE TABLE "berth_waiting_list" (
"id" text PRIMARY KEY NOT NULL,
"berth_id" text NOT NULL,
"client_id" text NOT NULL,
"position" integer NOT NULL,
"priority" text DEFAULT 'normal' NOT NULL,
"notify_pref" text DEFAULT 'email',
"notes" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "berths" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"mooring_number" text NOT NULL,
"area" text,
"status" text DEFAULT 'available' NOT NULL,
"length_ft" numeric,
"width_ft" numeric,
"draft_ft" numeric,
"length_m" numeric,
"width_m" numeric,
"draft_m" numeric,
"width_is_minimum" boolean DEFAULT false,
"nominal_boat_size" text,
"nominal_boat_size_m" text,
"water_depth" numeric,
"water_depth_m" numeric,
"water_depth_is_minimum" boolean DEFAULT false,
"side_pontoon" text,
"power_capacity" text,
"voltage" text,
"mooring_type" text,
"cleat_type" text,
"cleat_capacity" text,
"bollard_type" text,
"bollard_capacity" text,
"access" text,
"price" numeric,
"price_currency" text DEFAULT 'USD' NOT NULL,
"bow_facing" text,
"berth_approved" boolean DEFAULT false,
"tenure_type" text DEFAULT 'permanent' NOT NULL,
"tenure_years" integer,
"tenure_start_date" date,
"tenure_end_date" date,
"status_last_changed_by" text,
"status_last_changed_reason" text,
"status_last_modified" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_addresses" (
"id" text PRIMARY KEY NOT NULL,
"client_id" text NOT NULL,
"port_id" text NOT NULL,
"label" text DEFAULT 'Primary' NOT NULL,
"street_address" text,
"city" text,
"state_province" text,
"postal_code" text,
"country" text,
"is_primary" boolean DEFAULT true NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_contacts" (
"id" text PRIMARY KEY NOT NULL,
"client_id" text NOT NULL,
"channel" text NOT NULL,
"value" text NOT NULL,
"label" text,
"is_primary" boolean DEFAULT false NOT NULL,
"notes" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_merge_log" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"surviving_client_id" text NOT NULL,
"merged_client_id" text NOT NULL,
"merged_by" text NOT NULL,
"merge_details" jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_notes" (
"id" text PRIMARY KEY NOT NULL,
"client_id" text NOT NULL,
"author_id" text NOT NULL,
"content" text NOT NULL,
"mentions" text[],
"is_locked" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_relationships" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"client_a_id" text NOT NULL,
"client_b_id" text NOT NULL,
"relationship_type" text NOT NULL,
"description" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "client_tags" (
"client_id" text NOT NULL,
"tag_id" text NOT NULL,
CONSTRAINT "client_tags_client_id_tag_id_pk" PRIMARY KEY("client_id","tag_id")
);
--> statement-breakpoint
CREATE TABLE "clients" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"full_name" text NOT NULL,
"company_name" text,
"nationality" text,
"is_proxy" boolean DEFAULT false NOT NULL,
"proxy_type" text,
"actual_owner_name" text,
"relationship_notes" text,
"yacht_name" text,
"yacht_length_ft" numeric,
"yacht_width_ft" numeric,
"yacht_draft_ft" numeric,
"yacht_length_m" numeric,
"yacht_width_m" numeric,
"yacht_draft_m" numeric,
"berth_size_desired" text,
"preferred_contact_method" text,
"preferred_language" text,
"timezone" text,
"source" text,
"source_details" text,
"archived_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "document_events" (
"id" text PRIMARY KEY NOT NULL,
"document_id" text NOT NULL,
"event_type" text NOT NULL,
"signer_id" text,
"event_data" jsonb DEFAULT '{}'::jsonb,
"signature_hash" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "document_signers" (
"id" text PRIMARY KEY NOT NULL,
"document_id" text NOT NULL,
"signer_name" text NOT NULL,
"signer_email" text NOT NULL,
"signer_role" text NOT NULL,
"signing_order" integer NOT NULL,
"status" text DEFAULT 'pending' NOT NULL,
"signed_at" timestamp with time zone,
"signing_url" text,
"embedded_url" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "document_templates" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"name" text NOT NULL,
"description" text,
"template_type" text NOT NULL,
"body_html" text NOT NULL,
"merge_fields" jsonb DEFAULT '[]'::jsonb NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "documents" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"interest_id" text,
"client_id" text,
"document_type" text NOT NULL,
"title" text NOT NULL,
"status" text DEFAULT 'draft' NOT NULL,
"documenso_id" text,
"file_id" text,
"signed_file_id" text,
"is_manual_upload" boolean DEFAULT false NOT NULL,
"notes" text,
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "files" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"client_id" text,
"filename" text NOT NULL,
"original_name" text NOT NULL,
"mime_type" text,
"size_bytes" text,
"storage_path" text NOT NULL,
"storage_bucket" text DEFAULT 'crm-files' NOT NULL,
"category" text,
"uploaded_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "form_submissions" (
"id" text PRIMARY KEY NOT NULL,
"form_template_id" text NOT NULL,
"client_id" text,
"interest_id" text,
"token" text NOT NULL,
"prefilled_data" jsonb DEFAULT '{}'::jsonb,
"submitted_data" jsonb,
"status" text DEFAULT 'pending' NOT NULL,
"expires_at" timestamp with time zone,
"submitted_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "form_submissions_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "form_templates" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"name" text NOT NULL,
"description" text,
"fields" jsonb NOT NULL,
"branding" jsonb DEFAULT '{}'::jsonb,
"is_active" boolean DEFAULT true NOT NULL,
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "email_accounts" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"port_id" text NOT NULL,
"provider" text NOT NULL,
"email_address" text NOT NULL,
"smtp_host" text NOT NULL,
"smtp_port" integer NOT NULL,
"imap_host" text NOT NULL,
"imap_port" integer NOT NULL,
"credentials_enc" text NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"last_sync_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "email_messages" (
"id" text PRIMARY KEY NOT NULL,
"thread_id" text NOT NULL,
"message_id_header" text,
"from_address" text NOT NULL,
"to_addresses" text[] NOT NULL,
"cc_addresses" text[],
"subject" text,
"body_text" text,
"body_html" text,
"direction" text NOT NULL,
"sent_at" timestamp with time zone NOT NULL,
"attachment_file_ids" text[],
"raw_file_id" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "email_threads" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"client_id" text,
"subject" text,
"last_message_at" timestamp with time zone,
"message_count" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "expenses" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"establishment_name" text,
"amount" numeric NOT NULL,
"currency" text DEFAULT 'USD' NOT NULL,
"amount_usd" numeric,
"exchange_rate" numeric,
"payment_method" text,
"category" text,
"payer" text,
"expense_date" timestamp with time zone NOT NULL,
"description" text,
"receipt_file_ids" text[],
"payment_status" text DEFAULT 'unpaid',
"payment_date" date,
"payment_reference" text,
"payment_notes" text,
"created_by" text NOT NULL,
"archived_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "invoice_expenses" (
"invoice_id" text NOT NULL,
"expense_id" text NOT NULL,
CONSTRAINT "invoice_expenses_invoice_id_expense_id_pk" PRIMARY KEY("invoice_id","expense_id")
);
--> statement-breakpoint
CREATE TABLE "invoice_line_items" (
"id" text PRIMARY KEY NOT NULL,
"invoice_id" text NOT NULL,
"description" text NOT NULL,
"quantity" numeric DEFAULT '1' NOT NULL,
"unit_price" numeric NOT NULL,
"total" numeric NOT NULL,
"sort_order" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "invoices" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"invoice_number" text NOT NULL,
"client_name" text NOT NULL,
"billing_email" text,
"billing_address" text,
"due_date" date NOT NULL,
"payment_terms" text DEFAULT 'net30' NOT NULL,
"currency" text DEFAULT 'USD' NOT NULL,
"subtotal" numeric NOT NULL,
"discount_pct" numeric DEFAULT '0',
"discount_amount" numeric DEFAULT '0',
"fee_pct" numeric DEFAULT '0',
"fee_amount" numeric DEFAULT '0',
"total" numeric NOT NULL,
"status" text DEFAULT 'draft' NOT NULL,
"payment_status" text DEFAULT 'unpaid',
"payment_date" date,
"payment_method" text,
"payment_reference" text,
"pdf_file_id" text,
"notes" text,
"created_by" text NOT NULL,
"archived_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "ports" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"slug" text NOT NULL,
"logo_url" text,
"primary_color" text,
"default_currency" text DEFAULT 'USD' NOT NULL,
"timezone" text DEFAULT 'America/Anguilla' NOT NULL,
"settings" jsonb DEFAULT '{}'::jsonb NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "account" (
"id" text PRIMARY KEY NOT NULL,
"account_id" text NOT NULL,
"provider_id" text NOT NULL,
"user_id" text NOT NULL,
"access_token" text,
"refresh_token" text,
"id_token" text,
"access_token_expires_at" timestamp with time zone,
"refresh_token_expires_at" timestamp with time zone,
"scope" text,
"password" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "port_role_overrides" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"role_id" text NOT NULL,
"permission_overrides" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "roles" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"description" text,
"permissions" jsonb DEFAULT '{}'::jsonb NOT NULL,
"is_global" boolean DEFAULT true NOT NULL,
"is_system" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "session" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"token" text NOT NULL,
"expires_at" timestamp with time zone NOT NULL,
"ip_address" text,
"user_agent" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "session_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "user" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"email" text NOT NULL,
"email_verified" boolean DEFAULT false NOT NULL,
"image" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "user_email_unique" UNIQUE("email")
);
--> statement-breakpoint
CREATE TABLE "user_port_roles" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"port_id" text NOT NULL,
"role_id" text NOT NULL,
"assigned_by" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "user_profiles" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"display_name" text NOT NULL,
"avatar_url" text,
"phone" text,
"is_super_admin" boolean DEFAULT false NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"last_login_at" timestamp with time zone,
"preferences" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "user_profiles_user_id_unique" UNIQUE("user_id")
);
--> statement-breakpoint
CREATE TABLE "verification" (
"id" text PRIMARY KEY NOT NULL,
"identifier" text NOT NULL,
"value" text NOT NULL,
"expires_at" timestamp with time zone NOT NULL,
"created_at" timestamp with time zone,
"updated_at" timestamp with time zone
);
--> statement-breakpoint
CREATE TABLE "interest_notes" (
"id" text PRIMARY KEY NOT NULL,
"interest_id" text NOT NULL,
"author_id" text NOT NULL,
"content" text NOT NULL,
"mentions" text[],
"is_locked" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "interest_tags" (
"interest_id" text NOT NULL,
"tag_id" text NOT NULL,
CONSTRAINT "interest_tags_interest_id_tag_id_pk" PRIMARY KEY("interest_id","tag_id")
);
--> statement-breakpoint
CREATE TABLE "interests" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"client_id" text NOT NULL,
"berth_id" text,
"pipeline_stage" text DEFAULT 'open' NOT NULL,
"lead_category" text,
"source" text,
"eoi_status" text,
"documenso_id" text,
"contract_status" text,
"deposit_status" text,
"reservation_status" text,
"date_first_contact" timestamp with time zone,
"date_last_contact" timestamp with time zone,
"date_eoi_sent" timestamp with time zone,
"date_eoi_signed" timestamp with time zone,
"date_contract_sent" timestamp with time zone,
"date_contract_signed" timestamp with time zone,
"date_deposit_received" timestamp with time zone,
"reminder_enabled" boolean DEFAULT false NOT NULL,
"reminder_days" integer,
"reminder_last_fired" timestamp with time zone,
"notes" text,
"archived_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "generated_reports" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"scheduled_report_id" text,
"report_type" text NOT NULL,
"name" text NOT NULL,
"status" text DEFAULT 'queued' NOT NULL,
"parameters" jsonb DEFAULT '{}'::jsonb,
"file_id" text,
"error_message" text,
"requested_by" text NOT NULL,
"started_at" timestamp with time zone,
"completed_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "google_calendar_cache" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"event_id" text NOT NULL,
"title" text NOT NULL,
"start_at" timestamp with time zone NOT NULL,
"end_at" timestamp with time zone,
"location" text,
"description" text,
"is_crm_pushed" boolean DEFAULT false NOT NULL,
"reminder_id" text,
"fetched_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "google_calendar_tokens" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"access_token" text NOT NULL,
"refresh_token" text NOT NULL,
"token_expiry" timestamp with time zone NOT NULL,
"calendar_id" text DEFAULT 'primary' NOT NULL,
"connected_at" timestamp with time zone DEFAULT now() NOT NULL,
"last_sync_at" timestamp with time zone,
"sync_enabled" boolean DEFAULT true NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "google_calendar_tokens_user_id_unique" UNIQUE("user_id")
);
--> statement-breakpoint
CREATE TABLE "notifications" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"user_id" text NOT NULL,
"type" text NOT NULL,
"title" text NOT NULL,
"description" text,
"link" text,
"entity_type" text,
"entity_id" text,
"is_read" boolean DEFAULT false NOT NULL,
"email_sent" boolean DEFAULT false NOT NULL,
"metadata" jsonb DEFAULT '{}'::jsonb,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "reminders" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"title" text NOT NULL,
"note" text,
"due_at" timestamp with time zone NOT NULL,
"priority" text DEFAULT 'medium' NOT NULL,
"status" text DEFAULT 'pending' NOT NULL,
"assigned_to" text,
"created_by" text NOT NULL,
"client_id" text,
"interest_id" text,
"berth_id" text,
"auto_generated" boolean DEFAULT false NOT NULL,
"google_calendar_event_id" text,
"google_calendar_synced" boolean DEFAULT false NOT NULL,
"snoozed_until" timestamp with time zone,
"completed_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "report_recipients" (
"id" text PRIMARY KEY NOT NULL,
"report_id" text NOT NULL,
"email" text NOT NULL,
"user_id" text
);
--> statement-breakpoint
CREATE TABLE "scheduled_reports" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"name" text NOT NULL,
"report_type" text NOT NULL,
"schedule" text NOT NULL,
"last_run_at" timestamp with time zone,
"next_run_at" timestamp with time zone,
"is_active" boolean DEFAULT true NOT NULL,
"config" jsonb DEFAULT '{}'::jsonb,
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "audit_logs" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text,
"user_id" text,
"action" text NOT NULL,
"entity_type" text NOT NULL,
"entity_id" text,
"field_changed" text,
"old_value" jsonb,
"new_value" jsonb,
"ip_address" text,
"user_agent" text,
"reverted_by" text,
"reverted_at" timestamp with time zone,
"revert_of" text,
"metadata" jsonb DEFAULT '{}'::jsonb,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "currency_rates" (
"id" text PRIMARY KEY NOT NULL,
"base_currency" text NOT NULL,
"target_currency" text NOT NULL,
"rate" numeric NOT NULL,
"source" text DEFAULT 'frankfurter' NOT NULL,
"fetched_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "custom_field_definitions" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"entity_type" text NOT NULL,
"field_name" text NOT NULL,
"field_label" text NOT NULL,
"field_type" text NOT NULL,
"select_options" jsonb,
"is_required" boolean DEFAULT false NOT NULL,
"sort_order" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "custom_field_values" (
"id" text PRIMARY KEY NOT NULL,
"field_id" text NOT NULL,
"entity_id" text NOT NULL,
"value" jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "saved_views" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"user_id" text NOT NULL,
"entity_type" text NOT NULL,
"name" text NOT NULL,
"filters" jsonb NOT NULL,
"sort_config" jsonb,
"column_config" jsonb,
"is_shared" boolean DEFAULT false NOT NULL,
"is_default" boolean DEFAULT false NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "scratchpad_notes" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"content" text NOT NULL,
"linked_client_id" text,
"linked_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "system_settings" (
"key" text NOT NULL,
"value" jsonb NOT NULL,
"port_id" text,
"updated_by" text,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "tags" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"name" text NOT NULL,
"color" text DEFAULT '#6B7280' NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "user_notification_preferences" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"port_id" text NOT NULL,
"notification_type" text NOT NULL,
"in_app" boolean DEFAULT true NOT NULL,
"email" boolean DEFAULT true NOT NULL
);
--> statement-breakpoint
CREATE TABLE "webhook_deliveries" (
"id" text PRIMARY KEY NOT NULL,
"webhook_id" text NOT NULL,
"event_type" text NOT NULL,
"payload" jsonb NOT NULL,
"response_status" integer,
"response_body" text,
"attempt" integer DEFAULT 1 NOT NULL,
"status" text DEFAULT 'pending' NOT NULL,
"delivered_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "webhooks" (
"id" text PRIMARY KEY NOT NULL,
"port_id" text NOT NULL,
"name" text NOT NULL,
"url" text NOT NULL,
"secret" text,
"events" text[] NOT NULL,
"is_active" boolean DEFAULT true NOT NULL,
"created_by" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "berth_maintenance_log" ADD CONSTRAINT "berth_maintenance_log_berth_id_berths_id_fk" FOREIGN KEY ("berth_id") REFERENCES "public"."berths"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_maintenance_log" ADD CONSTRAINT "berth_maintenance_log_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_map_data" ADD CONSTRAINT "berth_map_data_berth_id_berths_id_fk" FOREIGN KEY ("berth_id") REFERENCES "public"."berths"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_recommendations" ADD CONSTRAINT "berth_recommendations_berth_id_berths_id_fk" FOREIGN KEY ("berth_id") REFERENCES "public"."berths"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_tags" ADD CONSTRAINT "berth_tags_berth_id_berths_id_fk" FOREIGN KEY ("berth_id") REFERENCES "public"."berths"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_waiting_list" ADD CONSTRAINT "berth_waiting_list_berth_id_berths_id_fk" FOREIGN KEY ("berth_id") REFERENCES "public"."berths"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berth_waiting_list" ADD CONSTRAINT "berth_waiting_list_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "berths" ADD CONSTRAINT "berths_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_addresses" ADD CONSTRAINT "client_addresses_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_addresses" ADD CONSTRAINT "client_addresses_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_contacts" ADD CONSTRAINT "client_contacts_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_merge_log" ADD CONSTRAINT "client_merge_log_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_merge_log" ADD CONSTRAINT "client_merge_log_surviving_client_id_clients_id_fk" FOREIGN KEY ("surviving_client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_notes" ADD CONSTRAINT "client_notes_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_relationships" ADD CONSTRAINT "client_relationships_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_relationships" ADD CONSTRAINT "client_relationships_client_a_id_clients_id_fk" FOREIGN KEY ("client_a_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_relationships" ADD CONSTRAINT "client_relationships_client_b_id_clients_id_fk" FOREIGN KEY ("client_b_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "client_tags" ADD CONSTRAINT "client_tags_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "clients" ADD CONSTRAINT "clients_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "document_events" ADD CONSTRAINT "document_events_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "document_events" ADD CONSTRAINT "document_events_signer_id_document_signers_id_fk" FOREIGN KEY ("signer_id") REFERENCES "public"."document_signers"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "document_signers" ADD CONSTRAINT "document_signers_document_id_documents_id_fk" FOREIGN KEY ("document_id") REFERENCES "public"."documents"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "document_templates" ADD CONSTRAINT "document_templates_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "documents" ADD CONSTRAINT "documents_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "documents" ADD CONSTRAINT "documents_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "documents" ADD CONSTRAINT "documents_file_id_files_id_fk" FOREIGN KEY ("file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "documents" ADD CONSTRAINT "documents_signed_file_id_files_id_fk" FOREIGN KEY ("signed_file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "files" ADD CONSTRAINT "files_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "files" ADD CONSTRAINT "files_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "form_submissions" ADD CONSTRAINT "form_submissions_form_template_id_form_templates_id_fk" FOREIGN KEY ("form_template_id") REFERENCES "public"."form_templates"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "form_submissions" ADD CONSTRAINT "form_submissions_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "form_templates" ADD CONSTRAINT "form_templates_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "email_accounts" ADD CONSTRAINT "email_accounts_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "email_messages" ADD CONSTRAINT "email_messages_thread_id_email_threads_id_fk" FOREIGN KEY ("thread_id") REFERENCES "public"."email_threads"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "email_messages" ADD CONSTRAINT "email_messages_raw_file_id_files_id_fk" FOREIGN KEY ("raw_file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "email_threads" ADD CONSTRAINT "email_threads_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "email_threads" ADD CONSTRAINT "email_threads_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "expenses" ADD CONSTRAINT "expenses_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invoice_expenses" ADD CONSTRAINT "invoice_expenses_invoice_id_invoices_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "public"."invoices"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invoice_expenses" ADD CONSTRAINT "invoice_expenses_expense_id_expenses_id_fk" FOREIGN KEY ("expense_id") REFERENCES "public"."expenses"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invoice_line_items" ADD CONSTRAINT "invoice_line_items_invoice_id_invoices_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "public"."invoices"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invoices" ADD CONSTRAINT "invoices_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "invoices" ADD CONSTRAINT "invoices_pdf_file_id_files_id_fk" FOREIGN KEY ("pdf_file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "port_role_overrides" ADD CONSTRAINT "port_role_overrides_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "port_role_overrides" ADD CONSTRAINT "port_role_overrides_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "public"."roles"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_port_roles" ADD CONSTRAINT "user_port_roles_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_port_roles" ADD CONSTRAINT "user_port_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "public"."roles"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "interest_notes" ADD CONSTRAINT "interest_notes_interest_id_interests_id_fk" FOREIGN KEY ("interest_id") REFERENCES "public"."interests"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "interest_tags" ADD CONSTRAINT "interest_tags_interest_id_interests_id_fk" FOREIGN KEY ("interest_id") REFERENCES "public"."interests"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "interests" ADD CONSTRAINT "interests_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "interests" ADD CONSTRAINT "interests_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "generated_reports" ADD CONSTRAINT "generated_reports_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "generated_reports" ADD CONSTRAINT "generated_reports_scheduled_report_id_scheduled_reports_id_fk" FOREIGN KEY ("scheduled_report_id") REFERENCES "public"."scheduled_reports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "generated_reports" ADD CONSTRAINT "generated_reports_file_id_files_id_fk" FOREIGN KEY ("file_id") REFERENCES "public"."files"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "google_calendar_cache" ADD CONSTRAINT "google_calendar_cache_reminder_id_reminders_id_fk" FOREIGN KEY ("reminder_id") REFERENCES "public"."reminders"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "notifications" ADD CONSTRAINT "notifications_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "reminders" ADD CONSTRAINT "reminders_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "reminders" ADD CONSTRAINT "reminders_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "report_recipients" ADD CONSTRAINT "report_recipients_report_id_scheduled_reports_id_fk" FOREIGN KEY ("report_id") REFERENCES "public"."scheduled_reports"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "scheduled_reports" ADD CONSTRAINT "scheduled_reports_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_revert_of_audit_logs_id_fk" FOREIGN KEY ("revert_of") REFERENCES "public"."audit_logs"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "custom_field_definitions" ADD CONSTRAINT "custom_field_definitions_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "custom_field_values" ADD CONSTRAINT "custom_field_values_field_id_custom_field_definitions_id_fk" FOREIGN KEY ("field_id") REFERENCES "public"."custom_field_definitions"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "saved_views" ADD CONSTRAINT "saved_views_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "scratchpad_notes" ADD CONSTRAINT "scratchpad_notes_linked_client_id_clients_id_fk" FOREIGN KEY ("linked_client_id") REFERENCES "public"."clients"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "system_settings" ADD CONSTRAINT "system_settings_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tags" ADD CONSTRAINT "tags_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_notification_preferences" ADD CONSTRAINT "user_notification_preferences_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "webhook_deliveries" ADD CONSTRAINT "webhook_deliveries_webhook_id_webhooks_id_fk" FOREIGN KEY ("webhook_id") REFERENCES "public"."webhooks"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "webhooks" ADD CONSTRAINT "webhooks_port_id_ports_id_fk" FOREIGN KEY ("port_id") REFERENCES "public"."ports"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "idx_bml_berth" ON "berth_maintenance_log" USING btree ("berth_id");--> statement-breakpoint
CREATE INDEX "idx_bml_port" ON "berth_maintenance_log" USING btree ("port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "berth_map_data_berth_id_idx" ON "berth_map_data" USING btree ("berth_id");--> statement-breakpoint
CREATE UNIQUE INDEX "berth_rec_interest_berth_idx" ON "berth_recommendations" USING btree ("interest_id","berth_id");--> statement-breakpoint
CREATE INDEX "idx_br_interest" ON "berth_recommendations" USING btree ("interest_id");--> statement-breakpoint
CREATE UNIQUE INDEX "berth_waiting_list_berth_client_idx" ON "berth_waiting_list" USING btree ("berth_id","client_id");--> statement-breakpoint
CREATE INDEX "idx_bwl_berth" ON "berth_waiting_list" USING btree ("berth_id","position");--> statement-breakpoint
CREATE INDEX "idx_berths_port" ON "berths" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_berths_status" ON "berths" USING btree ("port_id","status");--> statement-breakpoint
CREATE INDEX "idx_berths_area" ON "berths" USING btree ("port_id","area");--> statement-breakpoint
CREATE UNIQUE INDEX "idx_berths_mooring" ON "berths" USING btree ("port_id","mooring_number");--> statement-breakpoint
CREATE INDEX "idx_ca_client" ON "client_addresses" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_ca_port" ON "client_addresses" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_cc_client" ON "client_contacts" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_cc_email" ON "client_contacts" USING btree ("channel","value") WHERE "client_contacts"."channel" = 'email';--> statement-breakpoint
CREATE INDEX "idx_cc_phone" ON "client_contacts" USING btree ("channel","value") WHERE "client_contacts"."channel" = 'phone';--> statement-breakpoint
CREATE INDEX "idx_cml_port" ON "client_merge_log" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_cn_client" ON "client_notes" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_cr_port" ON "client_relationships" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_clients_port" ON "clients" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_clients_name" ON "clients" USING btree ("port_id","full_name");--> statement-breakpoint
CREATE INDEX "idx_clients_archived" ON "clients" USING btree ("port_id","archived_at");--> statement-breakpoint
CREATE INDEX "idx_de_doc" ON "document_events" USING btree ("document_id");--> statement-breakpoint
CREATE UNIQUE INDEX "idx_de_dedup" ON "document_events" USING btree ("document_id","signature_hash") WHERE "document_events"."signature_hash" IS NOT NULL;--> statement-breakpoint
CREATE INDEX "idx_ds_doc" ON "document_signers" USING btree ("document_id");--> statement-breakpoint
CREATE INDEX "idx_dt_port" ON "document_templates" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_dt_type" ON "document_templates" USING btree ("port_id","template_type");--> statement-breakpoint
CREATE INDEX "idx_docs_port" ON "documents" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_docs_interest" ON "documents" USING btree ("interest_id");--> statement-breakpoint
CREATE INDEX "idx_docs_client" ON "documents" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_docs_type" ON "documents" USING btree ("port_id","document_type");--> statement-breakpoint
CREATE INDEX "idx_files_port" ON "files" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_files_client" ON "files" USING btree ("client_id");--> statement-breakpoint
CREATE UNIQUE INDEX "idx_fs_token" ON "form_submissions" USING btree ("token");--> statement-breakpoint
CREATE INDEX "idx_ft_port" ON "form_templates" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_ea_user" ON "email_accounts" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "idx_ea_port" ON "email_accounts" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_em_thread" ON "email_messages" USING btree ("thread_id");--> statement-breakpoint
CREATE UNIQUE INDEX "idx_em_message_id" ON "email_messages" USING btree ("message_id_header") WHERE "email_messages"."message_id_header" IS NOT NULL;--> statement-breakpoint
CREATE INDEX "idx_et_client" ON "email_threads" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_et_port" ON "email_threads" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_expenses_port" ON "expenses" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_expenses_date" ON "expenses" USING btree ("port_id","expense_date");--> statement-breakpoint
CREATE INDEX "idx_expenses_category" ON "expenses" USING btree ("port_id","category");--> statement-breakpoint
CREATE INDEX "idx_ili_invoice" ON "invoice_line_items" USING btree ("invoice_id");--> statement-breakpoint
CREATE UNIQUE INDEX "idx_invoices_number" ON "invoices" USING btree ("port_id","invoice_number");--> statement-breakpoint
CREATE INDEX "idx_invoices_port" ON "invoices" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_invoices_status" ON "invoices" USING btree ("port_id","status");--> statement-breakpoint
CREATE UNIQUE INDEX "ports_slug_idx" ON "ports" USING btree ("slug");--> statement-breakpoint
CREATE UNIQUE INDEX "port_role_overrides_port_role_idx" ON "port_role_overrides" USING btree ("port_id","role_id");--> statement-breakpoint
CREATE INDEX "port_role_overrides_port_idx" ON "port_role_overrides" USING btree ("port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "sessions_token_idx" ON "session" USING btree ("token");--> statement-breakpoint
CREATE INDEX "sessions_user_id_idx" ON "session" USING btree ("user_id");--> statement-breakpoint
CREATE UNIQUE INDEX "user_port_roles_user_port_role_idx" ON "user_port_roles" USING btree ("user_id","port_id","role_id");--> statement-breakpoint
CREATE INDEX "idx_upr_user" ON "user_port_roles" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "idx_upr_port" ON "user_port_roles" USING btree ("port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "user_profiles_user_id_idx" ON "user_profiles" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "idx_in_interest" ON "interest_notes" USING btree ("interest_id");--> statement-breakpoint
CREATE INDEX "idx_interests_port" ON "interests" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_interests_client" ON "interests" USING btree ("client_id");--> statement-breakpoint
CREATE INDEX "idx_interests_berth" ON "interests" USING btree ("berth_id");--> statement-breakpoint
CREATE INDEX "idx_interests_stage" ON "interests" USING btree ("port_id","pipeline_stage");--> statement-breakpoint
CREATE INDEX "idx_interests_archived" ON "interests" USING btree ("port_id","archived_at");--> statement-breakpoint
CREATE INDEX "idx_gr_port_created" ON "generated_reports" USING btree ("port_id","created_at");--> statement-breakpoint
CREATE INDEX "idx_gr_port_status" ON "generated_reports" USING btree ("port_id","status");--> statement-breakpoint
CREATE INDEX "idx_gr_scheduled" ON "generated_reports" USING btree ("scheduled_report_id") WHERE "generated_reports"."scheduled_report_id" IS NOT NULL;--> statement-breakpoint
CREATE UNIQUE INDEX "gcal_cache_user_event_idx" ON "google_calendar_cache" USING btree ("user_id","event_id");--> statement-breakpoint
CREATE INDEX "idx_gcal_cache_user" ON "google_calendar_cache" USING btree ("user_id","start_at");--> statement-breakpoint
CREATE UNIQUE INDEX "gcal_tokens_user_id_idx" ON "google_calendar_tokens" USING btree ("user_id");--> statement-breakpoint
CREATE INDEX "idx_notif_user" ON "notifications" USING btree ("user_id","is_read");--> statement-breakpoint
CREATE INDEX "idx_notif_port" ON "notifications" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_notifications_user_type" ON "notifications" USING btree ("user_id","type","created_at");--> statement-breakpoint
CREATE INDEX "idx_reminders_port" ON "reminders" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_reminders_assigned" ON "reminders" USING btree ("assigned_to","status");--> statement-breakpoint
CREATE INDEX "idx_reminders_due" ON "reminders" USING btree ("port_id","due_at") WHERE "reminders"."status" IN ('pending', 'snoozed');--> statement-breakpoint
CREATE UNIQUE INDEX "report_recipients_report_email_idx" ON "report_recipients" USING btree ("report_id","email");--> statement-breakpoint
CREATE INDEX "idx_rr_report" ON "report_recipients" USING btree ("report_id");--> statement-breakpoint
CREATE INDEX "idx_sr_port" ON "scheduled_reports" USING btree ("port_id");--> statement-breakpoint
CREATE INDEX "idx_al_port" ON "audit_logs" USING btree ("port_id","created_at");--> statement-breakpoint
CREATE INDEX "idx_al_entity" ON "audit_logs" USING btree ("entity_type","entity_id");--> statement-breakpoint
CREATE INDEX "idx_al_user" ON "audit_logs" USING btree ("user_id","created_at");--> statement-breakpoint
CREATE INDEX "idx_al_created" ON "audit_logs" USING btree ("created_at");--> statement-breakpoint
CREATE UNIQUE INDEX "currency_rates_base_target_idx" ON "currency_rates" USING btree ("base_currency","target_currency");--> statement-breakpoint
CREATE UNIQUE INDEX "cfd_port_entity_name_idx" ON "custom_field_definitions" USING btree ("port_id","entity_type","field_name");--> statement-breakpoint
CREATE INDEX "idx_cfd_port" ON "custom_field_definitions" USING btree ("port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "cfv_field_entity_idx" ON "custom_field_values" USING btree ("field_id","entity_id");--> statement-breakpoint
CREATE INDEX "idx_cfv_entity" ON "custom_field_values" USING btree ("entity_id");--> statement-breakpoint
CREATE INDEX "idx_sv_user" ON "saved_views" USING btree ("user_id","entity_type");--> statement-breakpoint
CREATE INDEX "idx_sp_user" ON "scratchpad_notes" USING btree ("user_id");--> statement-breakpoint
CREATE UNIQUE INDEX "system_settings_key_port_idx" ON "system_settings" USING btree ("key","port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "tags_port_name_idx" ON "tags" USING btree ("port_id","name");--> statement-breakpoint
CREATE INDEX "idx_tags_port" ON "tags" USING btree ("port_id");--> statement-breakpoint
CREATE UNIQUE INDEX "unp_user_port_type_idx" ON "user_notification_preferences" USING btree ("user_id","port_id","notification_type");--> statement-breakpoint
CREATE INDEX "idx_wd_webhook" ON "webhook_deliveries" USING btree ("webhook_id","created_at");--> statement-breakpoint
CREATE INDEX "idx_webhooks_port" ON "webhooks" USING btree ("port_id");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1776185027494,
"tag": "0000_narrow_longshot",
"breakpoints": true
}
]
}

View File

@@ -14,7 +14,9 @@ import { ports } from './ports';
export const clients = pgTable(
'clients',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
portId: text('port_id')
.notNull()
.references(() => ports.id),
@@ -52,7 +54,9 @@ export const clients = pgTable(
export const clientContacts = pgTable(
'client_contacts',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
clientId: text('client_id')
.notNull()
.references(() => clients.id, { onDelete: 'cascade' }),
@@ -66,15 +70,21 @@ export const clientContacts = pgTable(
},
(table) => [
index('idx_cc_client').on(table.clientId),
index('idx_cc_email').on(table.channel, table.value).where(sql`${table.channel} = 'email'`),
index('idx_cc_phone').on(table.channel, table.value).where(sql`${table.channel} = 'phone'`),
index('idx_cc_email')
.on(table.channel, table.value)
.where(sql`${table.channel} = 'email'`),
index('idx_cc_phone')
.on(table.channel, table.value)
.where(sql`${table.channel} = 'phone'`),
],
);
export const clientRelationships = pgTable(
'client_relationships',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
portId: text('port_id')
.notNull()
.references(() => ports.id),
@@ -94,7 +104,9 @@ export const clientRelationships = pgTable(
export const clientNotes = pgTable(
'client_notes',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
clientId: text('client_id')
.notNull()
.references(() => clients.id, { onDelete: 'cascade' }),
@@ -122,7 +134,9 @@ export const clientTags = pgTable(
export const clientMergeLog = pgTable(
'client_merge_log',
{
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
portId: text('port_id')
.notNull()
.references(() => ports.id),
@@ -137,6 +151,31 @@ export const clientMergeLog = pgTable(
(table) => [index('idx_cml_port').on(table.portId)],
);
export const clientAddresses = pgTable(
'client_addresses',
{
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
clientId: text('client_id')
.notNull()
.references(() => clients.id, { onDelete: 'cascade' }),
portId: text('port_id')
.notNull()
.references(() => ports.id, { onDelete: 'cascade' }),
label: text('label').notNull().default('Primary'),
streetAddress: text('street_address'),
city: text('city'),
stateProvince: text('state_province'),
postalCode: text('postal_code'),
country: text('country'),
isPrimary: boolean('is_primary').notNull().default(true),
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
},
(table) => [index('idx_ca_client').on(table.clientId), index('idx_ca_port').on(table.portId)],
);
export type Client = typeof clients.$inferSelect;
export type NewClient = typeof clients.$inferInsert;
export type ClientContact = typeof clientContacts.$inferSelect;
@@ -147,3 +186,5 @@ export type ClientNote = typeof clientNotes.$inferSelect;
export type NewClientNote = typeof clientNotes.$inferInsert;
export type ClientMergeLog = typeof clientMergeLog.$inferSelect;
export type NewClientMergeLog = typeof clientMergeLog.$inferInsert;
export type ClientAddress = typeof clientAddresses.$inferSelect;
export type NewClientAddress = typeof clientAddresses.$inferInsert;

View File

@@ -14,6 +14,7 @@ import {
clientNotes,
clientTags,
clientMergeLog,
clientAddresses,
} from './clients';
// Interests
@@ -100,6 +101,7 @@ export const portsRelations = relations(ports, ({ many }) => ({
berthMaintenanceLogs: many(berthMaintenanceLog),
clientMergeLogs: many(clientMergeLog),
clientRelationships: many(clientRelationships),
clientAddresses: many(clientAddresses),
}));
// ─── Users ────────────────────────────────────────────────────────────────────
@@ -156,6 +158,7 @@ export const clientsRelations = relations(clients, ({ one, many }) => ({
waitingListEntries: many(berthWaitingList),
scratchpadNotes: many(scratchpadNotes),
formSubmissions: many(formSubmissions),
addresses: many(clientAddresses),
}));
export const clientContactsRelations = relations(clientContacts, ({ one }) => ({
@@ -165,6 +168,17 @@ export const clientContactsRelations = relations(clientContacts, ({ one }) => ({
}),
}));
export const clientAddressesRelations = relations(clientAddresses, ({ one }) => ({
client: one(clients, {
fields: [clientAddresses.clientId],
references: [clients.id],
}),
port: one(ports, {
fields: [clientAddresses.portId],
references: [ports.id],
}),
}));
export const clientRelationshipsRelations = relations(clientRelationships, ({ one }) => ({
port: one(ports, {
fields: [clientRelationships.portId],