feat: 서버 준비 전에 감사 초기 상태와 정책 기준을 저장

This commit is contained in:
2026-09-16 05:22:01 +00:00
parent 3d60e6122d
commit 8faab62866
20 changed files with 481 additions and 41 deletions
+1 -1
View File
@@ -140,7 +140,7 @@ export const playAuditRouter = router({
? {
year: samples[input.limit - 1]!.year,
month: samples[input.limit - 1]!.month,
kind: z.enum(['MONTH_END', 'FINAL']).parse(samples[input.limit - 1]!.kind),
kind: z.enum(['MONTH_END', 'FINAL', 'INITIAL']).parse(samples[input.limit - 1]!.kind),
}
: null,
};
+23 -1
View File
@@ -20,7 +20,7 @@ export const zAuditMonth = z
.object({
year: z.number().int().min(0).max(9999),
month: z.number().int().min(1).max(12),
kind: z.enum(['MONTH_END', 'FINAL']).default('MONTH_END'),
kind: z.enum(['MONTH_END', 'FINAL', 'INITIAL']).default('MONTH_END'),
})
.strict();
export const zAuditPage = z
@@ -89,12 +89,34 @@ export const readAuditWorld = async (tx: GamePrisma.TransactionClient) => {
? Math.min(scenarioStartYear, world.currentYear)
: world.currentYear;
const startMonth = hasInitialCalendar ? Number(meta.initMonth) : 1;
const collection = z
.object({
schemaVersion: z.literal(1),
serverId: z.string(),
year: z.number().int().nonnegative(),
month: z.number().int().min(1).max(12),
tick: z.number().int().nonnegative(),
observedAt: z.string().datetime(),
})
.safeParse(meta.playAuditCollection);
const collectionStart =
collection.success &&
collection.data.serverId === serverId &&
monthOrdinal(collection.data.year, collection.data.month) <= monthOrdinal(world.currentYear, world.currentMonth)
? {
year: collection.data.year,
month: collection.data.month,
tick: String(collection.data.tick),
observedAt: collection.data.observedAt,
}
: null;
return {
serverId,
year: world.currentYear,
month: world.currentMonth,
startYear,
startMonth,
collectionStart,
tick: world.lastTurnTick?.toString() ?? null,
asOf: new Date().toISOString(),
};
@@ -2563,6 +2563,75 @@ integration('game API security over HTTP transport', () => {
},
},
});
await db.playAuditMonth.create({
data: {
id: `${seasonId}:adoption`,
serverId: seasonId,
year: 190,
month: 1,
kind: 'INITIAL',
settlementsComplete: false,
hash: 'http-initial-fixture',
nations: {
create: {
nationId: ownerNationId,
data: { ...asRecord(finalNation.data), gold: 777, incomeGold: null },
},
},
generals: {
create: {
generalId,
nationId: current.nationId,
cityId: 99123,
npcState: current.npcState,
data: { ...past, name: '도입장수' },
},
},
},
});
await db.worldState.update({
where: { id: fixtureWorldId },
data: {
meta: {
serverId: seasonId,
scenarioMeta: { startYear: 190 },
playAuditCollection: {
schemaVersion: 1,
serverId: seasonId,
year: 190,
month: 1,
tick: 0,
observedAt: '2026-09-16T00:00:00.000Z',
},
},
},
});
expect((await get('coverage', admin, { limit: 1 })).body).toMatchObject({
result: {
data: {
collectionStart: { year: 190, month: 1, observedAt: '2026-09-16T00:00:00.000Z' },
samples: [{ kind: 'INITIAL' }],
nextCursor: { year: 190, month: 1, kind: 'INITIAL' },
},
},
});
expect(
(await get('coverage', admin, { limit: 1, cursor: { year: 190, month: 1, kind: 'INITIAL' } })).body
).toMatchObject({ result: { data: { samples: [{ kind: 'MONTH_END' }] } } });
expect(
(
await get('nationSnapshot', admin, {
nationId: ownerNationId,
at: { year: 190, month: 1, kind: 'INITIAL' },
})
).body
).toMatchObject({
result: { data: { nation: { gold: 777, incomeGold: null }, sample: { kind: 'INITIAL' } } },
});
expect(
(await get('generalDetail', admin, { id: generalId, at: { year: 190, month: 1, kind: 'INITIAL' } }))
.body
).toMatchObject({ result: { data: { general: { name: '도입장수' } } } });
expect(
(
await get('nationSnapshot', admin, {
@@ -167,6 +167,8 @@ integration('scenario 903 select pool through the durable turn daemon', () => {
await db.inputEvent.deleteMany();
await db.logEntry.deleteMany();
await db.playAuditPolicy.deleteMany({ where: { serverId: profile } });
// 이 fixture는 기수 ID를 재사용하므로 실제 RESET과 달리 해당 초기 표본도 비운다.
await db.playAuditMonth.deleteMany({ where: { serverId: profile, kind: 'INITIAL' } });
worldStateId = (await db.worldState.findFirstOrThrow()).id;
await db.playAuditMonth.deleteMany({
where: { id: { in: ['select-pool-audit-old', 'select-pool-audit-active'] } },