fix: 토너먼트 단계의 메인 실시간 갱신을 연결

토너먼트 state의 stage 전이만 공용 실시간 채널에 발행하고 공개 invalidation으로 변환한다.
메인 dashboard store가 단계 값을 소유해 상단 문구와 메뉴 강조를 단일/다중 탭에서 함께 갱신한다.
Redis 통합 테스트와 production Chromium 회귀 검증을 추가한다.
This commit is contained in:
2026-08-17 01:41:37 +00:00
parent 1a4cd1a53f
commit 50068224c8
17 changed files with 392 additions and 31 deletions
@@ -25,6 +25,7 @@ void test('last-turn-time-only events do not schedule any dashboard query', () =
reservedTurns: false,
records: false,
frontStatus: false,
tournament: false,
});
});
@@ -46,6 +47,7 @@ void test('selects only the read models affected by the current identity', () =>
reservedTurns: true,
records: true,
frontStatus: false,
tournament: false,
});
});
@@ -79,6 +81,7 @@ void test('routes defence, tax-rate, and current-city-state events to their exac
reservedTurns: false,
records: false,
frontStatus: false,
tournament: false,
});
const taxRate = resolveDashboardRefreshPlan(
@@ -100,6 +103,7 @@ void test('routes defence, tax-rate, and current-city-state events to their exac
reservedTurns: false,
records: false,
frontStatus: false,
tournament: false,
});
const cityState = resolveDashboardRefreshPlan(
@@ -161,6 +165,7 @@ void test('refreshes only front status for a global survey projection change', (
reservedTurns: false,
records: false,
frontStatus: true,
tournament: false,
});
});
@@ -174,8 +179,8 @@ void test('targets a submitted survey projection to its own general', () => {
assert.equal(resolveDashboardRefreshPlan(changes, { generalId: 8, cityId: 3, nationId: 2 }).frontStatus, false);
});
void test('keeps the access bundle projection-free for map, records, and front-status-only plans', () => {
for (const slice of ['map', 'records', 'frontStatus'] as const) {
void test('keeps the access bundle projection-free for independent read-model plans', () => {
for (const slice of ['map', 'records', 'frontStatus', 'tournament'] as const) {
const plan = { ...createEmptyRealtimeReadModelInvalidation(), [slice]: true };
assert.deepEqual(resolveDashboardContextBundleInclude(plan), {
context: false,