From d67130da2012df819186712843c20bc5d7ce59f7 Mon Sep 17 00:00:00 2001 From: Chandler Copeland Date: Thu, 19 Mar 2026 23:53:12 -0600 Subject: [PATCH] feat(05-01): extend documents schema with 4 new columns + migration 0003 - Added SignatureFieldData interface export to schema.ts - Added signatureFields (jsonb), textFillData (jsonb), assignedClientId (text), preparedFilePath (text) nullable columns to documents table - Added jsonb import to drizzle-orm/pg-core imports - Generated and applied migration 0003_cool_natasha_romanoff.sql Co-Authored-By: Claude Sonnet 4.6 --- .../drizzle/0003_cool_natasha_romanoff.sql | 4 + .../drizzle/meta/0003_snapshot.json | 289 ++++++++++++++++++ .../drizzle/meta/_journal.json | 7 + teressa-copeland-homes/src/lib/db/schema.ts | 15 +- 4 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 teressa-copeland-homes/drizzle/0003_cool_natasha_romanoff.sql create mode 100644 teressa-copeland-homes/drizzle/meta/0003_snapshot.json diff --git a/teressa-copeland-homes/drizzle/0003_cool_natasha_romanoff.sql b/teressa-copeland-homes/drizzle/0003_cool_natasha_romanoff.sql new file mode 100644 index 0000000..08220c1 --- /dev/null +++ b/teressa-copeland-homes/drizzle/0003_cool_natasha_romanoff.sql @@ -0,0 +1,4 @@ +ALTER TABLE "documents" ADD COLUMN "signature_fields" jsonb;--> statement-breakpoint +ALTER TABLE "documents" ADD COLUMN "text_fill_data" jsonb;--> statement-breakpoint +ALTER TABLE "documents" ADD COLUMN "assigned_client_id" text;--> statement-breakpoint +ALTER TABLE "documents" ADD COLUMN "prepared_file_path" text; \ No newline at end of file diff --git a/teressa-copeland-homes/drizzle/meta/0003_snapshot.json b/teressa-copeland-homes/drizzle/meta/0003_snapshot.json new file mode 100644 index 0000000..044df3c --- /dev/null +++ b/teressa-copeland-homes/drizzle/meta/0003_snapshot.json @@ -0,0 +1,289 @@ +{ + "id": "0f0c2e60-e89f-41d9-8a4f-cec2b4dfe938", + "prevId": "2b5e908a-37da-4cb2-b42e-066a7c727965", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.clients": { + "name": "clients", + "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 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.documents": { + "name": "documents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "document_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'Draft'" + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "form_template_id": { + "name": "form_template_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "signature_fields": { + "name": "signature_fields", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "text_fill_data": { + "name": "text_fill_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "assigned_client_id": { + "name": "assigned_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prepared_file_path": { + "name": "prepared_file_path", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "documents_client_id_clients_id_fk": { + "name": "documents_client_id_clients_id_fk", + "tableFrom": "documents", + "tableTo": "clients", + "columnsFrom": [ + "client_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "documents_form_template_id_form_templates_id_fk": { + "name": "documents_form_template_id_form_templates_id_fk", + "tableFrom": "documents", + "tableTo": "form_templates", + "columnsFrom": [ + "form_template_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.form_templates": { + "name": "form_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "form_templates_filename_unique": { + "name": "form_templates_filename_unique", + "nullsNotDistinct": false, + "columns": [ + "filename" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.document_status": { + "name": "document_status", + "schema": "public", + "values": [ + "Draft", + "Sent", + "Viewed", + "Signed" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/teressa-copeland-homes/drizzle/meta/_journal.json b/teressa-copeland-homes/drizzle/meta/_journal.json index 945573f..9a9524d 100644 --- a/teressa-copeland-homes/drizzle/meta/_journal.json +++ b/teressa-copeland-homes/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1773977523128, "tag": "0002_wealthy_zzzax", "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1773985969484, + "tag": "0003_cool_natasha_romanoff", + "breakpoints": true } ] } \ No newline at end of file diff --git a/teressa-copeland-homes/src/lib/db/schema.ts b/teressa-copeland-homes/src/lib/db/schema.ts index 3711a3f..c06e122 100644 --- a/teressa-copeland-homes/src/lib/db/schema.ts +++ b/teressa-copeland-homes/src/lib/db/schema.ts @@ -1,6 +1,15 @@ -import { pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { jsonb, pgEnum, pgTable, text, timestamp } from "drizzle-orm/pg-core"; import { relations } from "drizzle-orm"; +export interface SignatureFieldData { + id: string; + page: number; // 1-indexed + x: number; // PDF user space, bottom-left origin, points + y: number; // PDF user space, bottom-left origin, points + width: number; // PDF points (default: 144 — 2 inches) + height: number; // PDF points (default: 36 — 0.5 inches) +} + export const users = pgTable("users", { id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), email: text("email").notNull().unique(), @@ -42,6 +51,10 @@ export const documents = pgTable("documents", { createdAt: timestamp("created_at").defaultNow().notNull(), formTemplateId: text("form_template_id").references(() => formTemplates.id), filePath: text("file_path"), + signatureFields: jsonb("signature_fields").$type(), + textFillData: jsonb("text_fill_data").$type>(), + assignedClientId: text("assigned_client_id"), + preparedFilePath: text("prepared_file_path"), }); export const documentsRelations = relations(documents, ({ one }) => ({