feat: 이전 서버 기록 조회 화면을 통합

지난 플레이를 현재 장수 카드와 전투·숙련도·기록 컴포넌트로 표시하고, 중앙 archive의 소유자 기반 조회를 연결한다. 명예의 전당과 왕조에 현재/이전 서버 source 분리를 추가한다.
This commit is contained in:
2026-08-17 15:55:43 +00:00
parent fc7de05017
commit d6a25c63b0
18 changed files with 2594 additions and 777 deletions
+99
View File
@@ -123,6 +123,72 @@ const buildContext = (
oldNations: Array<Record<string, unknown>> = [oldNation, deletedOldNation]
): GameApiContext => {
const db = {
$queryRaw: async (query: { strings?: readonly string[] }) => {
const sql = query.strings?.join(' ') ?? '';
if (sql.includes('legacy_archive"."emperor')) {
return [
{
id: 101n,
sourceProfile: 'hwe',
legacyId: 7,
serverId: emperor.serverId,
data: {
phase: '이전 훼2기',
nation_count: emperor.nationCount,
nation_name: emperor.nationName,
nation_hist: emperor.nationHist,
gen_count: emperor.genCount,
personal_hist: emperor.personalHist,
special_hist: emperor.specialHist,
name: emperor.name,
type: emperor.type,
color: emperor.color,
year: emperor.year,
month: emperor.month,
power: emperor.power,
gennum: emperor.gennum,
citynum: emperor.citynum,
pop: emperor.pop,
poprate: emperor.poprate,
gold: emperor.gold,
rice: emperor.rice,
l12name: emperor.l12name,
l11name: emperor.l11name,
l10name: emperor.l10name,
l9name: emperor.l9name,
l8name: emperor.l8name,
l7name: emperor.l7name,
l6name: emperor.l6name,
l5name: emperor.l5name,
tiger: emperor.tiger,
eagle: emperor.eagle,
gen: emperor.gen,
history: emperor.history,
aux: emperor.aux,
},
},
];
}
if (sql.includes('legacy_archive"."nation')) {
return [
{
sourceProfile: 'hwe',
legacyId: oldNation.id,
serverId: oldNation.serverId,
nation: oldNation.nation,
data: oldNation.data,
archivedAt: oldNation.date,
},
];
}
if (sql.includes('legacy_archive"."general')) {
return [
{ generalNo: 11, name: '유비', lastYearMonth: 21504 },
{ generalNo: 12, name: '제갈량', lastYearMonth: 21504 },
];
}
return [];
},
worldState: {
findFirst: async () => ({ currentYear: 220, currentMonth: 1 }),
},
@@ -186,6 +252,39 @@ describe('dynasty public read model', () => {
]);
});
it('reads previous-server dynasties only when the archive source is selected', async () => {
const caller = appRouter.createCaller(buildContext(null));
const list = await caller.dynasty.getList({ source: 'legacy' });
expect(list).toMatchObject({
source: 'legacy',
current: null,
entries: [
expect.objectContaining({
id: 101,
source: 'legacy',
sourceProfile: 'hwe',
phase: '이전 훼2기',
}),
],
});
const detail = await caller.dynasty.getDetail({ emperorId: 101, source: 'legacy' });
expect(detail).toMatchObject({
source: 'legacy',
sourceProfile: 'hwe',
emperor: expect.objectContaining({ id: 101, phase: '이전 훼2기', name: '촉' }),
nations: [
expect.objectContaining({
name: '촉',
generalsFull: [
{ generalNo: 11, name: '유비', lastYearMonth: 21504 },
{ generalNo: 12, name: '제갈량', lastYearMonth: 21504 },
],
}),
],
});
});
it('exposes the same public DTO to anonymous, general owners and admins', async () => {
const anonymous = appRouter.createCaller(buildContext(null));
const owner = appRouter.createCaller(buildContext(authFor('owner-a')));