From d6904f2c9d0ee294b8f519deb66976ccc0c789b8 Mon Sep 17 00:00:00 2001 From: hided62 Date: Thu, 30 Jul 2026 17:20:52 +0000 Subject: [PATCH] fix(infra): reconcile shared Prisma migration history --- README.md | 4 ++ packages/infra/prisma/game.prisma | 6 +++ .../migration.sql | 43 ++++++++++++++++ .../migration.sql | 51 +++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 packages/infra/prisma/gateway-migrations/20260730002000_reconcile_gateway_legacy_archive/migration.sql create mode 100644 packages/infra/prisma/migrations/20260730001000_reconcile_game_legacy_archive/migration.sql diff --git a/README.md b/README.md index 3dd6c2e..52410c8 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,10 @@ pnpm --filter @sammo-ts/infra prisma:migrate:deploy:gateway pnpm migrate:legacy -- --help ``` +Game과 gateway가 같은 database/schema를 쓰므로 deploy 순서는 +`game → gateway`입니다. 양쪽 migration directory 이름은 공유 +`_prisma_migrations`에서 충돌하지 않도록 전역적으로 고유해야 합니다. + 활성 외부 prefix는 `/gateway/`, `/che/`, `/hwe/`입니다. 앱은 필요한 listener를 `0.0.0.0`에 bind하고 prefix를 보존한 frontend, tRPC, SSE, direct-navigation URL을 사용합니다. `/image/*`는 외부 Caddy가 소유합니다. diff --git a/packages/infra/prisma/game.prisma b/packages/infra/prisma/game.prisma index 308c006..5840c8a 100644 --- a/packages/infra/prisma/game.prisma +++ b/packages/infra/prisma/game.prisma @@ -29,12 +29,16 @@ enum AuctionStatus { FINALIZING FINISHED CANCELED + + @@map("auction_status") } enum AuctionType { BUY_RICE SELL_RICE UNIQUE_ITEM + + @@map("auction_type") } enum DiplomacyLetterState { @@ -42,6 +46,8 @@ enum DiplomacyLetterState { ACTIVATED CANCELLED REPLACED + + @@map("diplomacy_letter_state") } enum InputEventStatus { diff --git a/packages/infra/prisma/gateway-migrations/20260730002000_reconcile_gateway_legacy_archive/migration.sql b/packages/infra/prisma/gateway-migrations/20260730002000_reconcile_gateway_legacy_archive/migration.sql new file mode 100644 index 0000000..514c858 --- /dev/null +++ b/packages/infra/prisma/gateway-migrations/20260730002000_reconcile_gateway_legacy_archive/migration.sql @@ -0,0 +1,43 @@ +-- The game and gateway histories once used the same 20260727000000 migration +-- name. Prisma records names in one shared table, so whichever history ran +-- second skipped its different archive SQL. Reapply the gateway side +-- idempotently under a globally unique migration name. +ALTER TABLE "app_user" + ADD COLUMN IF NOT EXISTS "legacy_data" JSONB NOT NULL DEFAULT '{}'::jsonb; + +ALTER TABLE "system" + ADD COLUMN IF NOT EXISTS "registration_enabled" BOOLEAN NOT NULL DEFAULT FALSE, + ADD COLUMN IF NOT EXISTS "login_enabled" BOOLEAN NOT NULL DEFAULT FALSE, + ADD COLUMN IF NOT EXISTS "created_at" TIMESTAMP(3), + ADD COLUMN IF NOT EXISTS "updated_at" TIMESTAMP(3); + +CREATE TABLE IF NOT EXISTS "legacy_member_log" ( + "id" BIGINT PRIMARY KEY, + "member_no" INTEGER NOT NULL, + "user_id" TEXT NOT NULL, + "date" TIMESTAMP(3) NOT NULL, + "action_type" TEXT NOT NULL, + "action" JSONB +); + +CREATE INDEX IF NOT EXISTS "legacy_member_log_user_date" + ON "legacy_member_log" ("user_id", "date"); +CREATE INDEX IF NOT EXISTS "legacy_member_log_member_date" + ON "legacy_member_log" ("member_no", "date"); + +CREATE TABLE IF NOT EXISTS "legacy_banned_member" ( + "no" INTEGER PRIMARY KEY, + "hashed_email" TEXT NOT NULL UNIQUE, + "info" TEXT +); + +CREATE TABLE IF NOT EXISTS "legacy_root_key_value" ( + "id" SERIAL PRIMARY KEY, + "source_table" TEXT NOT NULL, + "namespace" TEXT NOT NULL, + "key" TEXT NOT NULL, + "value" JSONB NOT NULL, + "migrated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "legacy_root_key_value_source_namespace_key" + UNIQUE ("source_table", "namespace", "key") +); diff --git a/packages/infra/prisma/migrations/20260730001000_reconcile_game_legacy_archive/migration.sql b/packages/infra/prisma/migrations/20260730001000_reconcile_game_legacy_archive/migration.sql new file mode 100644 index 0000000..8ab2805 --- /dev/null +++ b/packages/infra/prisma/migrations/20260730001000_reconcile_game_legacy_archive/migration.sql @@ -0,0 +1,51 @@ +-- The game and gateway histories once used the same 20260727000000 migration +-- name. Prisma records names in one shared table, so whichever history ran +-- second skipped its different archive SQL. Reapply the game side idempotently. +ALTER TABLE "ng_old_nations" + ADD COLUMN IF NOT EXISTS "source_id" INTEGER NOT NULL DEFAULT 0; + +DROP INDEX IF EXISTS "ng_old_nations_server_id_nation"; +CREATE UNIQUE INDEX IF NOT EXISTS "ng_old_nations_server_nation_source" + ON "ng_old_nations" ("server_id", "nation", "source_id"); + +ALTER TABLE "yearbook_history" + ADD COLUMN IF NOT EXISTS "source_id" INTEGER NOT NULL DEFAULT 0, + ADD COLUMN IF NOT EXISTS "global_history" JSONB NOT NULL DEFAULT '[]'::jsonb, + ADD COLUMN IF NOT EXISTS "global_action" JSONB NOT NULL DEFAULT '[]'::jsonb; + +DROP INDEX IF EXISTS "yearbook_history_profile_year_month_key"; +CREATE UNIQUE INDEX IF NOT EXISTS "yearbook_history_profile_year_month_source" + ON "yearbook_history" ("profile_name", "year", "month", "source_id"); + +ALTER TABLE "inheritance_log" + ADD COLUMN IF NOT EXISTS "legacy_id" INTEGER, + ADD COLUMN IF NOT EXISTS "server_id" TEXT, + ADD COLUMN IF NOT EXISTS "log_type" TEXT NOT NULL DEFAULT 'inheritPoint'; + +CREATE UNIQUE INDEX IF NOT EXISTS "inheritance_log_legacy_id_key" + ON "inheritance_log" ("legacy_id"); + +ALTER TABLE "emperior" + ADD COLUMN IF NOT EXISTS "legacy_id" INTEGER; +CREATE UNIQUE INDEX IF NOT EXISTS "emperior_legacy_id_key" + ON "emperior" ("legacy_id"); + +ALTER TABLE "inheritance_result" + ADD COLUMN IF NOT EXISTS "legacy_id" INTEGER; +CREATE UNIQUE INDEX IF NOT EXISTS "inheritance_result_legacy_id_key" + ON "inheritance_result" ("legacy_id"); + +CREATE TABLE IF NOT EXISTS "legacy_game_storage" ( + "id" SERIAL PRIMARY KEY, + "source_id" INTEGER NOT NULL, + "namespace" TEXT NOT NULL, + "key" TEXT NOT NULL, + "value" JSONB NOT NULL, + "scope" TEXT NOT NULL, + "migrated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT "legacy_game_storage_source_id_key" UNIQUE ("source_id"), + CONSTRAINT "legacy_game_storage_namespace_key" UNIQUE ("namespace", "key") +); + +CREATE INDEX IF NOT EXISTS "legacy_game_storage_scope_namespace" + ON "legacy_game_storage" ("scope", "namespace");