feat: 서버 준비 전에 감사 초기 상태와 정책 기준을 저장
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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'] } },
|
||||
|
||||
Reference in New Issue
Block a user