feat: API 변화 저널과 outbox worker를 연결

입력 이벤트의 업무 변경, 성공 원장, revision 및 outbox를 한 transaction에서 커밋한다. 설문의 commit 전 Redis 발행을 제거하고 접속 점수용 private revision과 재시도·retention을 갖춘 dispatcher lifecycle을 추가한다.
This commit is contained in:
2026-08-16 18:22:57 +00:00
parent b41b161e9c
commit f858ca43f4
15 changed files with 606 additions and 52 deletions
+8
View File
@@ -1,4 +1,5 @@
import { z } from 'zod';
import type { ChangeJournal } from '@sammo-ts/common';
import type { GameSessionTokenPayload } from '@sammo-ts/common/auth/gameToken';
import type { DatabaseClient as InfraDatabaseClient, RedisConnector, GamePrisma } from '@sammo-ts/infra';
import { normalizeScenarioEffect, SCENARIO_EFFECT_KEYS } from '@sammo-ts/logic';
@@ -10,6 +11,7 @@ import type { RedisAccessTokenStore } from './auth/accessTokenStore.js';
import type { AccountIconSource } from './auth/accountIconSource.js';
import type { ProfileStatusSource } from './auth/profileStatusSource.js';
import type { ContentImageUploadStore } from './services/remoteContentImageStore.js';
import type { ReadModelOutboxWakeup } from './realtime/outboxWorker.js';
export interface GameProfile {
id: string;
@@ -87,6 +89,10 @@ export interface GameApiContext {
generalAccessTracking?: boolean;
/** Request-local identity already resolved by the realtime access gate. */
realtimeAccessGeneralId?: number;
/** Set only while an API input-event transaction owns the mutation. */
changeJournal?: ChangeJournal;
/** Post-commit scheduling hint for the durable outbox dispatcher. */
readModelOutbox?: ReadModelOutboxWakeup;
db: DatabaseClient;
redis: RedisConnector['client'];
turnDaemon: TurnDaemonTransport;
@@ -125,6 +131,7 @@ export const createGameApiContext = (options: {
gameTokenSecret: string;
accountIconSource?: AccountIconSource;
profileStatusSource: ProfileStatusSource;
readModelOutbox?: ReadModelOutboxWakeup;
}): GameApiContext => {
return {
requestId: options.requestId,
@@ -145,5 +152,6 @@ export const createGameApiContext = (options: {
gameTokenSecret: options.gameTokenSecret,
...(options.accountIconSource ? { accountIconSource: options.accountIconSource } : {}),
profileStatusSource: options.profileStatusSource,
...(options.readModelOutbox ? { readModelOutbox: options.readModelOutbox } : {}),
};
};