From 3a1e71f5b632e3ff550883de47bcc530293d6d2e Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Tue, 6 Jan 2026 15:32:51 +0900 Subject: [PATCH 1/2] feat(db): add spans_outbox table schema --- cloud/db/schema/index.ts | 7 ++- cloud/db/schema/spansOutbox.test.ts | 37 ++++++++++++ cloud/db/schema/spansOutbox.ts | 92 +++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 cloud/db/schema/spansOutbox.test.ts create mode 100644 cloud/db/schema/spansOutbox.ts diff --git a/cloud/db/schema/index.ts b/cloud/db/schema/index.ts index cae2ccfaef..87d53e252c 100644 --- a/cloud/db/schema/index.ts +++ b/cloud/db/schema/index.ts @@ -14,6 +14,7 @@ export * from "@/db/schema/traces"; export * from "@/db/schema/spans"; export * from "@/db/schema/router-requests"; export * from "@/db/schema/credit-reservations"; +export * from "@/db/schema/spansOutbox"; export type { PublicSession } from "@/db/schema/sessions"; export type { PublicUser } from "@/db/schema/users"; @@ -52,6 +53,7 @@ export type { NewCreditReservation, ReservationStatus, } from "@/db/schema/credit-reservations"; +export type { PublicSpansOutbox } from "@/db/schema/spansOutbox"; import { users } from "@/db/schema/users"; import { sessions } from "@/db/schema/sessions"; @@ -69,6 +71,7 @@ import { traces } from "@/db/schema/traces"; import { spans } from "@/db/schema/spans"; import { routerRequests } from "@/db/schema/router-requests"; import { creditReservations } from "@/db/schema/credit-reservations"; +import { spansOutbox } from "@/db/schema/spansOutbox"; export type DatabaseTable = | typeof users @@ -86,4 +89,6 @@ export type DatabaseTable = | typeof traces | typeof spans | typeof routerRequests - | typeof creditReservations; + | typeof routerRequests + | typeof creditReservations + | typeof spansOutbox; diff --git a/cloud/db/schema/spansOutbox.test.ts b/cloud/db/schema/spansOutbox.test.ts new file mode 100644 index 0000000000..c67ed34f92 --- /dev/null +++ b/cloud/db/schema/spansOutbox.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from "vitest"; +import { spansOutbox, outboxStatusEnum } from "./spansOutbox"; +import { getTableName } from "drizzle-orm"; + +describe("spansOutbox schema", () => { + describe("table definition", () => { + it("has correct table name", () => { + expect(getTableName(spansOutbox)).toBe("spans_outbox"); + }); + + it("has all required columns", () => { + const columns = Object.keys(spansOutbox); + expect(columns).toContain("id"); + expect(columns).toContain("spanId"); + expect(columns).toContain("operation"); + expect(columns).toContain("status"); + expect(columns).toContain("retryCount"); + expect(columns).toContain("lastError"); + expect(columns).toContain("lockedAt"); + expect(columns).toContain("lockedBy"); + expect(columns).toContain("createdAt"); + expect(columns).toContain("processAfter"); + expect(columns).toContain("processedAt"); + }); + }); + + describe("outboxStatusEnum", () => { + it("has all expected values", () => { + expect(outboxStatusEnum.enumValues).toEqual([ + "pending", + "processing", + "completed", + "failed", + ]); + }); + }); +}); diff --git a/cloud/db/schema/spansOutbox.ts b/cloud/db/schema/spansOutbox.ts new file mode 100644 index 0000000000..fd7e0cec87 --- /dev/null +++ b/cloud/db/schema/spansOutbox.ts @@ -0,0 +1,92 @@ +import { + pgTable, + uuid, + text, + integer, + timestamp, + pgEnum, + index, + unique, +} from "drizzle-orm/pg-core"; +import { spans } from "./spans"; + +/** + * Outbox status enum for tracking span sync state. + * + * - pending: Ready to be processed + * - processing: Currently being processed (locked) + * - completed: Successfully synced to ClickHouse + * - failed: Max retries exceeded, requires manual intervention + */ +export const outboxStatusEnum = pgEnum("outbox_status", [ + "pending", + "processing", + "completed", + "failed", +]); + +/** + * Outbox table for tracking spans to be synced to ClickHouse. + * + * Implements the Transactional Outbox pattern: + * 1. Span is inserted into PostgreSQL + * 2. Outbox row is created in the same transaction + * 3. Worker polls outbox and syncs to ClickHouse + * 4. On success, outbox status is updated to 'completed' + * + * ## v1 Limitations + * - Only INSERT operations are supported + * - UPDATE/DELETE support can be added by using the operation field + * + * ## Idempotency + * - ClickHouse side: ReplacingMergeTree + _version column + * - PostgreSQL side: (span_id, operation) unique constraint + */ +export const spansOutbox = pgTable( + "spans_outbox", + { + id: uuid("id").primaryKey().defaultRandom(), + spanId: uuid("span_id") + .notNull() + .references(() => spans.id, { onDelete: "cascade" }), + operation: text("operation").notNull().default("INSERT"), + status: outboxStatusEnum("status").notNull().default("pending"), + retryCount: integer("retry_count").notNull().default(0), + lastError: text("last_error"), + lockedAt: timestamp("locked_at"), + lockedBy: text("locked_by"), + createdAt: timestamp("created_at").defaultNow().notNull(), + processAfter: timestamp("process_after").defaultNow().notNull(), + processedAt: timestamp("processed_at"), + }, + (table) => ({ + // Idempotency: prevent duplicate operations for the same span + spanOperationUnique: unique().on(table.spanId, table.operation), + // Efficient query for processable rows + processableIdx: index("spans_outbox_processable_idx").on( + table.status, + table.processAfter, + table.retryCount + ), + // Lookup by spanId + spanIdIdx: index("spans_outbox_span_id_idx").on(table.spanId), + }) +); + +// Internal types +export type SpansOutbox = typeof spansOutbox.$inferSelect; +export type NewSpansOutbox = typeof spansOutbox.$inferInsert; + +// Public type (if needed for API responses) +export type PublicSpansOutbox = Pick< + SpansOutbox, + | "id" + | "spanId" + | "operation" + | "status" + | "retryCount" + | "lastError" + | "createdAt" + | "processAfter" + | "processedAt" +>; From a18be514dffa5ba691cd491d1e9ced9da76f46ce Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Tue, 6 Jan 2026 16:52:05 +0900 Subject: [PATCH 2/2] feat(db): add spans_outbox table schema --- .../db/migrations/0002_pink_peter_parker.sql | 19 + cloud/db/migrations/meta/0002_snapshot.json | 2117 +++++++++++++++++ cloud/db/migrations/meta/_journal.json | 7 + cloud/db/schema/index.ts | 1 - cloud/db/schema/spansOutbox.ts | 10 +- cloud/db/{schema => }/spansOutbox.test.ts | 2 +- 6 files changed, 2149 insertions(+), 7 deletions(-) create mode 100644 cloud/db/migrations/0002_pink_peter_parker.sql create mode 100644 cloud/db/migrations/meta/0002_snapshot.json rename cloud/db/{schema => }/spansOutbox.test.ts (93%) diff --git a/cloud/db/migrations/0002_pink_peter_parker.sql b/cloud/db/migrations/0002_pink_peter_parker.sql new file mode 100644 index 0000000000..616bd9e956 --- /dev/null +++ b/cloud/db/migrations/0002_pink_peter_parker.sql @@ -0,0 +1,19 @@ +CREATE TYPE "public"."outbox_status" AS ENUM('pending', 'processing', 'completed', 'failed');--> statement-breakpoint +CREATE TABLE "spans_outbox" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "span_id" uuid NOT NULL, + "operation" text DEFAULT 'INSERT' NOT NULL, + "status" "outbox_status" DEFAULT 'pending' NOT NULL, + "retry_count" integer DEFAULT 0 NOT NULL, + "last_error" text, + "locked_at" timestamp, + "locked_by" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "process_after" timestamp DEFAULT now() NOT NULL, + "processed_at" timestamp, + CONSTRAINT "spans_outbox_span_id_operation_unique" UNIQUE("span_id","operation") +); +--> statement-breakpoint +ALTER TABLE "spans_outbox" ADD CONSTRAINT "spans_outbox_span_id_spans_id_fk" FOREIGN KEY ("span_id") REFERENCES "public"."spans"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "spans_outbox_processable_idx" ON "spans_outbox" USING btree ("status","process_after","retry_count");--> statement-breakpoint +CREATE INDEX "spans_outbox_span_id_idx" ON "spans_outbox" USING btree ("span_id"); \ No newline at end of file diff --git a/cloud/db/migrations/meta/0002_snapshot.json b/cloud/db/migrations/meta/0002_snapshot.json new file mode 100644 index 0000000000..4224642e2b --- /dev/null +++ b/cloud/db/migrations/meta/0002_snapshot.json @@ -0,0 +1,2117 @@ +{ + "id": "81235f33-2a3a-40b1-b020-a50c75d49467", + "prevId": "0d9a2159-9a1e-4f1d-844b-e9881e16a775", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.annotations": { + "name": "annotations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "trace_id": { + "name": "trace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "otel_span_id": { + "name": "otel_span_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "otel_trace_id": { + "name": "otel_trace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "annotation_label", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "reasoning": { + "name": "reasoning", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "annotations_trace_id_idx": { + "name": "annotations_trace_id_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "annotations_span_id_spans_id_fk": { + "name": "annotations_span_id_spans_id_fk", + "tableFrom": "annotations", + "tableTo": "spans", + "columnsFrom": ["span_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_trace_id_traces_id_fk": { + "name": "annotations_trace_id_traces_id_fk", + "tableFrom": "annotations", + "tableTo": "traces", + "columnsFrom": ["trace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_environment_id_environments_id_fk": { + "name": "annotations_environment_id_environments_id_fk", + "tableFrom": "annotations", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_project_id_projects_id_fk": { + "name": "annotations_project_id_projects_id_fk", + "tableFrom": "annotations", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_organization_id_organizations_id_fk": { + "name": "annotations_organization_id_organizations_id_fk", + "tableFrom": "annotations", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_created_by_users_id_fk": { + "name": "annotations_created_by_users_id_fk", + "tableFrom": "annotations", + "tableTo": "users", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "annotations_span_otel_consistency_fk": { + "name": "annotations_span_otel_consistency_fk", + "tableFrom": "annotations", + "tableTo": "spans", + "columnsFrom": ["span_id", "otel_span_id"], + "columnsTo": ["id", "otel_span_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_trace_otel_consistency_fk": { + "name": "annotations_trace_otel_consistency_fk", + "tableFrom": "annotations", + "tableTo": "traces", + "columnsFrom": ["trace_id", "otel_trace_id"], + "columnsTo": ["id", "otel_trace_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_span_consistency_fk": { + "name": "annotations_span_consistency_fk", + "tableFrom": "annotations", + "tableTo": "spans", + "columnsFrom": ["organization_id", "project_id", "span_id"], + "columnsTo": ["organization_id", "project_id", "id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "annotations_trace_consistency_fk": { + "name": "annotations_trace_consistency_fk", + "tableFrom": "annotations", + "tableTo": "traces", + "columnsFrom": ["organization_id", "project_id", "trace_id"], + "columnsTo": ["organization_id", "project_id", "id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "annotations_otel_span_id_otel_trace_id_environment_id_unique": { + "name": "annotations_otel_span_id_otel_trace_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": ["otel_span_id", "otel_trace_id", "environment_id"] + }, + "annotations_span_id_environment_id_unique": { + "name": "annotations_span_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": ["span_id", "environment_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_prefix": { + "name": "key_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "ownerId": { + "name": "ownerId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_environment_id_environments_id_fk": { + "name": "api_keys_environment_id_environments_id_fk", + "tableFrom": "api_keys", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_keys_ownerId_users_id_fk": { + "name": "api_keys_ownerId_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": ["ownerId"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_environment_id_name_unique": { + "name": "api_keys_environment_id_name_unique", + "nullsNotDistinct": false, + "columns": ["environment_id", "name"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credit_reservations": { + "name": "credit_reservations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "estimated_cost_centicents": { + "name": "estimated_cost_centicents", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "reservation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "router_request_id": { + "name": "router_request_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "released_at": { + "name": "released_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "credit_reservations_customer_status_index": { + "name": "credit_reservations_customer_status_index", + "columns": [ + { + "expression": "stripe_customer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credit_reservations_expires_at_index": { + "name": "credit_reservations_expires_at_index", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"credit_reservations\".\"status\" = 'active'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credit_reservations_router_request_id_router_requests_id_fk": { + "name": "credit_reservations_router_request_id_router_requests_id_fk", + "tableFrom": "credit_reservations", + "tableTo": "router_requests", + "columnsFrom": ["router_request_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.environments": { + "name": "environments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environments_project_id_projects_id_fk": { + "name": "environments_project_id_projects_id_fk", + "tableFrom": "environments", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environments_project_id_slug_unique": { + "name": "environments_project_id_slug_unique", + "nullsNotDistinct": false, + "columns": ["project_id", "slug"] + }, + "environments_project_id_id_unique": { + "name": "environments_project_id_id_unique", + "nullsNotDistinct": false, + "columns": ["project_id", "id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.functions": { + "name": "functions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "signature_hash": { + "name": "signature_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "signature": { + "name": "signature", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "dependencies": { + "name": "dependencies", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "functions_env_name_idx": { + "name": "functions_env_name_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "functions_env_sig_hash_idx": { + "name": "functions_env_sig_hash_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "signature_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "functions_environment_id_environments_id_fk": { + "name": "functions_environment_id_environments_id_fk", + "tableFrom": "functions", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "functions_project_id_projects_id_fk": { + "name": "functions_project_id_projects_id_fk", + "tableFrom": "functions", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "functions_organization_id_organizations_id_fk": { + "name": "functions_organization_id_organizations_id_fk", + "tableFrom": "functions", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "functions_env_project_fk": { + "name": "functions_env_project_fk", + "tableFrom": "functions", + "tableTo": "environments", + "columnsFrom": ["project_id", "environment_id"], + "columnsTo": ["project_id", "id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "functions_project_org_fk": { + "name": "functions_project_org_fk", + "tableFrom": "functions", + "tableTo": "projects", + "columnsFrom": ["organization_id", "project_id"], + "columnsTo": ["organization_id", "id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "functions_environment_id_hash_unique": { + "name": "functions_environment_id_hash_unique", + "nullsNotDistinct": false, + "columns": ["environment_id", "hash"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organizations": { + "name": "organizations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organizations_slug_unique": { + "name": "organizations_slug_unique", + "nullsNotDistinct": false, + "columns": ["slug"] + }, + "organizations_stripe_customer_id_unique": { + "name": "organizations_stripe_customer_id_unique", + "nullsNotDistinct": false, + "columns": ["stripe_customer_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_memberships": { + "name": "organization_memberships", + "schema": "", + "columns": { + "member_id": { + "name": "member_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "organization_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_memberships_member_id_users_id_fk": { + "name": "organization_memberships_member_id_users_id_fk", + "tableFrom": "organization_memberships", + "tableTo": "users", + "columnsFrom": ["member_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "organization_memberships_organization_id_organizations_id_fk": { + "name": "organization_memberships_organization_id_organizations_id_fk", + "tableFrom": "organization_memberships", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "organization_memberships_member_id_organization_id_pk": { + "name": "organization_memberships_member_id_organization_id_pk", + "columns": ["member_id", "organization_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_membership_audit": { + "name": "organization_membership_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "target_id": { + "name": "target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "audit_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "previous_role": { + "name": "previous_role", + "type": "organization_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "new_role": { + "name": "new_role", + "type": "organization_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_membership_audit_organization_id_organizations_id_fk": { + "name": "organization_membership_audit_organization_id_organizations_id_fk", + "tableFrom": "organization_membership_audit", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_membership_audit_actor_id_users_id_fk": { + "name": "organization_membership_audit_actor_id_users_id_fk", + "tableFrom": "organization_membership_audit", + "tableTo": "users", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "organization_membership_audit_target_id_users_id_fk": { + "name": "organization_membership_audit_target_id_users_id_fk", + "tableFrom": "organization_membership_audit", + "tableTo": "users", + "columnsFrom": ["target_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "projects_organization_id_organizations_id_fk": { + "name": "projects_organization_id_organizations_id_fk", + "tableFrom": "projects", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "projects_created_by_user_id_users_id_fk": { + "name": "projects_created_by_user_id_users_id_fk", + "tableFrom": "projects", + "tableTo": "users", + "columnsFrom": ["created_by_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "projects_organization_id_slug_unique": { + "name": "projects_organization_id_slug_unique", + "nullsNotDistinct": false, + "columns": ["organization_id", "slug"] + }, + "projects_organization_id_id_unique": { + "name": "projects_organization_id_id_unique", + "nullsNotDistinct": false, + "columns": ["organization_id", "id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_memberships": { + "name": "project_memberships", + "schema": "", + "columns": { + "member_id": { + "name": "member_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "project_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_memberships_project_id_projects_id_fk": { + "name": "project_memberships_project_id_projects_id_fk", + "tableFrom": "project_memberships", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_memberships_member_id_organization_id_organization_memberships_member_id_organization_id_fk": { + "name": "project_memberships_member_id_organization_id_organization_memberships_member_id_organization_id_fk", + "tableFrom": "project_memberships", + "tableTo": "organization_memberships", + "columnsFrom": ["member_id", "organization_id"], + "columnsTo": ["member_id", "organization_id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "project_memberships_member_id_project_id_pk": { + "name": "project_memberships_member_id_project_id_pk", + "columns": ["member_id", "project_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_membership_audit": { + "name": "project_membership_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "target_id": { + "name": "target_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "audit_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "previous_role": { + "name": "previous_role", + "type": "project_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "new_role": { + "name": "new_role", + "type": "project_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "project_membership_audit_project_id_projects_id_fk": { + "name": "project_membership_audit_project_id_projects_id_fk", + "tableFrom": "project_membership_audit", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_membership_audit_actor_id_users_id_fk": { + "name": "project_membership_audit_actor_id_users_id_fk", + "tableFrom": "project_membership_audit", + "tableTo": "users", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "project_membership_audit_target_id_users_id_fk": { + "name": "project_membership_audit_target_id_users_id_fk", + "tableFrom": "project_membership_audit", + "tableTo": "users", + "columnsFrom": ["target_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.traces": { + "name": "traces", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "otel_trace_id": { + "name": "otel_trace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "service_name": { + "name": "service_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "service_version": { + "name": "service_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_attributes": { + "name": "resource_attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "traces_env_created_at_idx": { + "name": "traces_env_created_at_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "traces_env_service_name_idx": { + "name": "traces_env_service_name_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "service_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "traces_environment_id_environments_id_fk": { + "name": "traces_environment_id_environments_id_fk", + "tableFrom": "traces", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "traces_project_id_projects_id_fk": { + "name": "traces_project_id_projects_id_fk", + "tableFrom": "traces", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "traces_organization_id_organizations_id_fk": { + "name": "traces_organization_id_organizations_id_fk", + "tableFrom": "traces", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "traces_otel_trace_id_environment_id_unique": { + "name": "traces_otel_trace_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": ["otel_trace_id", "environment_id"] + }, + "traces_id_trace_id_environment_id_unique": { + "name": "traces_id_trace_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": ["id", "otel_trace_id", "environment_id"] + }, + "traces_id_project_id_organization_id_unique": { + "name": "traces_id_project_id_organization_id_unique", + "nullsNotDistinct": false, + "columns": ["organization_id", "project_id", "id"] + }, + "traces_id_trace_id_unique": { + "name": "traces_id_trace_id_unique", + "nullsNotDistinct": false, + "columns": ["id", "otel_trace_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.spans": { + "name": "spans", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "trace_id": { + "name": "trace_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "otel_trace_id": { + "name": "otel_trace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "otel_span_id": { + "name": "otel_span_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_span_id": { + "name": "parent_span_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "start_time_unix_nano": { + "name": "start_time_unix_nano", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "end_time_unix_nano": { + "name": "end_time_unix_nano", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "events": { + "name": "events", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "links": { + "name": "links", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "dropped_attributes_count": { + "name": "dropped_attributes_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "dropped_events_count": { + "name": "dropped_events_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "dropped_links_count": { + "name": "dropped_links_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": { + "spans_env_created_at_idx": { + "name": "spans_env_created_at_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_trace_id_idx": { + "name": "spans_trace_id_idx", + "columns": [ + { + "expression": "trace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_start_time_idx": { + "name": "spans_start_time_idx", + "columns": [ + { + "expression": "start_time_unix_nano", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_env_start_time_idx": { + "name": "spans_env_start_time_idx", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "start_time_unix_nano", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "spans_environment_id_environments_id_fk": { + "name": "spans_environment_id_environments_id_fk", + "tableFrom": "spans", + "tableTo": "environments", + "columnsFrom": ["environment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "spans_project_id_projects_id_fk": { + "name": "spans_project_id_projects_id_fk", + "tableFrom": "spans", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "spans_organization_id_organizations_id_fk": { + "name": "spans_organization_id_organizations_id_fk", + "tableFrom": "spans", + "tableTo": "organizations", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "spans_trace_consistency_fk": { + "name": "spans_trace_consistency_fk", + "tableFrom": "spans", + "tableTo": "traces", + "columnsFrom": ["trace_id", "otel_trace_id", "environment_id"], + "columnsTo": ["id", "otel_trace_id", "environment_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "spans_trace_org_consistency_fk": { + "name": "spans_trace_org_consistency_fk", + "tableFrom": "spans", + "tableTo": "traces", + "columnsFrom": ["organization_id", "project_id", "trace_id"], + "columnsTo": ["organization_id", "project_id", "id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "spans_otel_span_id_otel_trace_id_environment_id_unique": { + "name": "spans_otel_span_id_otel_trace_id_environment_id_unique", + "nullsNotDistinct": false, + "columns": ["otel_span_id", "otel_trace_id", "environment_id"] + }, + "spans_id_span_id_unique": { + "name": "spans_id_span_id_unique", + "nullsNotDistinct": false, + "columns": ["id", "otel_span_id"] + }, + "spans_id_project_id_organization_id_unique": { + "name": "spans_id_project_id_organization_id_unique", + "nullsNotDistinct": false, + "columns": ["organization_id", "project_id", "id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.router_requests": { + "name": "router_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "output_tokens": { + "name": "output_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_read_tokens": { + "name": "cache_read_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_write_tokens": { + "name": "cache_write_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "cache_write_breakdown": { + "name": "cache_write_breakdown", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost_centicents": { + "name": "cost_centicents", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "request_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "environment_id": { + "name": "environment_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "router_requests_org_created_at_index": { + "name": "router_requests_org_created_at_index", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "router_requests_environment_index": { + "name": "router_requests_environment_index", + "columns": [ + { + "expression": "environment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "router_requests_api_key_id_api_keys_id_fk": { + "name": "router_requests_api_key_id_api_keys_id_fk", + "tableFrom": "router_requests", + "tableTo": "api_keys", + "columnsFrom": ["api_key_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "router_requests_user_id_users_id_fk": { + "name": "router_requests_user_id_users_id_fk", + "tableFrom": "router_requests", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.spans_outbox": { + "name": "spans_outbox", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "span_id": { + "name": "span_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "operation": { + "name": "operation", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'INSERT'" + }, + "status": { + "name": "status", + "type": "outbox_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "retry_count": { + "name": "retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locked_at": { + "name": "locked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "locked_by": { + "name": "locked_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "process_after": { + "name": "process_after", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "spans_outbox_processable_idx": { + "name": "spans_outbox_processable_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "process_after", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "retry_count", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "spans_outbox_span_id_idx": { + "name": "spans_outbox_span_id_idx", + "columns": [ + { + "expression": "span_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "spans_outbox_span_id_spans_id_fk": { + "name": "spans_outbox_span_id_spans_id_fk", + "tableFrom": "spans_outbox", + "tableTo": "spans", + "columnsFrom": ["span_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "spans_outbox_span_id_operation_unique": { + "name": "spans_outbox_span_id_operation_unique", + "nullsNotDistinct": false, + "columns": ["span_id", "operation"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.annotation_label": { + "name": "annotation_label", + "schema": "public", + "values": ["pass", "fail"] + }, + "public.reservation_status": { + "name": "reservation_status", + "schema": "public", + "values": ["active", "released", "expired"] + }, + "public.organization_role": { + "name": "organization_role", + "schema": "public", + "values": ["OWNER", "ADMIN", "MEMBER"] + }, + "public.audit_action": { + "name": "audit_action", + "schema": "public", + "values": ["GRANT", "REVOKE", "CHANGE"] + }, + "public.project_role": { + "name": "project_role", + "schema": "public", + "values": ["ADMIN", "DEVELOPER", "VIEWER", "ANNOTATOR"] + }, + "public.request_status": { + "name": "request_status", + "schema": "public", + "values": ["pending", "success", "failure"] + }, + "public.outbox_status": { + "name": "outbox_status", + "schema": "public", + "values": ["pending", "processing", "completed", "failed"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/cloud/db/migrations/meta/_journal.json b/cloud/db/migrations/meta/_journal.json index 56efe657f1..681d176448 100644 --- a/cloud/db/migrations/meta/_journal.json +++ b/cloud/db/migrations/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1767856411068, "tag": "0001_glossy_unus", "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1767860710000, + "tag": "0002_pink_peter_parker", + "breakpoints": true } ] } diff --git a/cloud/db/schema/index.ts b/cloud/db/schema/index.ts index 87d53e252c..5f0f7471db 100644 --- a/cloud/db/schema/index.ts +++ b/cloud/db/schema/index.ts @@ -89,6 +89,5 @@ export type DatabaseTable = | typeof traces | typeof spans | typeof routerRequests - | typeof routerRequests | typeof creditReservations | typeof spansOutbox; diff --git a/cloud/db/schema/spansOutbox.ts b/cloud/db/schema/spansOutbox.ts index fd7e0cec87..d8fab50e35 100644 --- a/cloud/db/schema/spansOutbox.ts +++ b/cloud/db/schema/spansOutbox.ts @@ -61,16 +61,16 @@ export const spansOutbox = pgTable( }, (table) => ({ // Idempotency: prevent duplicate operations for the same span - spanOperationUnique: unique().on(table.spanId, table.operation), + uniqueSpanOperation: unique().on(table.spanId, table.operation), // Efficient query for processable rows - processableIdx: index("spans_outbox_processable_idx").on( + processableIndex: index("spans_outbox_processable_idx").on( table.status, table.processAfter, - table.retryCount + table.retryCount, ), // Lookup by spanId - spanIdIdx: index("spans_outbox_span_id_idx").on(table.spanId), - }) + spanIdIndex: index("spans_outbox_span_id_idx").on(table.spanId), + }), ); // Internal types diff --git a/cloud/db/schema/spansOutbox.test.ts b/cloud/db/spansOutbox.test.ts similarity index 93% rename from cloud/db/schema/spansOutbox.test.ts rename to cloud/db/spansOutbox.test.ts index c67ed34f92..f64249c2d5 100644 --- a/cloud/db/schema/spansOutbox.test.ts +++ b/cloud/db/spansOutbox.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from "vitest"; -import { spansOutbox, outboxStatusEnum } from "./spansOutbox"; +import { spansOutbox, outboxStatusEnum } from "@/db/schema/spansOutbox"; import { getTableName } from "drizzle-orm"; describe("spansOutbox schema", () => {