Commit the first migration, and apply schema the same way everywhere

`drizzle/` was gitignored, so every environment re-derived the schema from
src/db/schema and nothing recorded what a given release expected. That is
survivable while nothing is deployed and a problem the moment something is.
The generated migration is now committed: four tables, three enums, five
foreign keys, and the per-farm unique index on gateway_printer_id.

It needed one hand-added line to be usable on its own. drizzle-kit does not
emit extension statements, but frame_embeddings.embedding is vector(512) with
an ivfflat index, so as generated the migration only applied to a database
somebody had already run `CREATE EXTENSION vector` on - which was true locally
precisely because dev-env.sh does that, and would not have been true on a
fresh deploy. `CREATE EXTENSION IF NOT EXISTS vector` now leads the file, and
it survives regeneration: drizzle only appends new migrations, and the diffing
snapshot lives in meta/0000_snapshot.json rather than in the SQL.

Verified by dropping the database, recreating it with no extensions at all
(`pg_extension` count 0), and running db:migrate: the extension and all four
tables were created, `db:generate` then reported no pending changes, and the
e2e script still passed against both live printers on the result.

`dev-env.sh schema` now runs `migrate` instead of `push`, so a local database
and a deployed one get the schema by the same route - testing `push` locally
while production runs `migrate` tests two different things. `push` is still
available as its own command for iterating on a table that is still moving,
with a comment about what it does not record.
This commit is contained in:
2026-10-03 15:17:42 +00:00
parent 42d4b3820a
commit d827b465cf
6 changed files with 715 additions and 11 deletions
+126
View File
@@ -0,0 +1,126 @@
-- Hand-added to the generated migration: drizzle-kit does not emit extension
-- statements, but frame_embeddings.embedding is vector(512) and its index is
-- ivfflat, so this migration cannot apply to a database without pgvector. A
-- committed migration has to stand on its own - relying on whoever set the
-- database up having run this first is how a deploy fails.
--
-- Safe to keep across regeneration: drizzle only ever appends new files, and
-- the diffing snapshot lives in meta/0000_snapshot.json, not here.
CREATE EXTENSION IF NOT EXISTS vector;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "public"."printer_status" AS ENUM('offline', 'idle', 'printing', 'paused', 'error', 'maintenance');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "public"."printer_vendor" AS ENUM('bambu', 'prusa', 'klipper');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "public"."print_job_status" AS ENUM('queued', 'uploading', 'printing', 'paused', 'completed', 'failed', 'cancelled');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "farms" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"name" text NOT NULL,
"owner_id" uuid NOT NULL,
"edge_proxy_token" text NOT NULL,
"location" text,
"settings" jsonb DEFAULT '{}'::jsonb,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "printers" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"farm_id" uuid NOT NULL,
"name" text NOT NULL,
"vendor" "printer_vendor" NOT NULL,
"status" "printer_status" DEFAULT 'offline' NOT NULL,
"lan_address" text,
"serial_number" text,
"access_code" text,
"gateway_printer_id" text,
"nozzle_temp_c" real,
"nozzle_target_temp_c" real,
"bed_temp_c" real,
"bed_target_temp_c" real,
"progress_percent" integer,
"current_layer" integer,
"total_layers" integer,
"remaining_minutes" integer,
"current_job_name" text,
"active_alerts" integer,
"vendor_state" text,
"vendor_error_code" integer,
"metadata" jsonb DEFAULT '{}'::jsonb,
"last_seen_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "print_jobs" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"farm_id" uuid NOT NULL,
"printer_id" uuid,
"file_name" text NOT NULL,
"r2_object_key" text NOT NULL,
"status" "print_job_status" DEFAULT 'queued' NOT NULL,
"progress_pct" real DEFAULT 0 NOT NULL,
"estimated_time_s" real,
"elapsed_time_s" real,
"submitted_by" uuid NOT NULL,
"metadata" jsonb DEFAULT '{}'::jsonb,
"started_at" timestamp with time zone,
"completed_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "frame_embeddings" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"print_job_id" uuid NOT NULL,
"printer_id" uuid NOT NULL,
"r2_object_key" text NOT NULL,
"embedding" vector(512) NOT NULL,
"captured_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "printers" ADD CONSTRAINT "printers_farm_id_farms_id_fk" FOREIGN KEY ("farm_id") REFERENCES "public"."farms"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "print_jobs" ADD CONSTRAINT "print_jobs_farm_id_farms_id_fk" FOREIGN KEY ("farm_id") REFERENCES "public"."farms"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "print_jobs" ADD CONSTRAINT "print_jobs_printer_id_printers_id_fk" FOREIGN KEY ("printer_id") REFERENCES "public"."printers"("id") ON DELETE set null ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "frame_embeddings" ADD CONSTRAINT "frame_embeddings_print_job_id_print_jobs_id_fk" FOREIGN KEY ("print_job_id") REFERENCES "public"."print_jobs"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "frame_embeddings" ADD CONSTRAINT "frame_embeddings_printer_id_printers_id_fk" FOREIGN KEY ("printer_id") REFERENCES "public"."printers"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE UNIQUE INDEX IF NOT EXISTS "printers_farm_gateway_printer_id_idx" ON "printers" USING btree ("farm_id","gateway_printer_id");--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "frame_embeddings_embedding_ivfflat_idx" ON "frame_embeddings" USING ivfflat ("embedding" vector_cosine_ops) WITH (lists=100);
+544
View File
@@ -0,0 +1,544 @@
{
"id": "f60fed84-9b69-403f-a789-9e29cee970f1",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.farms": {
"name": "farms",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"owner_id": {
"name": "owner_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"edge_proxy_token": {
"name": "edge_proxy_token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"location": {
"name": "location",
"type": "text",
"primaryKey": false,
"notNull": false
},
"settings": {
"name": "settings",
"type": "jsonb",
"primaryKey": false,
"notNull": false,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.printers": {
"name": "printers",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"farm_id": {
"name": "farm_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"vendor": {
"name": "vendor",
"type": "printer_vendor",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "printer_status",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'offline'"
},
"lan_address": {
"name": "lan_address",
"type": "text",
"primaryKey": false,
"notNull": false
},
"serial_number": {
"name": "serial_number",
"type": "text",
"primaryKey": false,
"notNull": false
},
"access_code": {
"name": "access_code",
"type": "text",
"primaryKey": false,
"notNull": false
},
"gateway_printer_id": {
"name": "gateway_printer_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"nozzle_temp_c": {
"name": "nozzle_temp_c",
"type": "real",
"primaryKey": false,
"notNull": false
},
"nozzle_target_temp_c": {
"name": "nozzle_target_temp_c",
"type": "real",
"primaryKey": false,
"notNull": false
},
"bed_temp_c": {
"name": "bed_temp_c",
"type": "real",
"primaryKey": false,
"notNull": false
},
"bed_target_temp_c": {
"name": "bed_target_temp_c",
"type": "real",
"primaryKey": false,
"notNull": false
},
"progress_percent": {
"name": "progress_percent",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"current_layer": {
"name": "current_layer",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"total_layers": {
"name": "total_layers",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"remaining_minutes": {
"name": "remaining_minutes",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"current_job_name": {
"name": "current_job_name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"active_alerts": {
"name": "active_alerts",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"vendor_state": {
"name": "vendor_state",
"type": "text",
"primaryKey": false,
"notNull": false
},
"vendor_error_code": {
"name": "vendor_error_code",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"primaryKey": false,
"notNull": false,
"default": "'{}'::jsonb"
},
"last_seen_at": {
"name": "last_seen_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"printers_farm_gateway_printer_id_idx": {
"name": "printers_farm_gateway_printer_id_idx",
"columns": [
{
"expression": "farm_id",
"isExpression": false,
"asc": true,
"nulls": "last"
},
{
"expression": "gateway_printer_id",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": true,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"printers_farm_id_farms_id_fk": {
"name": "printers_farm_id_farms_id_fk",
"tableFrom": "printers",
"tableTo": "farms",
"columnsFrom": [
"farm_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.print_jobs": {
"name": "print_jobs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"farm_id": {
"name": "farm_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"printer_id": {
"name": "printer_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"file_name": {
"name": "file_name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"r2_object_key": {
"name": "r2_object_key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "print_job_status",
"typeSchema": "public",
"primaryKey": false,
"notNull": true,
"default": "'queued'"
},
"progress_pct": {
"name": "progress_pct",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"estimated_time_s": {
"name": "estimated_time_s",
"type": "real",
"primaryKey": false,
"notNull": false
},
"elapsed_time_s": {
"name": "elapsed_time_s",
"type": "real",
"primaryKey": false,
"notNull": false
},
"submitted_by": {
"name": "submitted_by",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"metadata": {
"name": "metadata",
"type": "jsonb",
"primaryKey": false,
"notNull": false,
"default": "'{}'::jsonb"
},
"started_at": {
"name": "started_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"completed_at": {
"name": "completed_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"print_jobs_farm_id_farms_id_fk": {
"name": "print_jobs_farm_id_farms_id_fk",
"tableFrom": "print_jobs",
"tableTo": "farms",
"columnsFrom": [
"farm_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"print_jobs_printer_id_printers_id_fk": {
"name": "print_jobs_printer_id_printers_id_fk",
"tableFrom": "print_jobs",
"tableTo": "printers",
"columnsFrom": [
"printer_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.frame_embeddings": {
"name": "frame_embeddings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"print_job_id": {
"name": "print_job_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"printer_id": {
"name": "printer_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"r2_object_key": {
"name": "r2_object_key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"embedding": {
"name": "embedding",
"type": "vector(512)",
"primaryKey": false,
"notNull": true
},
"captured_at": {
"name": "captured_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"frame_embeddings_embedding_ivfflat_idx": {
"name": "frame_embeddings_embedding_ivfflat_idx",
"columns": [
{
"expression": "embedding",
"isExpression": false,
"asc": true,
"nulls": "last",
"opclass": "vector_cosine_ops"
}
],
"isUnique": false,
"concurrently": false,
"method": "ivfflat",
"with": {
"lists": 100
}
}
},
"foreignKeys": {
"frame_embeddings_print_job_id_print_jobs_id_fk": {
"name": "frame_embeddings_print_job_id_print_jobs_id_fk",
"tableFrom": "frame_embeddings",
"tableTo": "print_jobs",
"columnsFrom": [
"print_job_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"frame_embeddings_printer_id_printers_id_fk": {
"name": "frame_embeddings_printer_id_printers_id_fk",
"tableFrom": "frame_embeddings",
"tableTo": "printers",
"columnsFrom": [
"printer_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"public.printer_status": {
"name": "printer_status",
"schema": "public",
"values": [
"offline",
"idle",
"printing",
"paused",
"error",
"maintenance"
]
},
"public.printer_vendor": {
"name": "printer_vendor",
"schema": "public",
"values": [
"bambu",
"prusa",
"klipper"
]
},
"public.print_job_status": {
"name": "print_job_status",
"schema": "public",
"values": [
"queued",
"uploading",
"printing",
"paused",
"completed",
"failed",
"cancelled"
]
}
},
"schemas": {},
"sequences": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1791029521420,
"tag": "0000_watery_firedrake",
"breakpoints": true
}
]
}