feat(admin): apply durable runtime clock shifts

This commit is contained in:
2026-07-30 17:21:01 +00:00
parent d6904f2c9d
commit 7f31459385
23 changed files with 1889 additions and 93 deletions
+22
View File
@@ -51,6 +51,12 @@ export type TurnDaemonCommand =
| { type: 'pause'; requestId?: string; reason?: string }
| { type: 'resume'; requestId?: string; reason?: string }
| { type: 'shutdown'; requestId?: string; reason?: string }
| {
type: 'shiftSchedule';
requestId?: string;
actionId: string;
deltaMinutes: number;
}
| { type: 'getStatus'; requestId?: string }
| { type: 'troopCreate'; requestId?: string; generalId: number; troopName: string }
| { type: 'troopJoin'; requestId?: string; generalId: number; troopId: number }
@@ -214,6 +220,22 @@ export type TurnDaemonCommandResult =
commandType: TurnDaemonCommand['type'];
reason: string;
}
| {
type: 'shiftSchedule';
ok: true;
actionId: string;
deltaMinutes: number;
lastTurnTime: string;
shiftedGenerals: number;
shiftedAuctions: number;
checkpoint?: TurnCheckpoint;
}
| {
type: 'shiftSchedule';
ok: false;
actionId: string;
reason: string;
}
| {
type: 'auctionFinalize';
ok: true;
@@ -0,0 +1,42 @@
CREATE TYPE "GatewayRuntimeActionStatus" AS ENUM (
'REQUESTED',
'PARTIAL',
'APPLIED',
'FAILED',
'IGNORED'
);
CREATE TABLE "gateway_runtime_action" (
"id" TEXT NOT NULL,
"profile_name" TEXT NOT NULL,
"action" TEXT NOT NULL,
"duration_minutes" INTEGER,
"scheduled_at" TIMESTAMP(3),
"reason" TEXT,
"requested_by" TEXT NOT NULL,
"status" "GatewayRuntimeActionStatus" NOT NULL DEFAULT 'REQUESTED',
"detail" TEXT,
"handler" TEXT,
"handled_at" TIMESTAMP(3),
"attempts" INTEGER NOT NULL DEFAULT 0,
"next_attempt_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "gateway_runtime_action_pkey" PRIMARY KEY ("id"),
CONSTRAINT "gateway_runtime_action_profile_name_fkey"
FOREIGN KEY ("profile_name")
REFERENCES "gateway_profile"("profile_name")
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX "gateway_runtime_action_profile_name_status_created_at_idx"
ON "gateway_runtime_action"("profile_name", "status", "created_at");
CREATE INDEX "gateway_runtime_action_profile_name_created_at_idx"
ON "gateway_runtime_action"("profile_name", "created_at");
CREATE UNIQUE INDEX "gateway_runtime_action_one_pending_per_profile_idx"
ON "gateway_runtime_action"("profile_name")
WHERE "status" IN ('REQUESTED', 'PARTIAL');
+49 -17
View File
@@ -45,6 +45,14 @@ enum GatewayOperationStatus {
CANCELLED
}
enum GatewayRuntimeActionStatus {
REQUESTED
PARTIAL
APPLIED
FAILED
IGNORED
}
enum GatewaySourceMode {
BRANCH
COMMIT
@@ -113,32 +121,56 @@ model LegacyRootKeyValue {
}
model GatewayProfile {
profileName String @id @map("profile_name")
profileName String @id @map("profile_name")
profile String
scenario String
apiPort Int @map("api_port")
apiPort Int @map("api_port")
status GatewayProfileStatus
buildStatus GatewayBuildStatus @default(IDLE) @map("build_status")
buildCommitSha String? @map("build_commit_sha")
buildWorkspace String? @map("build_workspace")
buildLastUsedAt DateTime? @map("build_last_used_at")
preopenAt DateTime? @map("preopen_at")
openAt DateTime? @map("open_at")
scheduledStartAt DateTime? @map("scheduled_start_at")
buildRequestedAt DateTime? @map("build_requested_at")
buildStartedAt DateTime? @map("build_started_at")
buildCompletedAt DateTime? @map("build_completed_at")
buildError String? @map("build_error")
lastError String? @map("last_error")
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
buildStatus GatewayBuildStatus @default(IDLE) @map("build_status")
buildCommitSha String? @map("build_commit_sha")
buildWorkspace String? @map("build_workspace")
buildLastUsedAt DateTime? @map("build_last_used_at")
preopenAt DateTime? @map("preopen_at")
openAt DateTime? @map("open_at")
scheduledStartAt DateTime? @map("scheduled_start_at")
buildRequestedAt DateTime? @map("build_requested_at")
buildStartedAt DateTime? @map("build_started_at")
buildCompletedAt DateTime? @map("build_completed_at")
buildError String? @map("build_error")
lastError String? @map("last_error")
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
operations GatewayOperation[]
runtimeActions GatewayRuntimeAction[]
@@unique([profile, scenario])
@@map("gateway_profile")
}
model GatewayRuntimeAction {
id String @id @default(uuid())
profileName String @map("profile_name")
profile GatewayProfile @relation(fields: [profileName], references: [profileName], onDelete: Cascade)
action String
durationMinutes Int? @map("duration_minutes")
scheduledAt DateTime? @map("scheduled_at")
reason String?
requestedBy String @map("requested_by")
status GatewayRuntimeActionStatus @default(REQUESTED)
detail String?
handler String?
handledAt DateTime? @map("handled_at")
attempts Int @default(0)
nextAttemptAt DateTime? @map("next_attempt_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([profileName, status, createdAt])
@@index([profileName, createdAt])
@@map("gateway_runtime_action")
}
model GatewayOperation {
id String @id @default(uuid())
profileName String @map("profile_name")