feat(db): Postgres schema, migrations and defects repository (T3)

Drizzle schema for projects, defects, push_subscriptions (C8); generated
migration; a defects repository (createDefect / listRecentDefects); a
programmatic migrator; and a db:verify script. section_id is a plain string
referencing in-code board ids, no FK (ADR 0001). Verified against real
Postgres: migration applies, a defect round-trips, /api/health reports db up.
This commit is contained in:
Julien Calixte
2026-05-27 22:39:32 +02:00
parent 7a4860e111
commit 60ee7b6277
10 changed files with 334 additions and 4 deletions

View File

@@ -0,0 +1,27 @@
CREATE TABLE "defects" (
"id" uuid PRIMARY KEY NOT NULL,
"section_id" text NOT NULL,
"project_id" uuid NOT NULL,
"verbatim" text NOT NULL,
"reporter_email" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE "projects" (
"id" uuid PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "projects_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE "push_subscriptions" (
"id" uuid PRIMARY KEY NOT NULL,
"endpoint" text NOT NULL,
"p256dh" text NOT NULL,
"auth" text NOT NULL,
"reporter_email" text,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "push_subscriptions_endpoint_unique" UNIQUE("endpoint")
);
--> statement-breakpoint
ALTER TABLE "defects" ADD CONSTRAINT "defects_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE no action ON UPDATE no action;

View File

@@ -0,0 +1,181 @@
{
"id": "a68da650-95df-4918-9def-4cccec67a7bf",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.defects": {
"name": "defects",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
},
"section_id": {
"name": "section_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"project_id": {
"name": "project_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"verbatim": {
"name": "verbatim",
"type": "text",
"primaryKey": false,
"notNull": true
},
"reporter_email": {
"name": "reporter_email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"defects_project_id_projects_id_fk": {
"name": "defects_project_id_projects_id_fk",
"tableFrom": "defects",
"tableTo": "projects",
"columnsFrom": [
"project_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
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"projects_name_unique": {
"name": "projects_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.push_subscriptions": {
"name": "push_subscriptions",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"p256dh": {
"name": "p256dh",
"type": "text",
"primaryKey": false,
"notNull": true
},
"auth": {
"name": "auth",
"type": "text",
"primaryKey": false,
"notNull": true
},
"reporter_email": {
"name": "reporter_email",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"push_subscriptions_endpoint_unique": {
"name": "push_subscriptions_endpoint_unique",
"nullsNotDistinct": false,
"columns": [
"endpoint"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

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