chore: test deploy snapshot

This commit is contained in:
2026-05-27 10:43:01 +09:00
parent c1d0f4c1db
commit 4c4b3c8d2c
78 changed files with 10392 additions and 2301 deletions

View File

@@ -2,7 +2,15 @@ import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { z } from 'zod';
import { env } from '../config/env.js';
import { getSharedResourceTokenDetailBySharePath } from '../services/shared-resource-token-service.js';
import { listServerCommands, restartServerCommand, serverCommandKeys } from '../services/server-command-service.js';
import {
deployTestServerCommand,
deployWorkServerCommand,
listServerCommands,
readWorkServerDeploymentState,
restartServerCommand,
serverCommandKeys,
} from '../services/server-command-service.js';
import { readTestServerDeploymentState } from '../services/test-server-deployment-service.js';
import {
cancelServerRestartReservation,
confirmServerRestartReservation,
@@ -43,16 +51,7 @@ function getImmediateRestartBlockInfo(
}
if (key === 'work-server') {
const pendingCount = codexPendingCount + automationPendingCount;
if (pendingCount === 0) {
return null;
}
return {
pendingCount,
message: `진행 중인 Codex Live/자동화 작업 ${pendingCount}건이 있어 즉시 재기동할 수 없습니다. 재기동 예약을 사용해 주세요.`,
};
return null;
}
return null;
@@ -92,7 +91,7 @@ async function resolveSharedServerCommandAccessContext(request: FastifyRequest)
return {
scope: 'shared' as const,
allowedKeys: new Set<string>(['work-server']),
allowedKeys: new Set<string>(['work-server', 'test']),
};
}
@@ -182,6 +181,12 @@ export async function registerServerCommandRoutes(app: FastifyInstance) {
};
} catch (error) {
const message = error instanceof Error ? error.message : '서버 재기동에 실패했습니다.';
const statusCode = error && typeof error === 'object' && 'statusCode' in error ? Number((error as { statusCode?: unknown }).statusCode) : null;
if (statusCode === 409) {
reply.status(409);
return { ok: false, message };
}
if (key !== 'test' && key !== 'work-server') {
throw error;
@@ -207,6 +212,99 @@ export async function registerServerCommandRoutes(app: FastifyInstance) {
}
});
app.get('/api/server-commands/work-server/deployment', async (request, reply) => {
const accessContext = await resolveServerCommandAccessContext(request);
if (!accessContext) {
sendAccessDenied(reply);
return;
}
if (accessContext.scope !== 'full' && !accessContext.allowedKeys.has('work-server')) {
reply.status(403);
return { ok: false, message: '현재 공유채팅 링크로는 WORK 서버 배포 상태를 확인할 수 없습니다.' };
}
return {
ok: true,
item: (await readWorkServerDeploymentState()) ?? null,
};
});
app.post('/api/server-commands/work-server/actions/deploy', async (request, reply) => {
const accessContext = await resolveServerCommandAccessContext(request);
if (!accessContext) {
sendAccessDenied(reply);
return;
}
if (accessContext.scope !== 'full' && !accessContext.allowedKeys.has('work-server')) {
reply.status(403);
return { ok: false, message: '현재 공유채팅 링크로는 WORK 서버를 배포할 수 없습니다.' };
}
const result = await deployWorkServerCommand();
return {
ok: true,
item: result.server,
commandOutput: result.commandOutput,
restartState: result.restartState,
deployment: result.deployment ?? result.server.deployment ?? null,
};
});
app.get('/api/server-commands/test/deployment', async (request, reply) => {
const accessContext = await resolveServerCommandAccessContext(request);
if (!accessContext) {
sendAccessDenied(reply);
return;
}
if (accessContext.scope !== 'full' && !accessContext.allowedKeys.has('test')) {
reply.status(403);
return { ok: false, message: '현재 공유채팅 링크로는 TEST 서버 배포 상태를 확인할 수 없습니다.' };
}
return {
ok: true,
item: (await readTestServerDeploymentState()) ?? null,
};
});
app.post('/api/server-commands/test/actions/deploy', async (request, reply) => {
const accessContext = await resolveServerCommandAccessContext(request);
if (!accessContext) {
sendAccessDenied(reply);
return;
}
if (accessContext.scope !== 'full' && !accessContext.allowedKeys.has('test')) {
reply.status(403);
return { ok: false, message: '현재 공유채팅 링크로는 TEST 서버를 배포할 수 없습니다.' };
}
try {
const result = await deployTestServerCommand();
return {
ok: true,
item: result.server,
commandOutput: result.commandOutput,
restartState: result.restartState,
testDeployment: result.testDeployment ?? null,
};
} catch (error) {
const statusCode = error && typeof error === 'object' && 'statusCode' in error ? Number((error as { statusCode?: unknown }).statusCode) : null;
if (statusCode === 409) {
reply.status(409);
return { ok: false, message: error instanceof Error ? error.message : 'TEST 서버 배포가 이미 진행 중입니다.' };
}
throw error;
}
});
app.get('/api/server-commands/restart-reservation', async (request, reply) => {
const accessContext = await resolveServerCommandAccessContext(request);
if (!accessContext) {