feat: 오픈 게임 취소와 유산 정산 경로 추가
별도 최고위험 권한으로 실행되는 원자적 취소 작업을 추가한다. 버려진 게임과 장수 기록의 보존·삭제 옵션, 오픈 원금 전액 환급 및 획득 포인트 보전율, 취소 상태와 관리자·과거기록 UI를 함께 반영한다.
This commit is contained in:
@@ -4,6 +4,7 @@ export const GATEWAY_PROFILE_STATUSES = [
|
||||
'RUNNING',
|
||||
'PAUSED',
|
||||
'COMPLETED',
|
||||
'CANCELLED',
|
||||
'STOPPED',
|
||||
'DISABLED',
|
||||
] as const;
|
||||
@@ -52,6 +53,12 @@ const CAPABILITIES: Record<GatewayProfileStatus, GatewayProfileCapabilities> = {
|
||||
turnsRunning: false,
|
||||
operatorResumable: false,
|
||||
},
|
||||
CANCELLED: {
|
||||
runtimeExpected: false,
|
||||
userAccessible: false,
|
||||
turnsRunning: false,
|
||||
operatorResumable: false,
|
||||
},
|
||||
STOPPED: {
|
||||
runtimeExpected: false,
|
||||
userAccessible: false,
|
||||
|
||||
@@ -21,6 +21,6 @@ describe('gateway profile status capabilities', () => {
|
||||
});
|
||||
|
||||
it('defines capabilities for every persisted status', () => {
|
||||
expect(GATEWAY_PROFILE_STATUSES.map((status) => gatewayProfileCapabilities(status))).toHaveLength(7);
|
||||
expect(GATEWAY_PROFILE_STATUSES.map((status) => gatewayProfileCapabilities(status))).toHaveLength(8);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -375,22 +375,74 @@ model HallOfFame {
|
||||
@@map("hall")
|
||||
}
|
||||
|
||||
enum GameHistoryStatus {
|
||||
OPEN
|
||||
COMPLETED
|
||||
ABANDONED
|
||||
}
|
||||
|
||||
enum GameCancellationHistoryMode {
|
||||
RETAIN_ABANDONED
|
||||
DELETE
|
||||
}
|
||||
|
||||
enum GameCancellationGeneralMode {
|
||||
RETAIN
|
||||
DELETE
|
||||
}
|
||||
|
||||
model GameHistory {
|
||||
id Int @id @default(autoincrement())
|
||||
serverId String @map("server_id")
|
||||
id Int @id @default(autoincrement())
|
||||
serverId String @map("server_id")
|
||||
date DateTime
|
||||
winnerNation Int? @map("winner_nation")
|
||||
map String? @map("map")
|
||||
winnerNation Int? @map("winner_nation")
|
||||
map String? @map("map")
|
||||
season Int
|
||||
scenario Int
|
||||
scenarioName String @map("scenario_name")
|
||||
env Json @default(dbgenerated("'{}'::jsonb"))
|
||||
scenarioName String @map("scenario_name")
|
||||
status GameHistoryStatus @default(OPEN)
|
||||
env Json @default(dbgenerated("'{}'::jsonb"))
|
||||
|
||||
@@unique([serverId])
|
||||
@@index([date])
|
||||
@@map("ng_games")
|
||||
}
|
||||
|
||||
model GameInheritanceBaseline {
|
||||
serverId String @map("server_id")
|
||||
userId String @map("user_id")
|
||||
openingPoint Float @map("opening_point")
|
||||
source String @default("OPENING")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@id([serverId, userId])
|
||||
@@index([userId, createdAt])
|
||||
@@map("game_inheritance_baseline")
|
||||
}
|
||||
|
||||
model GameCancellation {
|
||||
id String @id
|
||||
serverId String @unique @map("server_id")
|
||||
originalSeason Int @map("original_season")
|
||||
scenario Int
|
||||
scenarioName String @map("scenario_name")
|
||||
openedAt DateTime @map("opened_at")
|
||||
cancelledAt DateTime @map("cancelled_at")
|
||||
cancelledBy String @map("cancelled_by")
|
||||
reason String
|
||||
historyMode GameCancellationHistoryMode @map("history_mode")
|
||||
generalMode GameCancellationGeneralMode @map("general_mode")
|
||||
earnedPointRetentionPercent Int @map("earned_point_retention_percent")
|
||||
participantCount Int @map("participant_count")
|
||||
preservedGeneralCount Int @map("preserved_general_count")
|
||||
settlement Json @default(dbgenerated("'{}'::jsonb"))
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@index([cancelledAt])
|
||||
@@map("game_cancellation")
|
||||
}
|
||||
|
||||
model OldNation {
|
||||
id Int @id @default(autoincrement())
|
||||
serverId String @map("server_id")
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TYPE "GatewayProfileStatus" ADD VALUE IF NOT EXISTS 'CANCELLED';
|
||||
ALTER TYPE "GatewayOperationType" ADD VALUE IF NOT EXISTS 'CANCEL_GAME';
|
||||
@@ -19,6 +19,7 @@ enum GatewayProfileStatus {
|
||||
RUNNING
|
||||
PAUSED
|
||||
COMPLETED
|
||||
CANCELLED
|
||||
STOPPED
|
||||
DISABLED
|
||||
}
|
||||
@@ -34,6 +35,7 @@ enum GatewayBuildStatus {
|
||||
enum GatewayOperationType {
|
||||
RESET
|
||||
DEPLOY
|
||||
CANCEL_GAME
|
||||
START
|
||||
STOP
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
CREATE TYPE "GameHistoryStatus" AS ENUM ('OPEN', 'COMPLETED', 'ABANDONED');
|
||||
CREATE TYPE "GameCancellationHistoryMode" AS ENUM ('RETAIN_ABANDONED', 'DELETE');
|
||||
CREATE TYPE "GameCancellationGeneralMode" AS ENUM ('RETAIN', 'DELETE');
|
||||
|
||||
ALTER TABLE "ng_games"
|
||||
ADD COLUMN "status" "GameHistoryStatus" NOT NULL DEFAULT 'OPEN';
|
||||
|
||||
UPDATE "ng_games"
|
||||
SET "status" = 'COMPLETED'
|
||||
WHERE "winner_nation" IS NOT NULL;
|
||||
|
||||
CREATE TABLE "game_inheritance_baseline" (
|
||||
"server_id" TEXT NOT NULL,
|
||||
"user_id" TEXT NOT NULL,
|
||||
"opening_point" DOUBLE PRECISION NOT NULL,
|
||||
"source" TEXT NOT NULL DEFAULT 'OPENING',
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "game_inheritance_baseline_pkey" PRIMARY KEY ("server_id", "user_id")
|
||||
);
|
||||
|
||||
CREATE INDEX "game_inheritance_baseline_user_id_created_at_idx"
|
||||
ON "game_inheritance_baseline"("user_id", "created_at");
|
||||
|
||||
CREATE TABLE "game_cancellation" (
|
||||
"id" TEXT NOT NULL,
|
||||
"server_id" TEXT NOT NULL,
|
||||
"original_season" INTEGER NOT NULL,
|
||||
"scenario" INTEGER NOT NULL,
|
||||
"scenario_name" TEXT NOT NULL,
|
||||
"opened_at" TIMESTAMP(3) NOT NULL,
|
||||
"cancelled_at" TIMESTAMP(3) NOT NULL,
|
||||
"cancelled_by" TEXT NOT NULL,
|
||||
"reason" TEXT NOT NULL,
|
||||
"history_mode" "GameCancellationHistoryMode" NOT NULL,
|
||||
"general_mode" "GameCancellationGeneralMode" NOT NULL,
|
||||
"earned_point_retention_percent" INTEGER NOT NULL,
|
||||
"participant_count" INTEGER NOT NULL,
|
||||
"preserved_general_count" INTEGER NOT NULL,
|
||||
"settlement" JSONB NOT NULL DEFAULT '{}',
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "game_cancellation_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "game_cancellation_server_id_key" ON "game_cancellation"("server_id");
|
||||
CREATE INDEX "game_cancellation_cancelled_at_idx" ON "game_cancellation"("cancelled_at");
|
||||
|
||||
ALTER TABLE "game_cancellation"
|
||||
ADD CONSTRAINT "game_cancellation_retention_percent_check"
|
||||
CHECK ("earned_point_retention_percent" BETWEEN 0 AND 100);
|
||||
@@ -21,6 +21,8 @@ export interface DatabaseClient {
|
||||
rankData: GamePrisma.RankDataDelegate;
|
||||
hallOfFame: GamePrisma.HallOfFameDelegate;
|
||||
gameHistory: GamePrisma.GameHistoryDelegate;
|
||||
gameInheritanceBaseline: GamePrisma.GameInheritanceBaselineDelegate;
|
||||
gameCancellation: GamePrisma.GameCancellationDelegate;
|
||||
oldNation: GamePrisma.OldNationDelegate;
|
||||
oldGeneral: GamePrisma.OldGeneralDelegate;
|
||||
emperor: GamePrisma.EmperorDelegate;
|
||||
|
||||
Reference in New Issue
Block a user