PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m14s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 11s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m14s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 10s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 1m33s
Staging failed on boot with 42P01, relation "payload.users" does not exist. The schema was empty because no migration existed, and the adapter cannot create tables itself: db-postgres/connect.js gates push on NODE_ENV !== 'production', so it is inert in a deployed container regardless of config. The generated migration is schema-qualified to "payload" throughout but does not create that schema — schemaName says where tables go, it does not create anything. It only worked against the throwaway database used to generate it because the schema was created there by hand, so every real environment would have failed on the first statement. CREATE SCHEMA IF NOT EXISTS is hand-added at the top of up(), which makes it exactly the kind of edit a regeneration discards silently; a test asserts it is present and ordered before the first CREATE TABLE. payload-types.ts is now committed rather than ignored. Ignoring it meant CI typechecked against looser types than a developer with a generated copy, which is how a Record<string, unknown> cast passed CI and then failed locally the moment the file appeared. The post page uses the generated Post and Media types instead, and narrows heroImage rather than asserting it, since the field is an id at shallow depth. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017YmbBhr8s7GusjDE12hrZM
217 lines
12 KiB
TypeScript
217 lines
12 KiB
TypeScript
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
|
|
|
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
|
/*
|
|
* Hand-added, and it must survive any regeneration of this file.
|
|
*
|
|
* `schemaName: 'payload'` tells Payload where to put its tables; it does not
|
|
* create the schema. Every statement below is qualified to "payload", so on
|
|
* a database that has never run this (staging and production both), the
|
|
* whole migration fails with `schema "payload" does not exist`. The schema
|
|
* only existed on the throwaway database used to generate this because it
|
|
* was created there by hand.
|
|
*/
|
|
await db.execute(sql`CREATE SCHEMA IF NOT EXISTS "payload";`)
|
|
|
|
await db.execute(sql`
|
|
CREATE TYPE "payload"."enum_posts_status" AS ENUM('draft', 'published');
|
|
CREATE TYPE "payload"."enum__posts_v_version_status" AS ENUM('draft', 'published');
|
|
CREATE TABLE "payload"."users_sessions" (
|
|
"_order" integer NOT NULL,
|
|
"_parent_id" integer NOT NULL,
|
|
"id" varchar PRIMARY KEY NOT NULL,
|
|
"created_at" timestamp(3) with time zone,
|
|
"expires_at" timestamp(3) with time zone NOT NULL
|
|
);
|
|
|
|
CREATE TABLE "payload"."users" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"display_name" varchar DEFAULT 'Tudor' NOT NULL,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"email" varchar NOT NULL,
|
|
"reset_password_token" varchar,
|
|
"reset_password_expiration" timestamp(3) with time zone,
|
|
"salt" varchar,
|
|
"hash" varchar,
|
|
"login_attempts" numeric DEFAULT 0,
|
|
"lock_until" timestamp(3) with time zone
|
|
);
|
|
|
|
CREATE TABLE "payload"."posts" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"title" varchar,
|
|
"slug" varchar,
|
|
"published_at" timestamp(3) with time zone,
|
|
"excerpt" varchar,
|
|
"hero_image_id" integer,
|
|
"content" jsonb,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"_status" "payload"."enum_posts_status" DEFAULT 'draft'
|
|
);
|
|
|
|
CREATE TABLE "payload"."_posts_v" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"parent_id" integer,
|
|
"version_title" varchar,
|
|
"version_slug" varchar,
|
|
"version_published_at" timestamp(3) with time zone,
|
|
"version_excerpt" varchar,
|
|
"version_hero_image_id" integer,
|
|
"version_content" jsonb,
|
|
"version_updated_at" timestamp(3) with time zone,
|
|
"version_created_at" timestamp(3) with time zone,
|
|
"version__status" "payload"."enum__posts_v_version_status" DEFAULT 'draft',
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"latest" boolean
|
|
);
|
|
|
|
CREATE TABLE "payload"."media" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"alt" varchar NOT NULL,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"url" varchar,
|
|
"thumbnail_u_r_l" varchar,
|
|
"filename" varchar,
|
|
"mime_type" varchar,
|
|
"filesize" numeric,
|
|
"width" numeric,
|
|
"height" numeric,
|
|
"focal_x" numeric,
|
|
"focal_y" numeric,
|
|
"sizes_thumbnail_url" varchar,
|
|
"sizes_thumbnail_width" numeric,
|
|
"sizes_thumbnail_height" numeric,
|
|
"sizes_thumbnail_mime_type" varchar,
|
|
"sizes_thumbnail_filesize" numeric,
|
|
"sizes_thumbnail_filename" varchar,
|
|
"sizes_hero_url" varchar,
|
|
"sizes_hero_width" numeric,
|
|
"sizes_hero_height" numeric,
|
|
"sizes_hero_mime_type" varchar,
|
|
"sizes_hero_filesize" numeric,
|
|
"sizes_hero_filename" varchar
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_kv" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"key" varchar NOT NULL,
|
|
"data" jsonb NOT NULL
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_locked_documents" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"global_slug" varchar,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_locked_documents_rels" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"order" integer,
|
|
"parent_id" integer NOT NULL,
|
|
"path" varchar NOT NULL,
|
|
"users_id" integer,
|
|
"posts_id" integer,
|
|
"media_id" integer
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_preferences" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"key" varchar,
|
|
"value" jsonb,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_preferences_rels" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"order" integer,
|
|
"parent_id" integer NOT NULL,
|
|
"path" varchar NOT NULL,
|
|
"users_id" integer
|
|
);
|
|
|
|
CREATE TABLE "payload"."payload_migrations" (
|
|
"id" serial PRIMARY KEY NOT NULL,
|
|
"name" varchar,
|
|
"batch" numeric,
|
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
|
);
|
|
|
|
ALTER TABLE "payload"."users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."posts" ADD CONSTRAINT "posts_hero_image_id_media_id_fk" FOREIGN KEY ("hero_image_id") REFERENCES "payload"."media"("id") ON DELETE set null ON UPDATE no action;
|
|
ALTER TABLE "payload"."_posts_v" ADD CONSTRAINT "_posts_v_parent_id_posts_id_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."posts"("id") ON DELETE set null ON UPDATE no action;
|
|
ALTER TABLE "payload"."_posts_v" ADD CONSTRAINT "_posts_v_version_hero_image_id_media_id_fk" FOREIGN KEY ("version_hero_image_id") REFERENCES "payload"."media"("id") ON DELETE set null ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "payload"."posts"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "payload"."media"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
|
|
ALTER TABLE "payload"."payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
|
CREATE INDEX "users_sessions_order_idx" ON "payload"."users_sessions" USING btree ("_order");
|
|
CREATE INDEX "users_sessions_parent_id_idx" ON "payload"."users_sessions" USING btree ("_parent_id");
|
|
CREATE INDEX "users_updated_at_idx" ON "payload"."users" USING btree ("updated_at");
|
|
CREATE INDEX "users_created_at_idx" ON "payload"."users" USING btree ("created_at");
|
|
CREATE UNIQUE INDEX "users_email_idx" ON "payload"."users" USING btree ("email");
|
|
CREATE UNIQUE INDEX "posts_slug_idx" ON "payload"."posts" USING btree ("slug");
|
|
CREATE INDEX "posts_hero_image_idx" ON "payload"."posts" USING btree ("hero_image_id");
|
|
CREATE INDEX "posts_updated_at_idx" ON "payload"."posts" USING btree ("updated_at");
|
|
CREATE INDEX "posts_created_at_idx" ON "payload"."posts" USING btree ("created_at");
|
|
CREATE INDEX "posts__status_idx" ON "payload"."posts" USING btree ("_status");
|
|
CREATE INDEX "_posts_v_parent_idx" ON "payload"."_posts_v" USING btree ("parent_id");
|
|
CREATE INDEX "_posts_v_version_version_slug_idx" ON "payload"."_posts_v" USING btree ("version_slug");
|
|
CREATE INDEX "_posts_v_version_version_hero_image_idx" ON "payload"."_posts_v" USING btree ("version_hero_image_id");
|
|
CREATE INDEX "_posts_v_version_version_updated_at_idx" ON "payload"."_posts_v" USING btree ("version_updated_at");
|
|
CREATE INDEX "_posts_v_version_version_created_at_idx" ON "payload"."_posts_v" USING btree ("version_created_at");
|
|
CREATE INDEX "_posts_v_version_version__status_idx" ON "payload"."_posts_v" USING btree ("version__status");
|
|
CREATE INDEX "_posts_v_created_at_idx" ON "payload"."_posts_v" USING btree ("created_at");
|
|
CREATE INDEX "_posts_v_updated_at_idx" ON "payload"."_posts_v" USING btree ("updated_at");
|
|
CREATE INDEX "_posts_v_latest_idx" ON "payload"."_posts_v" USING btree ("latest");
|
|
CREATE INDEX "media_updated_at_idx" ON "payload"."media" USING btree ("updated_at");
|
|
CREATE INDEX "media_created_at_idx" ON "payload"."media" USING btree ("created_at");
|
|
CREATE UNIQUE INDEX "media_filename_idx" ON "payload"."media" USING btree ("filename");
|
|
CREATE INDEX "media_sizes_thumbnail_sizes_thumbnail_filename_idx" ON "payload"."media" USING btree ("sizes_thumbnail_filename");
|
|
CREATE INDEX "media_sizes_hero_sizes_hero_filename_idx" ON "payload"."media" USING btree ("sizes_hero_filename");
|
|
CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload"."payload_kv" USING btree ("key");
|
|
CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload"."payload_locked_documents" USING btree ("global_slug");
|
|
CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload"."payload_locked_documents" USING btree ("updated_at");
|
|
CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload"."payload_locked_documents" USING btree ("created_at");
|
|
CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload"."payload_locked_documents_rels" USING btree ("order");
|
|
CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload"."payload_locked_documents_rels" USING btree ("parent_id");
|
|
CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload"."payload_locked_documents_rels" USING btree ("path");
|
|
CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("users_id");
|
|
CREATE INDEX "payload_locked_documents_rels_posts_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("posts_id");
|
|
CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("media_id");
|
|
CREATE INDEX "payload_preferences_key_idx" ON "payload"."payload_preferences" USING btree ("key");
|
|
CREATE INDEX "payload_preferences_updated_at_idx" ON "payload"."payload_preferences" USING btree ("updated_at");
|
|
CREATE INDEX "payload_preferences_created_at_idx" ON "payload"."payload_preferences" USING btree ("created_at");
|
|
CREATE INDEX "payload_preferences_rels_order_idx" ON "payload"."payload_preferences_rels" USING btree ("order");
|
|
CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload"."payload_preferences_rels" USING btree ("parent_id");
|
|
CREATE INDEX "payload_preferences_rels_path_idx" ON "payload"."payload_preferences_rels" USING btree ("path");
|
|
CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload"."payload_preferences_rels" USING btree ("users_id");
|
|
CREATE INDEX "payload_migrations_updated_at_idx" ON "payload"."payload_migrations" USING btree ("updated_at");
|
|
CREATE INDEX "payload_migrations_created_at_idx" ON "payload"."payload_migrations" USING btree ("created_at");`)
|
|
}
|
|
|
|
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
|
await db.execute(sql`
|
|
DROP TABLE "payload"."users_sessions" CASCADE;
|
|
DROP TABLE "payload"."users" CASCADE;
|
|
DROP TABLE "payload"."posts" CASCADE;
|
|
DROP TABLE "payload"."_posts_v" CASCADE;
|
|
DROP TABLE "payload"."media" CASCADE;
|
|
DROP TABLE "payload"."payload_kv" CASCADE;
|
|
DROP TABLE "payload"."payload_locked_documents" CASCADE;
|
|
DROP TABLE "payload"."payload_locked_documents_rels" CASCADE;
|
|
DROP TABLE "payload"."payload_preferences" CASCADE;
|
|
DROP TABLE "payload"."payload_preferences_rels" CASCADE;
|
|
DROP TABLE "payload"."payload_migrations" CASCADE;
|
|
DROP TYPE "payload"."enum_posts_status";
|
|
DROP TYPE "payload"."enum__posts_v_version_status";`)
|
|
}
|