feat(gateway): 프로필별 첫 기수 번호를 관리한다

첫 기수 번호를 완료 게임 수의 기준값으로 적용하고 0기를 API와 화면에서 보존한다. 시즌 번호와 독립된 RESET 계약을 관리 패널, 테스트, 운영 문서에 반영한다.
This commit is contained in:
2026-08-21 13:49:11 +00:00
parent 32d69d7049
commit 88be40f729
15 changed files with 192 additions and 19 deletions
+37 -14
View File
@@ -171,22 +171,33 @@ describeDb('scenario database seed', () => {
}
});
test('persists the next official game index without counting cancelled or unfinished games', async () => {
test('adds the configured first game index without counting cancelled or unfinished games', async () => {
const marker = `scenario-seeder-game-index-${Date.now()}`;
const connector = createGamePostgresConnector({ url: databaseUrl });
await connector.connect();
try {
const completedBefore = await connector.prisma.gameHistory.count({ where: { status: 'COMPLETED' } });
expect(completedBefore).toBe(0);
await seedScenarioToDatabase({
scenarioId: 1010,
databaseUrl,
installOptions: { serverId: `${marker}-zero`, firstGameIdx: 0 },
});
const zeroWorldState = await connector.prisma.worldState.findFirstOrThrow();
expect(zeroWorldState.meta).toMatchObject({ firstGameIdx: 0, gameIdx: 0 });
const zeroBasedHistory = await connector.prisma.gameHistory.findUniqueOrThrow({
where: { serverId: `${marker}-zero` },
});
expect(zeroBasedHistory).toMatchObject({ status: 'OPEN' });
expect(zeroBasedHistory.env).toMatchObject({ meta: { firstGameIdx: 0, gameIdx: 0 } });
await connector.prisma.gameHistory.update({
where: { serverId: `${marker}-zero` },
data: { status: 'COMPLETED' },
});
await connector.prisma.gameHistory.createMany({
data: [
{
serverId: `${marker}-completed`,
date: new Date('2026-08-01T00:00:00.000Z'),
season: 1,
scenario: 1010,
scenarioName: '정상 종료 fixture',
status: 'COMPLETED',
},
{
serverId: `${marker}-abandoned`,
date: new Date('2026-08-02T00:00:00.000Z'),
@@ -209,14 +220,26 @@ describeDb('scenario database seed', () => {
await seedScenarioToDatabase({
scenarioId: 1010,
databaseUrl,
installOptions: { serverId: marker },
installOptions: { serverId: `${marker}-one`, firstGameIdx: 0 },
});
const worldState = await connector.prisma.worldState.findFirstOrThrow();
expect(worldState.meta).toMatchObject({ gameIdx: completedBefore + 2 });
await expect(
connector.prisma.gameHistory.findUniqueOrThrow({ where: { serverId: marker } })
).resolves.toMatchObject({ status: 'OPEN' });
expect(worldState.meta).toMatchObject({ firstGameIdx: 0, gameIdx: completedBefore + 1 });
const oneBasedHistory = await connector.prisma.gameHistory.findUniqueOrThrow({
where: { serverId: `${marker}-one` },
});
expect(oneBasedHistory).toMatchObject({ status: 'OPEN' });
expect(oneBasedHistory.env).toMatchObject({
meta: { firstGameIdx: 0, gameIdx: completedBefore + 1 },
});
await seedScenarioToDatabase({
scenarioId: 1010,
databaseUrl,
installOptions: { serverId: `${marker}-default` },
});
const defaultWorldState = await connector.prisma.worldState.findFirstOrThrow();
expect(defaultWorldState.meta).toMatchObject({ firstGameIdx: 1, gameIdx: completedBefore + 2 });
} finally {
await connector.prisma.gameHistory.deleteMany({ where: { serverId: { startsWith: marker } } });
await connector.disconnect();