feat: add initial migration and run it on container start
All checks were successful
Build & Deploy to K3s / build-and-deploy (push) Successful in 3m6s

Payload's postgresAdapter `push: true` only runs in dev. Prod needs
committed migrations; the container now runs `payload migrate` before
starting Next.js so the schema is created on first deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ordinarthur 2026-04-21 10:45:03 +02:00
parent bf5bf977e9
commit 955dbeb63b
4 changed files with 2473 additions and 1 deletions

View File

@ -60,4 +60,5 @@ RUN mkdir -p /app/media && chown -R nextjs:nodejs /app/media
USER nextjs
EXPOSE 3000
CMD ["node", "node_modules/next/dist/bin/next", "start"]
# Run pending migrations (idempotent) then start Next.js
CMD ["sh", "-c", "node node_modules/payload/bin.js migrate && node node_modules/next/dist/bin/next start"]

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
await db.execute(sql`
CREATE TYPE "public"."enum_products_currency" AS ENUM('EUR', 'USD');
CREATE TYPE "public"."enum_products_availability" AS ENUM('https://schema.org/InStock', 'https://schema.org/LimitedAvailability', 'https://schema.org/PreOrder', 'https://schema.org/OutOfStock');
CREATE TYPE "public"."enum_products_status" AS ENUM('draft', 'published');
CREATE TYPE "public"."enum__products_v_version_currency" AS ENUM('EUR', 'USD');
CREATE TYPE "public"."enum__products_v_version_availability" AS ENUM('https://schema.org/InStock', 'https://schema.org/LimitedAvailability', 'https://schema.org/PreOrder', 'https://schema.org/OutOfStock');
CREATE TYPE "public"."enum__products_v_version_status" AS ENUM('draft', 'published');
CREATE TABLE "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 "users" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar,
"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 "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_card_url" varchar,
"sizes_card_width" numeric,
"sizes_card_height" numeric,
"sizes_card_mime_type" varchar,
"sizes_card_filesize" numeric,
"sizes_card_filename" varchar,
"sizes_feature_url" varchar,
"sizes_feature_width" numeric,
"sizes_feature_height" numeric,
"sizes_feature_mime_type" varchar,
"sizes_feature_filesize" numeric,
"sizes_feature_filename" varchar
);
CREATE TABLE "products_images" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" varchar PRIMARY KEY NOT NULL,
"image_id" integer
);
CREATE TABLE "products" (
"id" serial PRIMARY KEY NOT NULL,
"product_display_name" varchar,
"name" varchar,
"slug" varchar,
"index" varchar,
"type" varchar,
"materials" varchar,
"year" varchar DEFAULT '2026',
"status" varchar,
"sort_order" numeric DEFAULT 0,
"is_published" boolean DEFAULT true,
"description" varchar,
"specs" varchar,
"notes" varchar,
"price" numeric,
"currency" "enum_products_currency" DEFAULT 'EUR',
"availability" "enum_products_availability" DEFAULT 'https://schema.org/InStock',
"stripe_product_i_d" varchar,
"seo_title" varchar,
"seo_description" varchar,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"_status" "enum_products_status" DEFAULT 'draft'
);
CREATE TABLE "_products_v_version_images" (
"_order" integer NOT NULL,
"_parent_id" integer NOT NULL,
"id" serial PRIMARY KEY NOT NULL,
"image_id" integer,
"_uuid" varchar
);
CREATE TABLE "_products_v" (
"id" serial PRIMARY KEY NOT NULL,
"parent_id" integer,
"version_product_display_name" varchar,
"version_name" varchar,
"version_slug" varchar,
"version_index" varchar,
"version_type" varchar,
"version_materials" varchar,
"version_year" varchar DEFAULT '2026',
"version_status" varchar,
"version_sort_order" numeric DEFAULT 0,
"version_is_published" boolean DEFAULT true,
"version_description" varchar,
"version_specs" varchar,
"version_notes" varchar,
"version_price" numeric,
"version_currency" "enum__products_v_version_currency" DEFAULT 'EUR',
"version_availability" "enum__products_v_version_availability" DEFAULT 'https://schema.org/InStock',
"version_stripe_product_i_d" varchar,
"version_seo_title" varchar,
"version_seo_description" varchar,
"version_updated_at" timestamp(3) with time zone,
"version_created_at" timestamp(3) with time zone,
"version__status" "enum__products_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,
"autosave" boolean
);
CREATE TABLE "payload_kv" (
"id" serial PRIMARY KEY NOT NULL,
"key" varchar NOT NULL,
"data" jsonb NOT NULL
);
CREATE TABLE "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_locked_documents_rels" (
"id" serial PRIMARY KEY NOT NULL,
"order" integer,
"parent_id" integer NOT NULL,
"path" varchar NOT NULL,
"users_id" integer,
"media_id" integer,
"products_id" integer
);
CREATE TABLE "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_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_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
);
CREATE TABLE "home_page" (
"id" serial PRIMARY KEY NOT NULL,
"hero_label" varchar DEFAULT '// ARCHIVE_001 — 2026',
"hero_title" varchar,
"hero_subtitle" varchar,
"hero_status" varchar,
"hero_image_id" integer,
"collection_label" varchar,
"collection_cta" varchar DEFAULT 'CLIQUER POUR OUVRIR',
"contact_label" varchar,
"contact_title" varchar,
"contact_description" varchar,
"whatsapp_number" varchar DEFAULT '33651755191' NOT NULL,
"whatsapp_button_text" varchar,
"contact_response_time" varchar,
"footer_text" varchar,
"instagram_url" varchar,
"seo_title" varchar,
"seo_description" varchar,
"updated_at" timestamp(3) with time zone,
"created_at" timestamp(3) with time zone
);
ALTER TABLE "users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "products_images" ADD CONSTRAINT "products_images_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "products_images" ADD CONSTRAINT "products_images_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_products_v_version_images" ADD CONSTRAINT "_products_v_version_images_image_id_media_id_fk" FOREIGN KEY ("image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "_products_v_version_images" ADD CONSTRAINT "_products_v_version_images_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "public"."_products_v"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "_products_v" ADD CONSTRAINT "_products_v_parent_id_products_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."products"("id") ON DELETE set null ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "public"."media"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_products_fk" FOREIGN KEY ("products_id") REFERENCES "public"."products"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "home_page" ADD CONSTRAINT "home_page_hero_image_id_media_id_fk" FOREIGN KEY ("hero_image_id") REFERENCES "public"."media"("id") ON DELETE set null ON UPDATE no action;
CREATE INDEX "users_sessions_order_idx" ON "users_sessions" USING btree ("_order");
CREATE INDEX "users_sessions_parent_id_idx" ON "users_sessions" USING btree ("_parent_id");
CREATE INDEX "users_updated_at_idx" ON "users" USING btree ("updated_at");
CREATE INDEX "users_created_at_idx" ON "users" USING btree ("created_at");
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
CREATE INDEX "media_updated_at_idx" ON "media" USING btree ("updated_at");
CREATE INDEX "media_created_at_idx" ON "media" USING btree ("created_at");
CREATE UNIQUE INDEX "media_filename_idx" ON "media" USING btree ("filename");
CREATE INDEX "media_sizes_thumbnail_sizes_thumbnail_filename_idx" ON "media" USING btree ("sizes_thumbnail_filename");
CREATE INDEX "media_sizes_card_sizes_card_filename_idx" ON "media" USING btree ("sizes_card_filename");
CREATE INDEX "media_sizes_feature_sizes_feature_filename_idx" ON "media" USING btree ("sizes_feature_filename");
CREATE INDEX "products_images_order_idx" ON "products_images" USING btree ("_order");
CREATE INDEX "products_images_parent_id_idx" ON "products_images" USING btree ("_parent_id");
CREATE INDEX "products_images_image_idx" ON "products_images" USING btree ("image_id");
CREATE UNIQUE INDEX "products_slug_idx" ON "products" USING btree ("slug");
CREATE INDEX "products_updated_at_idx" ON "products" USING btree ("updated_at");
CREATE INDEX "products_created_at_idx" ON "products" USING btree ("created_at");
CREATE INDEX "products__status_idx" ON "products" USING btree ("_status");
CREATE INDEX "_products_v_version_images_order_idx" ON "_products_v_version_images" USING btree ("_order");
CREATE INDEX "_products_v_version_images_parent_id_idx" ON "_products_v_version_images" USING btree ("_parent_id");
CREATE INDEX "_products_v_version_images_image_idx" ON "_products_v_version_images" USING btree ("image_id");
CREATE INDEX "_products_v_parent_idx" ON "_products_v" USING btree ("parent_id");
CREATE INDEX "_products_v_version_version_slug_idx" ON "_products_v" USING btree ("version_slug");
CREATE INDEX "_products_v_version_version_updated_at_idx" ON "_products_v" USING btree ("version_updated_at");
CREATE INDEX "_products_v_version_version_created_at_idx" ON "_products_v" USING btree ("version_created_at");
CREATE INDEX "_products_v_version_version__status_idx" ON "_products_v" USING btree ("version__status");
CREATE INDEX "_products_v_created_at_idx" ON "_products_v" USING btree ("created_at");
CREATE INDEX "_products_v_updated_at_idx" ON "_products_v" USING btree ("updated_at");
CREATE INDEX "_products_v_latest_idx" ON "_products_v" USING btree ("latest");
CREATE INDEX "_products_v_autosave_idx" ON "_products_v" USING btree ("autosave");
CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload_kv" USING btree ("key");
CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload_locked_documents" USING btree ("global_slug");
CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload_locked_documents" USING btree ("updated_at");
CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload_locked_documents" USING btree ("created_at");
CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload_locked_documents_rels" USING btree ("order");
CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload_locked_documents_rels" USING btree ("parent_id");
CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload_locked_documents_rels" USING btree ("path");
CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload_locked_documents_rels" USING btree ("users_id");
CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload_locked_documents_rels" USING btree ("media_id");
CREATE INDEX "payload_locked_documents_rels_products_id_idx" ON "payload_locked_documents_rels" USING btree ("products_id");
CREATE INDEX "payload_preferences_key_idx" ON "payload_preferences" USING btree ("key");
CREATE INDEX "payload_preferences_updated_at_idx" ON "payload_preferences" USING btree ("updated_at");
CREATE INDEX "payload_preferences_created_at_idx" ON "payload_preferences" USING btree ("created_at");
CREATE INDEX "payload_preferences_rels_order_idx" ON "payload_preferences_rels" USING btree ("order");
CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload_preferences_rels" USING btree ("parent_id");
CREATE INDEX "payload_preferences_rels_path_idx" ON "payload_preferences_rels" USING btree ("path");
CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload_preferences_rels" USING btree ("users_id");
CREATE INDEX "payload_migrations_updated_at_idx" ON "payload_migrations" USING btree ("updated_at");
CREATE INDEX "payload_migrations_created_at_idx" ON "payload_migrations" USING btree ("created_at");
CREATE INDEX "home_page_hero_image_idx" ON "home_page" USING btree ("hero_image_id");`)
}
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
await db.execute(sql`
DROP TABLE "users_sessions" CASCADE;
DROP TABLE "users" CASCADE;
DROP TABLE "media" CASCADE;
DROP TABLE "products_images" CASCADE;
DROP TABLE "products" CASCADE;
DROP TABLE "_products_v_version_images" CASCADE;
DROP TABLE "_products_v" CASCADE;
DROP TABLE "payload_kv" CASCADE;
DROP TABLE "payload_locked_documents" CASCADE;
DROP TABLE "payload_locked_documents_rels" CASCADE;
DROP TABLE "payload_preferences" CASCADE;
DROP TABLE "payload_preferences_rels" CASCADE;
DROP TABLE "payload_migrations" CASCADE;
DROP TABLE "home_page" CASCADE;
DROP TYPE "public"."enum_products_currency";
DROP TYPE "public"."enum_products_availability";
DROP TYPE "public"."enum_products_status";
DROP TYPE "public"."enum__products_v_version_currency";
DROP TYPE "public"."enum__products_v_version_availability";
DROP TYPE "public"."enum__products_v_version_status";`)
}

View File

@ -0,0 +1,9 @@
import * as migration_20260421_083912_initial from './20260421_083912_initial';
export const migrations = [
{
up: migration_20260421_083912_initial.up,
down: migration_20260421_083912_initial.down,
name: '20260421_083912_initial'
},
];