fix(deploy): Regenerate migrations & ensure artifacts are copied

This commit is contained in:
fullsizemalt 2025-12-17 00:23:44 -08:00
parent 09a6f076d6
commit 00b8e8b627
4 changed files with 758 additions and 98 deletions

50
apps/web/Dockerfile Normal file
View file

@ -0,0 +1,50 @@
FROM oven/bun:latest AS base
# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
COPY package.json ./
RUN bun install
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build Next.js
ENV NEXT_TELEMETRY_DISABLED=1
RUN bun run build
# # Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Copy public folder
COPY --from=builder /app/public ./public
# Set permission for prerender cache
RUN mkdir .next
# Automatically leverage output traces to reduce image size
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Copy migrations and migration script
COPY --from=builder /app/drizzle ./drizzle
COPY --from=builder /app/src/db/migrate.ts ./src/db/migrate.ts
COPY --from=builder /app/src ./src
RUN bun install drizzle-orm pg dotenv
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Custom entrypoint to run migrations then start app
CMD ["sh", "-c", "bun --bun run src/db/migrate.ts && bun --bun run server.js"]

View file

@ -1,41 +1,3 @@
CREATE TABLE IF NOT EXISTS "user" (
"id" text PRIMARY KEY NOT NULL,
"name" text,
"email" text NOT NULL,
"emailVerified" timestamp,
"image" text
);
CREATE TABLE IF NOT EXISTS "pastes" (
"id" text PRIMARY KEY NOT NULL,
"title" text,
"content" text NOT NULL,
"contentType" text DEFAULT 'text/plain',
"syntax" text,
"visibility" text DEFAULT 'public',
"author_id" text,
"session_id" text,
"expires_at" timestamp,
"created_at" timestamp DEFAULT now(),
"updated_at" timestamp DEFAULT now()
);
CREATE TABLE IF NOT EXISTS "tags" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL UNIQUE,
"color" text,
"description" text
);
CREATE TABLE IF NOT EXISTS "pastes_to_tags" (
"paste_id" text NOT NULL,
"tag_id" text NOT NULL,
CONSTRAINT "pastes_to_tags_paste_id_tag_id_pk" PRIMARY KEY("paste_id", "tag_id")
);
CREATE TABLE IF NOT EXISTS "agent_sessions" (
"id" text PRIMARY KEY NOT NULL,
"title" text,
"agent_name" text,
"user_id" text,
"created_at" timestamp DEFAULT now()
);
CREATE TABLE IF NOT EXISTS "account" ( CREATE TABLE IF NOT EXISTS "account" (
"userId" text NOT NULL, "userId" text NOT NULL,
"type" text NOT NULL, "type" text NOT NULL,
@ -50,19 +12,17 @@ CREATE TABLE IF NOT EXISTS "account" (
"session_state" text, "session_state" text,
CONSTRAINT "account_provider_providerAccountId_pk" PRIMARY KEY("provider", "providerAccountId") CONSTRAINT "account_provider_providerAccountId_pk" PRIMARY KEY("provider", "providerAccountId")
); );
CREATE TABLE IF NOT EXISTS "session" ( --> statement-breakpoint
"sessionToken" text PRIMARY KEY NOT NULL, CREATE TABLE IF NOT EXISTS "agent_sessions" (
"userId" text NOT NULL, "id" text PRIMARY KEY NOT NULL,
"expires" timestamp NOT NULL "title" text,
); "agent_name" text,
CREATE TABLE IF NOT EXISTS "verificationToken" ( "user_id" text,
"identifier" text NOT NULL, "created_at" timestamp DEFAULT now()
"token" text NOT NULL,
"expires" timestamp NOT NULL,
CONSTRAINT "verificationToken_identifier_token_pk" PRIMARY KEY("identifier", "token")
); );
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "authenticator" ( CREATE TABLE IF NOT EXISTS "authenticator" (
"credentialID" text PRIMARY KEY NOT NULL UNIQUE, "credentialID" text NOT NULL,
"userId" text NOT NULL, "userId" text NOT NULL,
"providerAccountId" text NOT NULL, "providerAccountId" text NOT NULL,
"credentialPublicKey" text NOT NULL, "credentialPublicKey" text NOT NULL,
@ -70,55 +30,81 @@ CREATE TABLE IF NOT EXISTS "authenticator" (
"credentialDeviceType" text NOT NULL, "credentialDeviceType" text NOT NULL,
"credentialBackedUp" boolean NOT NULL, "credentialBackedUp" boolean NOT NULL,
"transports" text, "transports" text,
CONSTRAINT "authenticator_userId_credentialID_pk" PRIMARY KEY("userId", "credentialID") CONSTRAINT "authenticator_userId_credentialID_pk" PRIMARY KEY("userId", "credentialID"),
CONSTRAINT "authenticator_credentialID_unique" UNIQUE("credentialID")
); );
DO $$ BEGIN --> statement-breakpoint
ALTER TABLE "pastes" CREATE TABLE IF NOT EXISTS "pastes" (
ADD CONSTRAINT "pastes_author_id_user_id_fk" FOREIGN KEY ("author_id") REFERENCES "user"("id") ON DELETE "id" text PRIMARY KEY NOT NULL,
set null ON UPDATE no action; "title" text,
EXCEPTION "content" text NOT NULL,
WHEN duplicate_object THEN null; "content_type" text DEFAULT 'text/plain',
END $$; "syntax" text,
DO $$ BEGIN "visibility" text DEFAULT 'public',
ALTER TABLE "pastes" "author_id" text,
ADD CONSTRAINT "pastes_session_id_agent_sessions_id_fk" FOREIGN KEY ("session_id") REFERENCES "agent_sessions"("id") ON DELETE "session_id" text,
set null ON UPDATE no action; "expires_at" timestamp,
EXCEPTION "created_at" timestamp DEFAULT now(),
WHEN duplicate_object THEN null; "updated_at" timestamp DEFAULT now()
END $$; );
DO $$ BEGIN --> statement-breakpoint
ALTER TABLE "pastes_to_tags" CREATE TABLE IF NOT EXISTS "pastes_to_tags" (
ADD CONSTRAINT "pastes_to_tags_paste_id_pastes_id_fk" FOREIGN KEY ("paste_id") REFERENCES "pastes"("id") ON DELETE cascade ON UPDATE no action; "paste_id" text,
EXCEPTION "tag_id" text,
WHEN duplicate_object THEN null; CONSTRAINT "pastes_to_tags_paste_id_tag_id_pk" PRIMARY KEY("paste_id", "tag_id")
END $$; );
DO $$ BEGIN --> statement-breakpoint
ALTER TABLE "pastes_to_tags" CREATE TABLE IF NOT EXISTS "session" (
ADD CONSTRAINT "pastes_to_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "tags"("id") ON DELETE cascade ON UPDATE no action; "sessionToken" text PRIMARY KEY NOT NULL,
EXCEPTION "userId" text NOT NULL,
WHEN duplicate_object THEN null; "expires" timestamp NOT NULL
END $$; );
DO $$ BEGIN --> statement-breakpoint
ALTER TABLE "agent_sessions" CREATE TABLE IF NOT EXISTS "tags" (
ADD CONSTRAINT "agent_sessions_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action; "id" text PRIMARY KEY NOT NULL,
EXCEPTION "name" text NOT NULL,
WHEN duplicate_object THEN null; "color" text,
END $$; "description" text,
DO $$ BEGIN CONSTRAINT "tags_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "user" (
"id" text PRIMARY KEY NOT NULL,
"name" text,
"email" text NOT NULL,
"emailVerified" timestamp,
"image" text
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "verificationToken" (
"identifier" text NOT NULL,
"token" text NOT NULL,
"expires" timestamp NOT NULL,
CONSTRAINT "verificationToken_identifier_token_pk" PRIMARY KEY("identifier", "token")
);
--> statement-breakpoint
ALTER TABLE "account" ALTER TABLE "account"
ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action; ADD CONSTRAINT "account_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION --> statement-breakpoint
WHEN duplicate_object THEN null; ALTER TABLE "agent_sessions"
END $$; ADD CONSTRAINT "agent_sessions_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
DO $$ BEGIN --> statement-breakpoint
ALTER TABLE "session"
ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
DO $$ BEGIN
ALTER TABLE "authenticator" ALTER TABLE "authenticator"
ADD CONSTRAINT "authenticator_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action; ADD CONSTRAINT "authenticator_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION --> statement-breakpoint
WHEN duplicate_object THEN null; ALTER TABLE "pastes"
END $$; ADD CONSTRAINT "pastes_author_id_user_id_fk" FOREIGN KEY ("author_id") REFERENCES "public"."user"("id") ON DELETE
set null ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "pastes"
ADD CONSTRAINT "pastes_session_id_agent_sessions_id_fk" FOREIGN KEY ("session_id") REFERENCES "public"."agent_sessions"("id") ON DELETE
set null ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "pastes_to_tags"
ADD CONSTRAINT "pastes_to_tags_paste_id_pastes_id_fk" FOREIGN KEY ("paste_id") REFERENCES "public"."pastes"("id") ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "pastes_to_tags"
ADD CONSTRAINT "pastes_to_tags_tag_id_tags_id_fk" FOREIGN KEY ("tag_id") REFERENCES "public"."tags"("id") ON DELETE cascade ON UPDATE no action;
--> statement-breakpoint
ALTER TABLE "session"
ADD CONSTRAINT "session_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;

View file

@ -0,0 +1,611 @@
{
"id": "f6b95186-510d-43a2-b8c9-40511244786f",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.account": {
"name": "account",
"schema": "",
"columns": {
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"providerAccountId": {
"name": "providerAccountId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"token_type": {
"name": "token_type",
"type": "text",
"primaryKey": false,
"notNull": false
},
"scope": {
"name": "scope",
"type": "text",
"primaryKey": false,
"notNull": false
},
"id_token": {
"name": "id_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"session_state": {
"name": "session_state",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"account_userId_user_id_fk": {
"name": "account_userId_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_providerAccountId_pk": {
"name": "account_provider_providerAccountId_pk",
"columns": [
"provider",
"providerAccountId"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.agent_sessions": {
"name": "agent_sessions",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false
},
"agent_name": {
"name": "agent_name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"agent_sessions_user_id_user_id_fk": {
"name": "agent_sessions_user_id_user_id_fk",
"tableFrom": "agent_sessions",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.authenticator": {
"name": "authenticator",
"schema": "",
"columns": {
"credentialID": {
"name": "credentialID",
"type": "text",
"primaryKey": false,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"providerAccountId": {
"name": "providerAccountId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"credentialPublicKey": {
"name": "credentialPublicKey",
"type": "text",
"primaryKey": false,
"notNull": true
},
"counter": {
"name": "counter",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"credentialDeviceType": {
"name": "credentialDeviceType",
"type": "text",
"primaryKey": false,
"notNull": true
},
"credentialBackedUp": {
"name": "credentialBackedUp",
"type": "boolean",
"primaryKey": false,
"notNull": true
},
"transports": {
"name": "transports",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"authenticator_userId_user_id_fk": {
"name": "authenticator_userId_user_id_fk",
"tableFrom": "authenticator",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"authenticator_userId_credentialID_pk": {
"name": "authenticator_userId_credentialID_pk",
"columns": [
"userId",
"credentialID"
]
}
},
"uniqueConstraints": {
"authenticator_credentialID_unique": {
"name": "authenticator_credentialID_unique",
"nullsNotDistinct": false,
"columns": [
"credentialID"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.pastes": {
"name": "pastes",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"title": {
"name": "title",
"type": "text",
"primaryKey": false,
"notNull": false
},
"content": {
"name": "content",
"type": "text",
"primaryKey": false,
"notNull": true
},
"content_type": {
"name": "content_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'text/plain'"
},
"syntax": {
"name": "syntax",
"type": "text",
"primaryKey": false,
"notNull": false
},
"visibility": {
"name": "visibility",
"type": "text",
"primaryKey": false,
"notNull": false,
"default": "'public'"
},
"author_id": {
"name": "author_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"session_id": {
"name": "session_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"expires_at": {
"name": "expires_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": {
"pastes_author_id_user_id_fk": {
"name": "pastes_author_id_user_id_fk",
"tableFrom": "pastes",
"tableTo": "user",
"columnsFrom": [
"author_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"pastes_session_id_agent_sessions_id_fk": {
"name": "pastes_session_id_agent_sessions_id_fk",
"tableFrom": "pastes",
"tableTo": "agent_sessions",
"columnsFrom": [
"session_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.pastes_to_tags": {
"name": "pastes_to_tags",
"schema": "",
"columns": {
"paste_id": {
"name": "paste_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tag_id": {
"name": "tag_id",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"pastes_to_tags_paste_id_pastes_id_fk": {
"name": "pastes_to_tags_paste_id_pastes_id_fk",
"tableFrom": "pastes_to_tags",
"tableTo": "pastes",
"columnsFrom": [
"paste_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"pastes_to_tags_tag_id_tags_id_fk": {
"name": "pastes_to_tags_tag_id_tags_id_fk",
"tableFrom": "pastes_to_tags",
"tableTo": "tags",
"columnsFrom": [
"tag_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"pastes_to_tags_paste_id_tag_id_pk": {
"name": "pastes_to_tags_paste_id_tag_id_pk",
"columns": [
"paste_id",
"tag_id"
]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.session": {
"name": "session",
"schema": "",
"columns": {
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"session_userId_user_id_fk": {
"name": "session_userId_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"userId"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.tags": {
"name": "tags",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"color": {
"name": "color",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"tags_name_unique": {
"name": "tags_name_unique",
"nullsNotDistinct": false,
"columns": [
"name"
]
}
},
"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": false
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"emailVerified": {
"name": "emailVerified",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.verificationToken": {
"name": "verificationToken",
"schema": "",
"columns": {
"identifier": {
"name": "identifier",
"type": "text",
"primaryKey": false,
"notNull": true
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expires": {
"name": "expires",
"type": "timestamp",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"name": "verificationToken_identifier_token_pk",
"columns": [
"identifier",
"token"
]
}
},
"uniqueConstraints": {},
"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": 1765959773637,
"tag": "0000_busy_bill_hollister",
"breakpoints": true
}
]
}