diff --git a/drizzle-pg/0021_parched_zombie.sql b/drizzle-pg/0021_parched_zombie.sql new file mode 100644 index 000000000..3ed4b843d --- /dev/null +++ b/drizzle-pg/0021_parched_zombie.sql @@ -0,0 +1,17 @@ +CREATE TABLE "brand_lookup_runs" ( + "id" text PRIMARY KEY NOT NULL, + "project_id" text NOT NULL, + "query" text NOT NULL, + "resolved_target" text NOT NULL, + "scope" text, + "competitors" text DEFAULT '[]' NOT NULL, + "total_mentions" integer, + "total_ai_search_volume" integer, + "share_of_voice_percent" integer, + "payload" text NOT NULL, + "fetched_at" text NOT NULL, + "created_at" text DEFAULT to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') NOT NULL +); +--> statement-breakpoint +ALTER TABLE "brand_lookup_runs" ADD CONSTRAINT "brand_lookup_runs_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "brand_lookup_runs_project_created_idx" ON "brand_lookup_runs" USING btree ("project_id","created_at"); \ No newline at end of file diff --git a/drizzle-pg/meta/0021_snapshot.json b/drizzle-pg/meta/0021_snapshot.json new file mode 100644 index 000000000..fb829bfc9 --- /dev/null +++ b/drizzle-pg/meta/0021_snapshot.json @@ -0,0 +1,4216 @@ +{ + "id": "0c545a6b-9e2f-418a-9b55-7c72aeca6225", + "prevId": "ac4619e0-4754-4c86-9bdb-417b10629526", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.backlink_snapshots": { + "name": "backlink_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rank": { + "name": "rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "backlinks": { + "name": "backlinks", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "referring_domains": { + "name": "referring_domains", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "broken_backlinks": { + "name": "broken_backlinks", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "new_backlinks": { + "name": "new_backlinks", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "lost_backlinks": { + "name": "lost_backlinks", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "new_referring_domains": { + "name": "new_referring_domains", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "lost_referring_domains": { + "name": "lost_referring_domains", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "captured_at": { + "name": "captured_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "backlink_snapshots_project_captured_idx": { + "name": "backlink_snapshots_project_captured_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "captured_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "backlink_snapshots_project_id_projects_id_fk": { + "name": "backlink_snapshots_project_id_projects_id_fk", + "tableFrom": "backlink_snapshots", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.keyword_metrics": { + "name": "keyword_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en'" + }, + "search_volume": { + "name": "search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpc": { + "name": "cpc", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "competition": { + "name": "competition", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "keyword_difficulty": { + "name": "keyword_difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "intent": { + "name": "intent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "monthly_searches": { + "name": "monthly_searches", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fetched_at": { + "name": "fetched_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "keyword_metrics_unique_project_keyword_location_language": { + "name": "keyword_metrics_unique_project_keyword_location_language", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "keyword", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "language_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keyword_metrics_lookup_idx": { + "name": "keyword_metrics_lookup_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "keyword", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "language_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "fetched_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "keyword_metrics_project_id_projects_id_fk": { + "name": "keyword_metrics_project_id_projects_id_fk", + "tableFrom": "keyword_metrics", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_activation_state": { + "name": "organization_activation_state", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "first_mcp_authorized_at": { + "name": "first_mcp_authorized_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "first_mcp_tool_call_at": { + "name": "first_mcp_tool_call_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_activation_state_organization_id_organization_id_fk": { + "name": "organization_activation_state_organization_id_organization_id_fk", + "tableFrom": "organization_activation_state", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_activation_state": { + "name": "project_activation_state", + "schema": "", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "competitor_step_clicked_at": { + "name": "competitor_step_clicked_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_card_dismissed_at": { + "name": "mcp_card_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ga4_card_dismissed_at": { + "name": "ga4_card_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": {}, + "foreignKeys": { + "project_activation_state_project_id_projects_id_fk": { + "name": "project_activation_state_project_id_projects_id_fk", + "tableFrom": "project_activation_state", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "projects_one_default_per_organization_idx": { + "name": "projects_one_default_per_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"projects\".\"name\" = 'Default' AND \"projects\".\"domain\" IS NULL AND \"projects\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "projects_organization_id_idx": { + "name": "projects_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "projects_organization_id_organization_id_fk": { + "name": "projects_organization_id_organization_id_fk", + "tableFrom": "projects", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rank_check_runs": { + "name": "rank_check_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "keywords_total": { + "name": "keywords_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "keywords_checked": { + "name": "keywords_checked", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_subset_run": { + "name": "is_subset_run", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "rank_check_runs_config_idx": { + "name": "rank_check_runs_config_idx", + "columns": [ + { + "expression": "config_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rank_check_runs_project_idx": { + "name": "rank_check_runs_project_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rank_check_runs_one_active_per_config_idx": { + "name": "rank_check_runs_one_active_per_config_idx", + "columns": [ + { + "expression": "config_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"rank_check_runs\".\"status\" IN ('pending', 'running')", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "rank_check_runs_config_id_rank_tracking_configs_id_fk": { + "name": "rank_check_runs_config_id_rank_tracking_configs_id_fk", + "tableFrom": "rank_check_runs", + "tableTo": "rank_tracking_configs", + "columnsFrom": [ + "config_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "rank_check_runs_project_id_projects_id_fk": { + "name": "rank_check_runs_project_id_projects_id_fk", + "tableFrom": "rank_check_runs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rank_snapshots": { + "name": "rank_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tracking_keyword_id": { + "name": "tracking_keyword_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "serp_features": { + "name": "serp_features", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "checked_at": { + "name": "checked_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "rank_snapshots_keyword_device_idx": { + "name": "rank_snapshots_keyword_device_idx", + "columns": [ + { + "expression": "tracking_keyword_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "device", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "checked_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rank_snapshots_run_keyword_device_idx": { + "name": "rank_snapshots_run_keyword_device_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tracking_keyword_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "device", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "rank_snapshots_run_id_rank_check_runs_id_fk": { + "name": "rank_snapshots_run_id_rank_check_runs_id_fk", + "tableFrom": "rank_snapshots", + "tableTo": "rank_check_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rank_tracking_configs": { + "name": "rank_tracking_configs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en'" + }, + "devices": { + "name": "devices", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'both'" + }, + "serp_depth": { + "name": "serp_depth", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "schedule_interval": { + "name": "schedule_interval", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'weekly'" + }, + "location_name": { + "name": "location_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_checked_at": { + "name": "last_checked_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_check_at": { + "name": "next_check_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_skip_reason": { + "name": "last_skip_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "rank_tracking_configs_project_active_created_idx": { + "name": "rank_tracking_configs_project_active_created_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "rank_tracking_configs_national_idx": { + "name": "rank_tracking_configs_national_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"rank_tracking_configs\".\"location_name\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "rank_tracking_configs_local_idx": { + "name": "rank_tracking_configs_local_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"rank_tracking_configs\".\"location_name\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "rank_tracking_configs_project_id_projects_id_fk": { + "name": "rank_tracking_configs_project_id_projects_id_fk", + "tableFrom": "rank_tracking_configs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rank_tracking_keywords": { + "name": "rank_tracking_keywords", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "search_volume": { + "name": "search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "keyword_difficulty": { + "name": "keyword_difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cpc": { + "name": "cpc", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "metrics_fetched_at": { + "name": "metrics_fetched_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "rank_tracking_keywords_config_keyword_idx": { + "name": "rank_tracking_keywords_config_keyword_idx", + "columns": [ + { + "expression": "config_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "keyword", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "rank_tracking_keywords_config_id_rank_tracking_configs_id_fk": { + "name": "rank_tracking_keywords_config_id_rank_tracking_configs_id_fk", + "tableFrom": "rank_tracking_keywords", + "tableTo": "rank_tracking_configs", + "columnsFrom": [ + "config_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.saved_keyword_tag_assignments": { + "name": "saved_keyword_tag_assignments", + "schema": "", + "columns": { + "saved_keyword_id": { + "name": "saved_keyword_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "saved_keyword_tag_assignments_unique_idx": { + "name": "saved_keyword_tag_assignments_unique_idx", + "columns": [ + { + "expression": "saved_keyword_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "saved_keyword_tag_assignments_tag_idx": { + "name": "saved_keyword_tag_assignments_tag_idx", + "columns": [ + { + "expression": "tag_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "saved_keyword_tag_assignments_saved_keyword_id_saved_keywords_id_fk": { + "name": "saved_keyword_tag_assignments_saved_keyword_id_saved_keywords_id_fk", + "tableFrom": "saved_keyword_tag_assignments", + "tableTo": "saved_keywords", + "columnsFrom": [ + "saved_keyword_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "saved_keyword_tag_assignments_tag_id_saved_keyword_tags_id_fk": { + "name": "saved_keyword_tag_assignments_tag_id_saved_keyword_tags_id_fk", + "tableFrom": "saved_keyword_tag_assignments", + "tableTo": "saved_keyword_tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.saved_keyword_tags": { + "name": "saved_keyword_tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "normalized_name": { + "name": "normalized_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "saved_keyword_tags_project_normalized_name_idx": { + "name": "saved_keyword_tags_project_normalized_name_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "normalized_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "saved_keyword_tags_project_name_idx": { + "name": "saved_keyword_tags_project_name_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "saved_keyword_tags_project_id_projects_id_fk": { + "name": "saved_keyword_tags_project_id_projects_id_fk", + "tableFrom": "saved_keyword_tags", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.saved_keywords": { + "name": "saved_keywords", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "saved_keywords_unique_project_keyword_location_language": { + "name": "saved_keywords_unique_project_keyword_location_language", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "keyword", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "location_code", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "language_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "saved_keywords_project_created_idx": { + "name": "saved_keywords_project_created_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "saved_keywords_project_id_projects_id_fk": { + "name": "saved_keywords_project_id_projects_id_fk", + "tableFrom": "saved_keywords", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_onboarding_answers": { + "name": "user_onboarding_answers", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "interested_features": { + "name": "interested_features", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "work_for": { + "name": "work_for", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_website_count": { + "name": "client_website_count", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "found_via": { + "name": "found_via", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_setup_intent": { + "name": "mcp_setup_intent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gsc_nudge_dismissed_at": { + "name": "gsc_nudge_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "user_onboarding_answers_organization_idx": { + "name": "user_onboarding_answers_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_onboarding_answers_user_id_user_id_fk": { + "name": "user_onboarding_answers_user_id_user_id_fk", + "tableFrom": "user_onboarding_answers", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_onboarding_answers_organization_id_organization_id_fk": { + "name": "user_onboarding_answers_organization_id_organization_id_fk", + "tableFrom": "user_onboarding_answers", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_competitors": { + "name": "project_competitors", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "project_competitors_project_domain_idx": { + "name": "project_competitors_project_domain_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_competitors_project_id_projects_id_fk": { + "name": "project_competitors_project_id_projects_id_fk", + "tableFrom": "project_competitors", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_context_sections": { + "name": "project_context_sections", + "schema": "", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "project_context_sections_project_id_projects_id_fk": { + "name": "project_context_sections_project_id_projects_id_fk", + "tableFrom": "project_context_sections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "project_context_sections_project_id_key_pk": { + "name": "project_context_sections_project_id_key_pk", + "columns": [ + "project_id", + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_key_pages": { + "name": "project_key_pages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "project_key_pages_project_url_idx": { + "name": "project_key_pages_project_url_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "url", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_key_pages_project_id_projects_id_fk": { + "name": "project_key_pages_project_id_projects_id_fk", + "tableFrom": "project_key_pages", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_research_log": { + "name": "project_research_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entry_date": { + "name": "entry_date", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "project_research_log_project_date_idx": { + "name": "project_research_log_project_date_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entry_date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_research_log_project_id_projects_id_fk": { + "name": "project_research_log_project_id_projects_id_fk", + "tableFrom": "project_research_log", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_issues": { + "name": "audit_issues", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "page_id": { + "name": "page_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "page_url": { + "name": "page_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "issue_type": { + "name": "issue_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "severity": { + "name": "severity", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'info'" + }, + "details_json": { + "name": "details_json", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "audit_issues_audit_type_idx": { + "name": "audit_issues_audit_type_idx", + "columns": [ + { + "expression": "audit_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "issue_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_issues_page_id_idx": { + "name": "audit_issues_page_id_idx", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_issues_audit_id_audits_id_fk": { + "name": "audit_issues_audit_id_audits_id_fk", + "tableFrom": "audit_issues", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_issues_page_id_audit_pages_id_fk": { + "name": "audit_issues_page_id_audit_pages_id_fk", + "tableFrom": "audit_issues", + "tableTo": "audit_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_lighthouse_results": { + "name": "audit_lighthouse_results", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "page_id": { + "name": "page_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "strategy": { + "name": "strategy", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "performance_score": { + "name": "performance_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "accessibility_score": { + "name": "accessibility_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "best_practices_score": { + "name": "best_practices_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "seo_score": { + "name": "seo_score", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "lcp_ms": { + "name": "lcp_ms", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "cls": { + "name": "cls", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "inp_ms": { + "name": "inp_ms", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "ttfb_ms": { + "name": "ttfb_ms", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "r2_key": { + "name": "r2_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payload_size_bytes": { + "name": "payload_size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "audit_lighthouse_results_audit_id_idx": { + "name": "audit_lighthouse_results_audit_id_idx", + "columns": [ + { + "expression": "audit_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_lighthouse_results_page_id_idx": { + "name": "audit_lighthouse_results_page_id_idx", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_lighthouse_results_audit_id_audits_id_fk": { + "name": "audit_lighthouse_results_audit_id_audits_id_fk", + "tableFrom": "audit_lighthouse_results", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_lighthouse_results_page_id_audit_pages_id_fk": { + "name": "audit_lighthouse_results_page_id_audit_pages_id_fk", + "tableFrom": "audit_lighthouse_results", + "tableTo": "audit_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_pages": { + "name": "audit_pages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "redirect_url": { + "name": "redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meta_description": { + "name": "meta_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "canonical_url": { + "name": "canonical_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "robots_meta": { + "name": "robots_meta", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "og_title": { + "name": "og_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "og_description": { + "name": "og_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "og_image": { + "name": "og_image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "h1_count": { + "name": "h1_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "h2_count": { + "name": "h2_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "h3_count": { + "name": "h3_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "h4_count": { + "name": "h4_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "h5_count": { + "name": "h5_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "h6_count": { + "name": "h6_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "heading_order_json": { + "name": "heading_order_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "word_count": { + "name": "word_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "images_total": { + "name": "images_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "images_missing_alt": { + "name": "images_missing_alt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "images_json": { + "name": "images_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "internal_link_count": { + "name": "internal_link_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "external_link_count": { + "name": "external_link_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "has_structured_data": { + "name": "has_structured_data", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "hreflang_tags_json": { + "name": "hreflang_tags_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_indexable": { + "name": "is_indexable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "x_robots_tag": { + "name": "x_robots_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "header_canonical_url": { + "name": "header_canonical_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "crawl_depth": { + "name": "crawl_depth", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "in_sitemap": { + "name": "in_sitemap", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fetch_class": { + "name": "fetch_class", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ok'" + }, + "response_time_ms": { + "name": "response_time_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "audit_pages_audit_url_idx": { + "name": "audit_pages_audit_url_idx", + "columns": [ + { + "expression": "audit_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "url", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_pages_audit_id_audits_id_fk": { + "name": "audit_pages_audit_id_audits_id_fk", + "tableFrom": "audit_pages", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audits": { + "name": "audits", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_by_user_id": { + "name": "started_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_url": { + "name": "start_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "workflow_instance_id": { + "name": "workflow_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "pages_crawled": { + "name": "pages_crawled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "pages_total": { + "name": "pages_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "lighthouse_total": { + "name": "lighthouse_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "lighthouse_completed": { + "name": "lighthouse_completed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "lighthouse_failed": { + "name": "lighthouse_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "current_phase": { + "name": "current_phase", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'discovery'" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail": { + "name": "error_detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "failed_phase": { + "name": "failed_phase", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "audits_project_id_idx": { + "name": "audits_project_id_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audits_started_by_user_id_idx": { + "name": "audits_started_by_user_id_idx", + "columns": [ + { + "expression": "started_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audits_project_id_projects_id_fk": { + "name": "audits_project_id_projects_id_fk", + "tableFrom": "audits", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sam_sessions": { + "name": "sam_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'New chat'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "sam_sessions_project_updated_idx": { + "name": "sam_sessions_project_updated_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sam_sessions_project_id_projects_id_fk": { + "name": "sam_sessions_project_id_projects_id_fk", + "tableFrom": "sam_sessions", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sam_sessions_user_id_user_id_fk": { + "name": "sam_sessions_user_id_user_id_fk", + "tableFrom": "sam_sessions", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "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 + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "account_accountId_providerId_idx": { + "name": "account_accountId_providerId_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 60000 + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 120 + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_request": { + "name": "last_request", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "apikey_configId_idx": { + "name": "apikey_configId_idx", + "columns": [ + { + "expression": "config_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "apikey_referenceId_idx": { + "name": "apikey_referenceId_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "organization_slug_uidx": { + "name": "organization_slug_uidx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "slug" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "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 + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": [ + "token" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "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()" + }, + "analytics_opted_out": { + "name": "analytics_opted_out", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "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 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": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "verification_expiresAt_idx": { + "name": "verification_expiresAt_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.billing_customer_status": { + "name": "billing_customer_status", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "is_paying": { + "name": "is_paying", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "paid_plan_id": { + "name": "paid_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "paid_plan_status": { + "name": "paid_plan_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "customer_json": { + "name": "customer_json", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "synced_at": { + "name": "synced_at", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": {}, + "foreignKeys": { + "billing_customer_status_organization_id_organization_id_fk": { + "name": "billing_customer_status_organization_id_organization_id_fk", + "tableFrom": "billing_customer_status", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ga4_connections": { + "name": "ga4_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_id": { + "name": "property_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_display_name": { + "name": "property_display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_time_zone": { + "name": "property_time_zone", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "property_currency_code": { + "name": "property_currency_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connected_by_user_id": { + "name": "connected_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ga4_account_id": { + "name": "ga4_account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connected_account_email": { + "name": "connected_account_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "ga4_connections_project_idx": { + "name": "ga4_connections_project_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ga4_connections_organization_idx": { + "name": "ga4_connections_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ga4_connections_connector_idx": { + "name": "ga4_connections_connector_idx", + "columns": [ + { + "expression": "connected_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "ga4_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "ga4_connections_project_id_projects_id_fk": { + "name": "ga4_connections_project_id_projects_id_fk", + "tableFrom": "ga4_connections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "ga4_connections_organization_id_organization_id_fk": { + "name": "ga4_connections_organization_id_organization_id_fk", + "tableFrom": "ga4_connections", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gsc_connections": { + "name": "gsc_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "site_url": { + "name": "site_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connected_by_user_id": { + "name": "connected_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "gsc_account_id": { + "name": "gsc_account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "connected_account_email": { + "name": "connected_account_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "gsc_connections_project_idx": { + "name": "gsc_connections_project_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "gsc_connections_organization_idx": { + "name": "gsc_connections_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "gsc_connections_project_id_projects_id_fk": { + "name": "gsc_connections_project_id_projects_id_fk", + "tableFrom": "gsc_connections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "gsc_connections_organization_id_organization_id_fk": { + "name": "gsc_connections_organization_id_organization_id_fk", + "tableFrom": "gsc_connections", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telemetry_state": { + "name": "telemetry_state", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "default": 1 + }, + "install_id": { + "name": "install_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "installed_at": { + "name": "installed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_version": { + "name": "last_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_tool_call_count": { + "name": "mcp_tool_call_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.brand_lookup_runs": { + "name": "brand_lookup_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "query": { + "name": "query", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resolved_target": { + "name": "resolved_target", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "competitors": { + "name": "competitors", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "total_mentions": { + "name": "total_mentions", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "total_ai_search_volume": { + "name": "total_ai_search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "share_of_voice_percent": { + "name": "share_of_voice_percent", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fetched_at": { + "name": "fetched_at", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD\"T\"HH24:MI:SS.MS\"Z\"')" + } + }, + "indexes": { + "brand_lookup_runs_project_created_idx": { + "name": "brand_lookup_runs_project_created_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "brand_lookup_runs_project_id_projects_id_fk": { + "name": "brand_lookup_runs_project_id_projects_id_fk", + "tableFrom": "brand_lookup_runs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle-pg/meta/_journal.json b/drizzle-pg/meta/_journal.json index 9eb6f46eb..f04d48807 100644 --- a/drizzle-pg/meta/_journal.json +++ b/drizzle-pg/meta/_journal.json @@ -148,6 +148,13 @@ "when": 1787099999115, "tag": "0020_project_memory", "breakpoints": true + }, + { + "idx": 21, + "version": "7", + "when": 1788293596305, + "tag": "0021_parched_zombie", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle/0043_red_vector.sql b/drizzle/0043_red_vector.sql new file mode 100644 index 000000000..0b07568bb --- /dev/null +++ b/drizzle/0043_red_vector.sql @@ -0,0 +1,17 @@ +CREATE TABLE `brand_lookup_runs` ( + `id` text PRIMARY KEY NOT NULL, + `project_id` text NOT NULL, + `query` text NOT NULL, + `resolved_target` text NOT NULL, + `scope` text, + `competitors` text DEFAULT '[]' NOT NULL, + `total_mentions` integer, + `total_ai_search_volume` integer, + `share_of_voice_percent` integer, + `payload` text NOT NULL, + `fetched_at` text NOT NULL, + `created_at` text DEFAULT (current_timestamp) NOT NULL, + FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE INDEX `brand_lookup_runs_project_created_idx` ON `brand_lookup_runs` (`project_id`,`created_at`); \ No newline at end of file diff --git a/drizzle/meta/0043_snapshot.json b/drizzle/meta/0043_snapshot.json new file mode 100644 index 000000000..7d04aa974 --- /dev/null +++ b/drizzle/meta/0043_snapshot.json @@ -0,0 +1,3851 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "56cb4a41-3b9f-4921-8735-3a5f5e39ff11", + "prevId": "f630c50c-3593-4109-bbc5-2de95ef1f74e", + "tables": { + "backlink_snapshots": { + "name": "backlink_snapshots", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rank": { + "name": "rank", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "backlinks": { + "name": "backlinks", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "referring_domains": { + "name": "referring_domains", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "broken_backlinks": { + "name": "broken_backlinks", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "new_backlinks": { + "name": "new_backlinks", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lost_backlinks": { + "name": "lost_backlinks", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "new_referring_domains": { + "name": "new_referring_domains", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lost_referring_domains": { + "name": "lost_referring_domains", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "captured_at": { + "name": "captured_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "backlink_snapshots_project_captured_idx": { + "name": "backlink_snapshots_project_captured_idx", + "columns": [ + "project_id", + "captured_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "backlink_snapshots_project_id_projects_id_fk": { + "name": "backlink_snapshots_project_id_projects_id_fk", + "tableFrom": "backlink_snapshots", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "keyword_metrics": { + "name": "keyword_metrics", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'en'" + }, + "search_volume": { + "name": "search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpc": { + "name": "cpc", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "competition": { + "name": "competition", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "keyword_difficulty": { + "name": "keyword_difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "intent": { + "name": "intent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "monthly_searches": { + "name": "monthly_searches", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fetched_at": { + "name": "fetched_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "keyword_metrics_unique_project_keyword_location_language": { + "name": "keyword_metrics_unique_project_keyword_location_language", + "columns": [ + "project_id", + "keyword", + "location_code", + "language_code" + ], + "isUnique": true + }, + "keyword_metrics_lookup_idx": { + "name": "keyword_metrics_lookup_idx", + "columns": [ + "project_id", + "keyword", + "location_code", + "language_code", + "fetched_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "keyword_metrics_project_id_projects_id_fk": { + "name": "keyword_metrics_project_id_projects_id_fk", + "tableFrom": "keyword_metrics", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization_activation_state": { + "name": "organization_activation_state", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "first_mcp_authorized_at": { + "name": "first_mcp_authorized_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_mcp_tool_call_at": { + "name": "first_mcp_tool_call_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_activation_state_organization_id_organization_id_fk": { + "name": "organization_activation_state_organization_id_organization_id_fk", + "tableFrom": "organization_activation_state", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_activation_state": { + "name": "project_activation_state", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "competitor_step_clicked_at": { + "name": "competitor_step_clicked_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mcp_card_dismissed_at": { + "name": "mcp_card_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ga4_card_dismissed_at": { + "name": "ga4_card_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": {}, + "foreignKeys": { + "project_activation_state_project_id_projects_id_fk": { + "name": "project_activation_state_project_id_projects_id_fk", + "tableFrom": "project_activation_state", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'en'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "projects_one_default_per_organization_idx": { + "name": "projects_one_default_per_organization_idx", + "columns": [ + "organization_id" + ], + "isUnique": true, + "where": "\"projects\".\"name\" = 'Default' AND \"projects\".\"domain\" IS NULL AND \"projects\".\"archived_at\" IS NULL" + }, + "projects_organization_id_idx": { + "name": "projects_organization_id_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "projects_organization_id_organization_id_fk": { + "name": "projects_organization_id_organization_id_fk", + "tableFrom": "projects", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rank_check_runs": { + "name": "rank_check_runs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "keywords_total": { + "name": "keywords_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "keywords_checked": { + "name": "keywords_checked", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "is_subset_run": { + "name": "is_subset_run", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "rank_check_runs_config_idx": { + "name": "rank_check_runs_config_idx", + "columns": [ + "config_id", + "started_at" + ], + "isUnique": false + }, + "rank_check_runs_project_idx": { + "name": "rank_check_runs_project_idx", + "columns": [ + "project_id", + "started_at" + ], + "isUnique": false + }, + "rank_check_runs_one_active_per_config_idx": { + "name": "rank_check_runs_one_active_per_config_idx", + "columns": [ + "config_id" + ], + "isUnique": true, + "where": "\"rank_check_runs\".\"status\" IN ('pending', 'running')" + } + }, + "foreignKeys": { + "rank_check_runs_config_id_rank_tracking_configs_id_fk": { + "name": "rank_check_runs_config_id_rank_tracking_configs_id_fk", + "tableFrom": "rank_check_runs", + "tableTo": "rank_tracking_configs", + "columnsFrom": [ + "config_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "rank_check_runs_project_id_projects_id_fk": { + "name": "rank_check_runs_project_id_projects_id_fk", + "tableFrom": "rank_check_runs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rank_snapshots": { + "name": "rank_snapshots", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tracking_keyword_id": { + "name": "tracking_keyword_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "serp_features": { + "name": "serp_features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "checked_at": { + "name": "checked_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "rank_snapshots_keyword_device_idx": { + "name": "rank_snapshots_keyword_device_idx", + "columns": [ + "tracking_keyword_id", + "device", + "checked_at" + ], + "isUnique": false + }, + "rank_snapshots_run_keyword_device_idx": { + "name": "rank_snapshots_run_keyword_device_idx", + "columns": [ + "run_id", + "tracking_keyword_id", + "device" + ], + "isUnique": true + } + }, + "foreignKeys": { + "rank_snapshots_run_id_rank_check_runs_id_fk": { + "name": "rank_snapshots_run_id_rank_check_runs_id_fk", + "tableFrom": "rank_snapshots", + "tableTo": "rank_check_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rank_tracking_configs": { + "name": "rank_tracking_configs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'en'" + }, + "devices": { + "name": "devices", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'both'" + }, + "serp_depth": { + "name": "serp_depth", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule_interval": { + "name": "schedule_interval", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'weekly'" + }, + "location_name": { + "name": "location_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "last_checked_at": { + "name": "last_checked_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "next_check_at": { + "name": "next_check_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_skip_reason": { + "name": "last_skip_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "rank_tracking_configs_project_active_created_idx": { + "name": "rank_tracking_configs_project_active_created_idx", + "columns": [ + "project_id", + "is_active", + "created_at" + ], + "isUnique": false + }, + "rank_tracking_configs_national_idx": { + "name": "rank_tracking_configs_national_idx", + "columns": [ + "project_id", + "domain", + "location_code" + ], + "isUnique": true, + "where": "\"rank_tracking_configs\".\"location_name\" IS NULL" + }, + "rank_tracking_configs_local_idx": { + "name": "rank_tracking_configs_local_idx", + "columns": [ + "project_id", + "domain", + "location_code", + "location_name" + ], + "isUnique": true, + "where": "\"rank_tracking_configs\".\"location_name\" IS NOT NULL" + } + }, + "foreignKeys": { + "rank_tracking_configs_project_id_projects_id_fk": { + "name": "rank_tracking_configs_project_id_projects_id_fk", + "tableFrom": "rank_tracking_configs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "rank_tracking_keywords": { + "name": "rank_tracking_keywords", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "search_volume": { + "name": "search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "keyword_difficulty": { + "name": "keyword_difficulty", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cpc": { + "name": "cpc", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metrics_fetched_at": { + "name": "metrics_fetched_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "rank_tracking_keywords_config_keyword_idx": { + "name": "rank_tracking_keywords_config_keyword_idx", + "columns": [ + "config_id", + "keyword" + ], + "isUnique": true + } + }, + "foreignKeys": { + "rank_tracking_keywords_config_id_rank_tracking_configs_id_fk": { + "name": "rank_tracking_keywords_config_id_rank_tracking_configs_id_fk", + "tableFrom": "rank_tracking_keywords", + "tableTo": "rank_tracking_configs", + "columnsFrom": [ + "config_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "saved_keyword_tag_assignments": { + "name": "saved_keyword_tag_assignments", + "columns": { + "saved_keyword_id": { + "name": "saved_keyword_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "tag_id": { + "name": "tag_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "saved_keyword_tag_assignments_unique_idx": { + "name": "saved_keyword_tag_assignments_unique_idx", + "columns": [ + "saved_keyword_id", + "tag_id" + ], + "isUnique": true + }, + "saved_keyword_tag_assignments_tag_idx": { + "name": "saved_keyword_tag_assignments_tag_idx", + "columns": [ + "tag_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "saved_keyword_tag_assignments_saved_keyword_id_saved_keywords_id_fk": { + "name": "saved_keyword_tag_assignments_saved_keyword_id_saved_keywords_id_fk", + "tableFrom": "saved_keyword_tag_assignments", + "tableTo": "saved_keywords", + "columnsFrom": [ + "saved_keyword_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "saved_keyword_tag_assignments_tag_id_saved_keyword_tags_id_fk": { + "name": "saved_keyword_tag_assignments_tag_id_saved_keyword_tags_id_fk", + "tableFrom": "saved_keyword_tag_assignments", + "tableTo": "saved_keyword_tags", + "columnsFrom": [ + "tag_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "saved_keyword_tags": { + "name": "saved_keyword_tags", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "normalized_name": { + "name": "normalized_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "saved_keyword_tags_project_normalized_name_idx": { + "name": "saved_keyword_tags_project_normalized_name_idx", + "columns": [ + "project_id", + "normalized_name" + ], + "isUnique": true + }, + "saved_keyword_tags_project_name_idx": { + "name": "saved_keyword_tags_project_name_idx", + "columns": [ + "project_id", + "name" + ], + "isUnique": false + } + }, + "foreignKeys": { + "saved_keyword_tags_project_id_projects_id_fk": { + "name": "saved_keyword_tags_project_id_projects_id_fk", + "tableFrom": "saved_keyword_tags", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "saved_keywords": { + "name": "saved_keywords", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "keyword": { + "name": "keyword", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "location_code": { + "name": "location_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 2840 + }, + "language_code": { + "name": "language_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'en'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "saved_keywords_unique_project_keyword_location_language": { + "name": "saved_keywords_unique_project_keyword_location_language", + "columns": [ + "project_id", + "keyword", + "location_code", + "language_code" + ], + "isUnique": true + }, + "saved_keywords_project_created_idx": { + "name": "saved_keywords_project_created_idx", + "columns": [ + "project_id", + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "saved_keywords_project_id_projects_id_fk": { + "name": "saved_keywords_project_id_projects_id_fk", + "tableFrom": "saved_keywords", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_onboarding_answers": { + "name": "user_onboarding_answers", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "interested_features": { + "name": "interested_features", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "work_for": { + "name": "work_for", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "client_website_count": { + "name": "client_website_count", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "found_via": { + "name": "found_via", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mcp_setup_intent": { + "name": "mcp_setup_intent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "gsc_nudge_dismissed_at": { + "name": "gsc_nudge_dismissed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "user_onboarding_answers_organization_idx": { + "name": "user_onboarding_answers_organization_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "user_onboarding_answers_user_id_user_id_fk": { + "name": "user_onboarding_answers_user_id_user_id_fk", + "tableFrom": "user_onboarding_answers", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_onboarding_answers_organization_id_organization_id_fk": { + "name": "user_onboarding_answers_organization_id_organization_id_fk", + "tableFrom": "user_onboarding_answers", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_competitors": { + "name": "project_competitors", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "project_competitors_project_domain_idx": { + "name": "project_competitors_project_domain_idx", + "columns": [ + "project_id", + "domain" + ], + "isUnique": true + } + }, + "foreignKeys": { + "project_competitors_project_id_projects_id_fk": { + "name": "project_competitors_project_id_projects_id_fk", + "tableFrom": "project_competitors", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_context_sections": { + "name": "project_context_sections", + "columns": { + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_context_sections_project_id_projects_id_fk": { + "name": "project_context_sections_project_id_projects_id_fk", + "tableFrom": "project_context_sections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "project_context_sections_project_id_key_pk": { + "columns": [ + "project_id", + "key" + ], + "name": "project_context_sections_project_id_key_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_key_pages": { + "name": "project_key_pages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "project_key_pages_project_url_idx": { + "name": "project_key_pages_project_url_idx", + "columns": [ + "project_id", + "url" + ], + "isUnique": true + } + }, + "foreignKeys": { + "project_key_pages_project_id_projects_id_fk": { + "name": "project_key_pages_project_id_projects_id_fk", + "tableFrom": "project_key_pages", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_research_log": { + "name": "project_research_log", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "entry_date": { + "name": "entry_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ','now'))" + } + }, + "indexes": { + "project_research_log_project_date_idx": { + "name": "project_research_log_project_date_idx", + "columns": [ + "project_id", + "entry_date" + ], + "isUnique": false + } + }, + "foreignKeys": { + "project_research_log_project_id_projects_id_fk": { + "name": "project_research_log_project_id_projects_id_fk", + "tableFrom": "project_research_log", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_issues": { + "name": "audit_issues", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "page_id": { + "name": "page_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_url": { + "name": "page_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "issue_type": { + "name": "issue_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "severity": { + "name": "severity", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'info'" + }, + "details_json": { + "name": "details_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_issues_audit_type_idx": { + "name": "audit_issues_audit_type_idx", + "columns": [ + "audit_id", + "issue_type" + ], + "isUnique": false + }, + "audit_issues_page_id_idx": { + "name": "audit_issues_page_id_idx", + "columns": [ + "page_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audit_issues_audit_id_audits_id_fk": { + "name": "audit_issues_audit_id_audits_id_fk", + "tableFrom": "audit_issues", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_issues_page_id_audit_pages_id_fk": { + "name": "audit_issues_page_id_audit_pages_id_fk", + "tableFrom": "audit_issues", + "tableTo": "audit_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_lighthouse_results": { + "name": "audit_lighthouse_results", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "page_id": { + "name": "page_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "strategy": { + "name": "strategy", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "performance_score": { + "name": "performance_score", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accessibility_score": { + "name": "accessibility_score", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "best_practices_score": { + "name": "best_practices_score", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "seo_score": { + "name": "seo_score", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lcp_ms": { + "name": "lcp_ms", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "cls": { + "name": "cls", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "inp_ms": { + "name": "inp_ms", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ttfb_ms": { + "name": "ttfb_ms", + "type": "real", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "r2_key": { + "name": "r2_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payload_size_bytes": { + "name": "payload_size_bytes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_lighthouse_results_audit_id_idx": { + "name": "audit_lighthouse_results_audit_id_idx", + "columns": [ + "audit_id" + ], + "isUnique": false + }, + "audit_lighthouse_results_page_id_idx": { + "name": "audit_lighthouse_results_page_id_idx", + "columns": [ + "page_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audit_lighthouse_results_audit_id_audits_id_fk": { + "name": "audit_lighthouse_results_audit_id_audits_id_fk", + "tableFrom": "audit_lighthouse_results", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "audit_lighthouse_results_page_id_audit_pages_id_fk": { + "name": "audit_lighthouse_results_page_id_audit_pages_id_fk", + "tableFrom": "audit_lighthouse_results", + "tableTo": "audit_pages", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audit_pages": { + "name": "audit_pages", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "audit_id": { + "name": "audit_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "redirect_url": { + "name": "redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta_description": { + "name": "meta_description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "canonical_url": { + "name": "canonical_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "robots_meta": { + "name": "robots_meta", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "og_title": { + "name": "og_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "og_description": { + "name": "og_description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "og_image": { + "name": "og_image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "h1_count": { + "name": "h1_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "h2_count": { + "name": "h2_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "h3_count": { + "name": "h3_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "h4_count": { + "name": "h4_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "h5_count": { + "name": "h5_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "h6_count": { + "name": "h6_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "heading_order_json": { + "name": "heading_order_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "word_count": { + "name": "word_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "images_total": { + "name": "images_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "images_missing_alt": { + "name": "images_missing_alt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "images_json": { + "name": "images_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "internal_link_count": { + "name": "internal_link_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "external_link_count": { + "name": "external_link_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "has_structured_data": { + "name": "has_structured_data", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "hreflang_tags_json": { + "name": "hreflang_tags_json", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_indexable": { + "name": "is_indexable", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "x_robots_tag": { + "name": "x_robots_tag", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "header_canonical_url": { + "name": "header_canonical_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "crawl_depth": { + "name": "crawl_depth", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "in_sitemap": { + "name": "in_sitemap", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fetch_class": { + "name": "fetch_class", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'ok'" + }, + "response_time_ms": { + "name": "response_time_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audit_pages_audit_url_idx": { + "name": "audit_pages_audit_url_idx", + "columns": [ + "audit_id", + "url" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audit_pages_audit_id_audits_id_fk": { + "name": "audit_pages_audit_id_audits_id_fk", + "tableFrom": "audit_pages", + "tableTo": "audits", + "columnsFrom": [ + "audit_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "audits": { + "name": "audits", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "started_by_user_id": { + "name": "started_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "start_url": { + "name": "start_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'running'" + }, + "workflow_instance_id": { + "name": "workflow_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "config": { + "name": "config", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'{}'" + }, + "pages_crawled": { + "name": "pages_crawled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "pages_total": { + "name": "pages_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "lighthouse_total": { + "name": "lighthouse_total", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "lighthouse_completed": { + "name": "lighthouse_completed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "lighthouse_failed": { + "name": "lighthouse_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "current_phase": { + "name": "current_phase", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'discovery'" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_detail": { + "name": "error_detail", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "failed_phase": { + "name": "failed_phase", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "audits_project_id_idx": { + "name": "audits_project_id_idx", + "columns": [ + "project_id" + ], + "isUnique": false + }, + "audits_started_by_user_id_idx": { + "name": "audits_started_by_user_id_idx", + "columns": [ + "started_by_user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "audits_project_id_projects_id_fk": { + "name": "audits_project_id_projects_id_fk", + "tableFrom": "audits", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sam_sessions": { + "name": "sam_sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'New chat'" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "archived_at": { + "name": "archived_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "sam_sessions_project_updated_idx": { + "name": "sam_sessions_project_updated_idx", + "columns": [ + "project_id", + "updated_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "sam_sessions_project_id_projects_id_fk": { + "name": "sam_sessions_project_id_projects_id_fk", + "tableFrom": "sam_sessions", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sam_sessions_user_id_user_id_fk": { + "name": "sam_sessions_user_id_user_id_fk", + "tableFrom": "sam_sessions", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "account_userId_idx": { + "name": "account_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + }, + "account_accountId_providerId_idx": { + "name": "account_accountId_providerId_idx", + "columns": [ + "account_id", + "provider_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "apikey": { + "name": "apikey", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "config_id": { + "name": "config_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'default'" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": true + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 60000 + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 120 + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_request": { + "name": "last_request", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "apikey_configId_idx": { + "name": "apikey_configId_idx", + "columns": [ + "config_id" + ], + "isUnique": false + }, + "apikey_referenceId_idx": { + "name": "apikey_referenceId_idx", + "columns": [ + "reference_id" + ], + "isUnique": false + }, + "apikey_key_idx": { + "name": "apikey_key_idx", + "columns": [ + "key" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invitation": { + "name": "invitation", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invitation_organizationId_idx": { + "name": "invitation_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": { + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "member": { + "name": "member", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "member_organizationId_idx": { + "name": "member_organizationId_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "member_userId_idx": { + "name": "member_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization": { + "name": "organization", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "organization_slug_unique": { + "name": "organization_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + }, + "organization_slug_uidx": { + "name": "organization_slug_uidx", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + "token" + ], + "isUnique": true + }, + "session_userId_idx": { + "name": "session_userId_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "analytics_opted_out": { + "name": "analytics_opted_out", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + "identifier" + ], + "isUnique": false + }, + "verification_expiresAt_idx": { + "name": "verification_expiresAt_idx", + "columns": [ + "expires_at" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "billing_customer_status": { + "name": "billing_customer_status", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "is_paying": { + "name": "is_paying", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "paid_plan_id": { + "name": "paid_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "paid_plan_status": { + "name": "paid_plan_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_json": { + "name": "customer_json", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "synced_at": { + "name": "synced_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": {}, + "foreignKeys": { + "billing_customer_status_organization_id_organization_id_fk": { + "name": "billing_customer_status_organization_id_organization_id_fk", + "tableFrom": "billing_customer_status", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "ga4_connections": { + "name": "ga4_connections", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "property_id": { + "name": "property_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "property_display_name": { + "name": "property_display_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "property_time_zone": { + "name": "property_time_zone", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "property_currency_code": { + "name": "property_currency_code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "connected_by_user_id": { + "name": "connected_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ga4_account_id": { + "name": "ga4_account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "connected_account_email": { + "name": "connected_account_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "ga4_connections_project_idx": { + "name": "ga4_connections_project_idx", + "columns": [ + "project_id" + ], + "isUnique": true + }, + "ga4_connections_organization_idx": { + "name": "ga4_connections_organization_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + }, + "ga4_connections_connector_idx": { + "name": "ga4_connections_connector_idx", + "columns": [ + "connected_by_user_id", + "ga4_account_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "ga4_connections_project_id_projects_id_fk": { + "name": "ga4_connections_project_id_projects_id_fk", + "tableFrom": "ga4_connections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "ga4_connections_organization_id_organization_id_fk": { + "name": "ga4_connections_organization_id_organization_id_fk", + "tableFrom": "ga4_connections", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "gsc_connections": { + "name": "gsc_connections", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "site_url": { + "name": "site_url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "connected_by_user_id": { + "name": "connected_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "gsc_account_id": { + "name": "gsc_account_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "connected_account_email": { + "name": "connected_account_email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "gsc_connections_project_idx": { + "name": "gsc_connections_project_idx", + "columns": [ + "project_id" + ], + "isUnique": true + }, + "gsc_connections_organization_idx": { + "name": "gsc_connections_organization_idx", + "columns": [ + "organization_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "gsc_connections_project_id_projects_id_fk": { + "name": "gsc_connections_project_id_projects_id_fk", + "tableFrom": "gsc_connections", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "gsc_connections_organization_id_organization_id_fk": { + "name": "gsc_connections_organization_id_organization_id_fk", + "tableFrom": "gsc_connections", + "tableTo": "organization", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "telemetry_state": { + "name": "telemetry_state", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "install_id": { + "name": "install_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "installed_at": { + "name": "installed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_version": { + "name": "last_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "mcp_tool_call_count": { + "name": "mcp_tool_call_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "brand_lookup_runs": { + "name": "brand_lookup_runs", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "query": { + "name": "query", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "resolved_target": { + "name": "resolved_target", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "competitors": { + "name": "competitors", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'[]'" + }, + "total_mentions": { + "name": "total_mentions", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "total_ai_search_volume": { + "name": "total_ai_search_volume", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "share_of_voice_percent": { + "name": "share_of_voice_percent", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "fetched_at": { + "name": "fetched_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(current_timestamp)" + } + }, + "indexes": { + "brand_lookup_runs_project_created_idx": { + "name": "brand_lookup_runs_project_created_idx", + "columns": [ + "project_id", + "created_at" + ], + "isUnique": false + } + }, + "foreignKeys": { + "brand_lookup_runs_project_id_projects_id_fk": { + "name": "brand_lookup_runs_project_id_projects_id_fk", + "tableFrom": "brand_lookup_runs", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 35b08cb88..52444991d 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -302,6 +302,13 @@ "when": 1787099999115, "tag": "0042_project_memory", "breakpoints": true + }, + { + "idx": 43, + "version": "6", + "when": 1788293595830, + "tag": "0043_red_vector", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/client/features/ai-search/BrandLookupPage.tsx b/src/client/features/ai-search/BrandLookupPage.tsx index 3540dfe73..bdad8e4ec 100644 --- a/src/client/features/ai-search/BrandLookupPage.tsx +++ b/src/client/features/ai-search/BrandLookupPage.tsx @@ -8,7 +8,7 @@ import { Quote, TrendingUp, } from "lucide-react"; -import { lookupBrand } from "@/serverFunctions/ai-search"; +import { getSavedBrandLookup, lookupBrand } from "@/serverFunctions/ai-search"; import { HostedPlanGate, type HostedPlanGateState, @@ -17,6 +17,7 @@ import { getStandardErrorMessage } from "@/client/lib/error-messages"; import { BrandLookupResults } from "@/client/features/ai-search/components/BrandLookupResults"; import { BrandLookupSearchCard } from "@/client/features/ai-search/components/BrandLookupSearchCard"; import { BrandLookupHistorySection } from "@/client/features/ai-search/components/BrandLookupHistorySection"; +import { SavedBrandLookupsSection } from "@/client/features/ai-search/components/SavedBrandLookupsSection"; import { AiSearchLoadingState } from "@/client/features/ai-search/components/AiSearchLoadingState"; import { AiSearchPaidPlanGate } from "@/client/features/ai-search/components/AiSearchPaidPlanGate"; import { useBrandLookupSearchHistory } from "@/client/hooks/useBrandLookupSearchHistory"; @@ -143,6 +144,19 @@ function BrandLookupPageInner({ retry: false, }); + // A saved run opened from the Saved lookups table. Rendering it reads the + // stored payload, so re-opening an old run never re-charges DataForSEO. + const [openedRunId, setOpenedRunId] = useState(null); + const savedRunQuery = useQuery({ + queryKey: ["brand-lookup-saved-run", projectId, openedRunId], + queryFn: () => + getSavedBrandLookup({ + data: { projectId, runId: openedRunId ?? "" }, + }), + enabled: openedRunId !== null, + staleTime: Infinity, + }); + const { history, isLoaded: historyLoaded, @@ -322,13 +336,45 @@ function BrandLookupPageInner({ + ) : openedRunId !== null ? ( + <> +
+ +
+ {savedRunQuery.isLoading ? ( + + ) : savedRunQuery.data ? ( + + ) : ( +
+ That saved lookup could not be read back. It may have been + written by an older version of the result format. +
+ )} + ) : !errorMessage ? ( - + <> + + + ) : null} )} diff --git a/src/client/features/ai-search/components/SavedBrandLookupsSection.tsx b/src/client/features/ai-search/components/SavedBrandLookupsSection.tsx new file mode 100644 index 000000000..5c29d827b --- /dev/null +++ b/src/client/features/ai-search/components/SavedBrandLookupsSection.tsx @@ -0,0 +1,133 @@ +import { useQuery } from "@tanstack/react-query"; +import { Database, Trash2 } from "lucide-react"; +import { + listSavedBrandLookups, + removeSavedBrandLookup, +} from "@/serverFunctions/ai-search"; +import { + RESEARCH_SCOPE_LABELS, + researchScopeSchema, +} from "@/shared/researchScope"; + +// Server-persisted Brand Lookup runs, as opposed to the localStorage "recent +// searches" list above it. These follow the project rather than the browser and +// keep the numbers each run returned, which is what makes a month-over-month +// comparison possible at all. + +type Props = { + projectId: string; + onOpenRun: (runId: string) => void; +}; + +const numberFormat = new Intl.NumberFormat("en-US"); + +/** + * The stored scope is a plain column, so it is narrowed at runtime rather than + * asserted — a row written by an older build could hold anything. + */ +function scopeLabel(scope: string): string { + const parsed = researchScopeSchema.safeParse(scope); + return parsed.success ? RESEARCH_SCOPE_LABELS[parsed.data] : scope; +} + +function formatWhen(iso: string): string { + // Stored values are either ISO or SQLite's "YYYY-MM-DD HH:MM:SS" (UTC). + const normalized = iso.includes("T") ? iso : `${iso.replace(" ", "T")}Z`; + const parsed = new Date(normalized); + if (Number.isNaN(parsed.getTime())) return iso; + return parsed.toLocaleDateString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + }); +} + +export function SavedBrandLookupsSection({ projectId, onOpenRun }: Props) { + const runsQuery = useQuery({ + queryKey: ["brand-lookup-saved-runs", projectId], + queryFn: () => listSavedBrandLookups({ data: { projectId } }), + staleTime: 30 * 1000, + }); + + const runs = runsQuery.data ?? []; + if (runsQuery.isLoading || runs.length === 0) return null; + + return ( +
+
+ +

Saved lookups

+ + kept on the server, opening one costs nothing + +
+ +
+ + + + + + + + + + + {runs.map((run) => ( + + + + + + + + ))} + +
TargetMentionsShare of voiceRun +
+ + {run.scope ? ( + + {scopeLabel(run.scope)} + + ) : null} + {run.competitors.length > 0 ? ( +

+ vs {run.competitors.join(", ")} +

+ ) : null} +
+ {run.totalMentions === null + ? "—" + : numberFormat.format(run.totalMentions)} + + {run.shareOfVoicePercent === null + ? "—" + : `${run.shareOfVoicePercent}%`} + + {formatWhen(run.createdAt)} + + +
+
+
+ ); +} diff --git a/src/db/ai-search.schema.ts b/src/db/ai-search.schema.ts new file mode 100644 index 000000000..9006b2905 --- /dev/null +++ b/src/db/ai-search.schema.ts @@ -0,0 +1,53 @@ +import { sql } from "drizzle-orm"; +import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; +import { projects } from "./app.schema"; + +// A saved snapshot of one Brand Lookup run. +// +// Brand Lookup is a PAID fan-out to several DataForSEO LLM-mentions endpoints, +// and its only prior memory was a 24h R2 cache plus a localStorage list of +// queries. That made the two things this feature is actually for impossible: +// seeing past runs from another browser, and comparing a run to the last one. +// Persisting the whole result means history survives the cache, follows the +// project rather than the browser, and can be re-opened without re-charging. +// +// The headline metrics are lifted into typed columns so a trend can be read +// without parsing every payload; `payload` keeps the full result for re-render. +export const brandLookupRuns = sqliteTable( + "brand_lookup_runs", + { + id: text("id").primaryKey(), + projectId: text("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), + // Exactly as typed by the user, so a saved run can be re-run identically. + query: text("query").notNull(), + // What the lookup actually resolved to (hostname, or hostname + path). + resolvedTarget: text("resolved_target").notNull(), + // Null for keyword lookups, which have no URL to scope. + scope: text("scope"), + // JSON array of competitor inputs. Part of the run's identity: the same + // brand with a different competitor set is a different (separately paid) run. + competitors: text("competitors").notNull().default("[]"), + // Nullable because a run can legitimately return no data for a target. + totalMentions: integer("total_mentions"), + totalAiSearchVolume: integer("total_ai_search_volume"), + // Our own Share of Voice as a percentage, when competitors were supplied. + shareOfVoicePercent: integer("share_of_voice_percent"), + // The complete BrandLookupResult as JSON, so a past run re-renders from + // storage instead of being re-fetched and re-charged. + payload: text("payload").notNull(), + // When the underlying data was fetched, per the result itself. + fetchedAt: text("fetched_at").notNull(), + createdAt: text("created_at") + .notNull() + .default(sql`(current_timestamp)`), + }, + (table) => [ + // Serves the only read: this project's runs, newest first. + index("brand_lookup_runs_project_created_idx").on( + table.projectId, + table.createdAt, + ), + ], +); diff --git a/src/db/d1/schema.ts b/src/db/d1/schema.ts index 41f252a9f..3522a6948 100644 --- a/src/db/d1/schema.ts +++ b/src/db/d1/schema.ts @@ -10,3 +10,4 @@ export * from "../billing.schema"; export * from "../ga4.schema"; export * from "../gsc.schema"; export * from "../telemetry.schema"; +export * from "../ai-search.schema"; diff --git a/src/db/pg/ai-search.schema.ts b/src/db/pg/ai-search.schema.ts new file mode 100644 index 000000000..7886118d8 --- /dev/null +++ b/src/db/pg/ai-search.schema.ts @@ -0,0 +1,32 @@ +import { sql } from "drizzle-orm"; +import { index, integer, pgTable, text } from "drizzle-orm/pg-core"; +import { projects } from "./app.schema"; + +const isoNow = sql`to_char(now() AT TIME ZONE 'utc', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')`; + +// Keep this definition structurally identical to ../ai-search.schema.ts. +export const brandLookupRuns = pgTable( + "brand_lookup_runs", + { + id: text("id").primaryKey(), + projectId: text("project_id") + .notNull() + .references(() => projects.id, { onDelete: "cascade" }), + query: text("query").notNull(), + resolvedTarget: text("resolved_target").notNull(), + scope: text("scope"), + competitors: text("competitors").notNull().default("[]"), + totalMentions: integer("total_mentions"), + totalAiSearchVolume: integer("total_ai_search_volume"), + shareOfVoicePercent: integer("share_of_voice_percent"), + payload: text("payload").notNull(), + fetchedAt: text("fetched_at").notNull(), + createdAt: text("created_at").notNull().default(isoNow), + }, + (table) => [ + index("brand_lookup_runs_project_created_idx").on( + table.projectId, + table.createdAt, + ), + ], +); diff --git a/src/db/pg/schema.ts b/src/db/pg/schema.ts index 5b74981a3..74adc6711 100644 --- a/src/db/pg/schema.ts +++ b/src/db/pg/schema.ts @@ -7,3 +7,4 @@ export * from "./billing.schema"; export * from "./ga4.schema"; export * from "./gsc.schema"; export * from "./telemetry.schema"; +export * from "./ai-search.schema"; diff --git a/src/db/schema-parity.test.ts b/src/db/schema-parity.test.ts index aa019409f..f86c884ee 100644 --- a/src/db/schema-parity.test.ts +++ b/src/db/schema-parity.test.ts @@ -13,6 +13,7 @@ import * as sqliteBilling from "./billing.schema"; import * as sqliteGa4 from "./ga4.schema"; import * as sqliteGsc from "./gsc.schema"; import * as sqliteTelemetry from "./telemetry.schema"; +import * as sqliteAiSearch from "./ai-search.schema"; import * as pgApp from "./pg/app.schema"; import * as pgProjectContext from "./pg/project-context.schema"; import * as pgAudit from "./pg/audit.schema"; @@ -22,6 +23,7 @@ import * as pgBilling from "./pg/billing.schema"; import * as pgGa4 from "./pg/ga4.schema"; import * as pgGsc from "./pg/gsc.schema"; import * as pgTelemetry from "./pg/telemetry.schema"; +import * as pgAiSearch from "./pg/ai-search.schema"; // Guards the ONE structural artifact `db:generate` does not regenerate: the // hand-written Postgres schema. The provider-aware `db`/`@/db/schema` barrel @@ -152,6 +154,7 @@ const sqliteAppTables = tablesFrom( sqliteGa4, sqliteGsc, sqliteTelemetry, + sqliteAiSearch, ); const pgAppTables = tablesFrom( pgApp, @@ -162,6 +165,7 @@ const pgAppTables = tablesFrom( pgGa4, pgGsc, pgTelemetry, + pgAiSearch, ); const sqliteAuthTables = tablesFrom(sqliteAuth); const pgAuthTables = tablesFrom(pgAuth); diff --git a/src/db/schema.ts b/src/db/schema.ts index 90234df22..9bd432d26 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -8,6 +8,7 @@ import * as sqliteBilling from "./billing.schema"; import * as sqliteGa4 from "./ga4.schema"; import * as sqliteGsc from "./gsc.schema"; import * as sqliteTelemetry from "./telemetry.schema"; +import * as sqliteAiSearch from "./ai-search.schema"; import * as pgApp from "./pg/app.schema"; import * as pgProjectContext from "./pg/project-context.schema"; import * as pgAudit from "./pg/audit.schema"; @@ -17,6 +18,7 @@ import * as pgBilling from "./pg/billing.schema"; import * as pgGa4 from "./pg/ga4.schema"; import * as pgGsc from "./pg/gsc.schema"; import * as pgTelemetry from "./pg/telemetry.schema"; +import * as pgAiSearch from "./pg/ai-search.schema"; // Canonical schema barrel. Repositories import their tables from here and the // provider-aware `db` from "@/db", so each repository is written ONCE for both @@ -36,7 +38,8 @@ type AppSchema = typeof sqliteApp & typeof sqliteBilling & typeof sqliteGa4 & typeof sqliteGsc & - typeof sqliteTelemetry; + typeof sqliteTelemetry & + typeof sqliteAiSearch; const runtimeSchema = getDatabaseProvider() === "postgres" @@ -50,6 +53,7 @@ const runtimeSchema = ...pgGa4, ...pgGsc, ...pgTelemetry, + ...pgAiSearch, } : { ...sqliteApp, @@ -61,6 +65,7 @@ const runtimeSchema = ...sqliteGa4, ...sqliteGsc, ...sqliteTelemetry, + ...sqliteAiSearch, }; // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- guarded by schema-parity.test.ts @@ -101,4 +106,5 @@ export const { ga4Connections, gscConnections, telemetryState, + brandLookupRuns, } = schema; diff --git a/src/server/features/ai-search/repositories/BrandLookupRunRepository.ts b/src/server/features/ai-search/repositories/BrandLookupRunRepository.ts new file mode 100644 index 000000000..2e77dee30 --- /dev/null +++ b/src/server/features/ai-search/repositories/BrandLookupRunRepository.ts @@ -0,0 +1,170 @@ +import { and, desc, eq } from "drizzle-orm"; +import { db } from "@/db"; +import { brandLookupRuns } from "@/db/schema"; +import type { BrandLookupResult } from "@/types/schemas/ai-search"; + +// Persistence for Brand Lookup runs. Every successful lookup is saved here so +// the history survives the 24h result cache, follows the project instead of one +// browser's localStorage, and can be re-opened without paying DataForSEO again. + +/** How many runs a project keeps. Old runs are pruned on write. */ +export const BRAND_LOOKUP_RUN_LIMIT = 100; + +export type BrandLookupRunSummary = { + id: string; + query: string; + resolvedTarget: string; + scope: string | null; + competitors: string[]; + totalMentions: number | null; + totalAiSearchVolume: number | null; + shareOfVoicePercent: number | null; + fetchedAt: string; + createdAt: string; +}; + +/** + * Our own Share of Voice as a whole percent, or null when no competitors were + * supplied. Stored as a column so a trend reads without parsing every payload. + */ +function ownSharePercent(result: BrandLookupResult): number | null { + const entries = result.shareOfVoice?.entries; + if (!entries?.length) return null; + const own = entries.find((entry) => entry.isTarget); + if (!own || typeof own.sharePct !== "number") return null; + return Math.round(own.sharePct); +} + +export async function saveBrandLookupRun(args: { + projectId: string; + query: string; + competitors: string[]; + result: BrandLookupResult; +}): Promise { + const id = crypto.randomUUID(); + + await db.insert(brandLookupRuns).values({ + id, + projectId: args.projectId, + query: args.query, + resolvedTarget: args.result.resolvedTarget, + scope: args.result.scope, + competitors: JSON.stringify(args.competitors), + totalMentions: args.result.totalMentions, + totalAiSearchVolume: args.result.totalAiSearchVolume, + shareOfVoicePercent: ownSharePercent(args.result), + payload: JSON.stringify(args.result), + fetchedAt: args.result.fetchedAt, + }); + + await pruneBrandLookupRuns(args.projectId); + return id; +} + +/** + * Keep the newest BRAND_LOOKUP_RUN_LIMIT runs per project. Payloads are large, + * so an unbounded table would grow without anyone noticing. + */ +async function pruneBrandLookupRuns(projectId: string): Promise { + const keep = await db + .select({ id: brandLookupRuns.id }) + .from(brandLookupRuns) + .where(eq(brandLookupRuns.projectId, projectId)) + .orderBy(desc(brandLookupRuns.createdAt)) + .limit(BRAND_LOOKUP_RUN_LIMIT); + + if (keep.length < BRAND_LOOKUP_RUN_LIMIT) return; + + const stale = await db + .select({ id: brandLookupRuns.id }) + .from(brandLookupRuns) + .where(eq(brandLookupRuns.projectId, projectId)) + .orderBy(desc(brandLookupRuns.createdAt)) + .limit(BRAND_LOOKUP_RUN_LIMIT * 2) + .offset(BRAND_LOOKUP_RUN_LIMIT); + + for (const row of stale) { + await db.delete(brandLookupRuns).where(eq(brandLookupRuns.id, row.id)); + } +} + +function parseCompetitors(raw: string): string[] { + try { + const parsed: unknown = JSON.parse(raw); + if (!Array.isArray(parsed)) return []; + return parsed.filter((v): v is string => typeof v === "string"); + } catch { + return []; + } +} + +export async function listBrandLookupRuns( + projectId: string, + limit = 25, +): Promise { + const rows = await db + .select({ + id: brandLookupRuns.id, + query: brandLookupRuns.query, + resolvedTarget: brandLookupRuns.resolvedTarget, + scope: brandLookupRuns.scope, + competitors: brandLookupRuns.competitors, + totalMentions: brandLookupRuns.totalMentions, + totalAiSearchVolume: brandLookupRuns.totalAiSearchVolume, + shareOfVoicePercent: brandLookupRuns.shareOfVoicePercent, + fetchedAt: brandLookupRuns.fetchedAt, + createdAt: brandLookupRuns.createdAt, + }) + .from(brandLookupRuns) + .where(eq(brandLookupRuns.projectId, projectId)) + .orderBy(desc(brandLookupRuns.createdAt)) + .limit(limit); + + return rows.map((row) => ({ + ...row, + competitors: parseCompetitors(row.competitors), + })); +} + +/** + * The stored result for one run, or null when there is no such run for this + * project. Returns the raw parsed payload typed as `unknown`: the caller + * validates it with brandLookupResultSchema, since a payload written by an + * older result shape must not be trusted blindly. + */ +export async function getBrandLookupRunPayload(args: { + projectId: string; + runId: string; +}): Promise { + const [row] = await db + .select({ payload: brandLookupRuns.payload }) + .from(brandLookupRuns) + .where( + and( + eq(brandLookupRuns.id, args.runId), + eq(brandLookupRuns.projectId, args.projectId), + ), + ) + .limit(1); + + if (!row) return null; + try { + return JSON.parse(row.payload); + } catch { + return null; + } +} + +export async function deleteBrandLookupRun(args: { + projectId: string; + runId: string; +}): Promise { + await db + .delete(brandLookupRuns) + .where( + and( + eq(brandLookupRuns.id, args.runId), + eq(brandLookupRuns.projectId, args.projectId), + ), + ); +} diff --git a/src/serverFunctions/ai-search.ts b/src/serverFunctions/ai-search.ts index ac090d1a9..b65b3658f 100644 --- a/src/serverFunctions/ai-search.ts +++ b/src/serverFunctions/ai-search.ts @@ -1,5 +1,12 @@ import { createServerFn } from "@tanstack/react-start"; +import { z } from "zod"; import { getBrandLookup } from "@/server/features/ai-search/services/brandLookup"; +import { + deleteBrandLookupRun, + getBrandLookupRunPayload, + listBrandLookupRuns, + saveBrandLookupRun, +} from "@/server/features/ai-search/repositories/BrandLookupRunRepository"; import { explorePrompt as runExplorePrompt } from "@/server/features/ai-search/services/promptExplorer"; import { customerHasPaidPlan } from "@/server/billing/subscription"; import { AppError } from "@/server/lib/errors"; @@ -7,6 +14,7 @@ import { isHostedServerAuthMode } from "@/server/lib/runtime-env"; import { requireProjectContext } from "@/serverFunctions/middleware"; import { brandLookupInputSchema, + brandLookupResultSchema, promptExplorerInputSchema, } from "@/types/schemas/ai-search"; @@ -29,7 +37,30 @@ export const lookupBrand = createServerFn({ method: "POST" }) .validator(brandLookupInputSchema) .handler(async ({ data, context }) => { await assertPaidPlan(context.organizationId); - return getBrandLookup({ ...data, projectId: context.projectId }, context); + const result = await getBrandLookup( + { ...data, projectId: context.projectId }, + context, + ); + + // Save every lookup that came back with data. This is the only durable + // record: the result cache expires after 24h and the old "recent searches" + // list was localStorage, so a paid run was previously unrecoverable from + // any other browser. A failed save must not fail the lookup the user just + // paid for, so it is logged and swallowed. + if (result.hasData) { + try { + await saveBrandLookupRun({ + projectId: context.projectId, + query: data.query, + competitors: data.competitors, + result, + }); + } catch (err) { + console.error("ai-search.brand-lookup.save-run failed:", err); + } + } + + return result; }); export const explorePrompt = createServerFn({ method: "POST" }) @@ -39,3 +70,49 @@ export const explorePrompt = createServerFn({ method: "POST" }) await assertPaidPlan(context.organizationId); return runExplorePrompt({ ...data, projectId: context.projectId }, context); }); + +/** + * Saved Brand Lookup runs for a project, newest first. + * + * projectId is required on every project-scoped server function: ensureUser + * resolves (and authorizes) the project from `data.projectId`, so omitting it + * fails the requireProjectContext middleware rather than defaulting to anything. + */ +export const listSavedBrandLookups = createServerFn({ method: "POST" }) + .middleware(requireProjectContext) + .validator(z.object({ projectId: z.string().min(1) })) + .handler(async ({ context }) => listBrandLookupRuns(context.projectId)); + +/** + * Re-open a saved run from storage. Costs nothing: the stored payload is + * returned instead of re-running the paid lookup. + */ +export const getSavedBrandLookup = createServerFn({ method: "POST" }) + .middleware(requireProjectContext) + .validator( + z.object({ projectId: z.string().min(1), runId: z.string().min(1) }), + ) + .handler(async ({ data, context }) => { + const payload = await getBrandLookupRunPayload({ + projectId: context.projectId, + runId: data.runId, + }); + if (payload === null) return null; + + // A payload written by an older result shape must not be trusted blindly. + const parsed = brandLookupResultSchema.safeParse(payload); + return parsed.success ? parsed.data : null; + }); + +export const removeSavedBrandLookup = createServerFn({ method: "POST" }) + .middleware(requireProjectContext) + .validator( + z.object({ projectId: z.string().min(1), runId: z.string().min(1) }), + ) + .handler(async ({ data, context }) => { + await deleteBrandLookupRun({ + projectId: context.projectId, + runId: data.runId, + }); + return { ok: true }; + });