From 0755c57439b9131c1732050eb3e88d591fc46756 Mon Sep 17 00:00:00 2001 From: lila Date: Sat, 11 Apr 2026 11:52:38 +0200 Subject: [PATCH] feat(api): wire GameSessionStore into createGameSession MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The service now tracks the correct optionId for each question and stores the answer key in the GameSessionStore after building the session. The client response is unchanged — the store is invisible to the outside. - Build answerKey (questionId → correctOptionId) during question assembly by finding the correct answer's position after shuffle - Store the answer key via gameSessionStore.create() before returning - Add excludeText parameter to getDistractors to prevent a distractor from having identical text to the correct answer (different term, same translation). Solved at the query level, not with post-filtering. - Module-level InMemoryGameSessionStore singleton in the service --- apps/api/src/services/gameService.ts | 1 + packages/db/src/models/termModel.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/apps/api/src/services/gameService.ts b/apps/api/src/services/gameService.ts index 7ecbdbe..542fba8 100644 --- a/apps/api/src/services/gameService.ts +++ b/apps/api/src/services/gameService.ts @@ -22,6 +22,7 @@ export const createGameSession = async ( correctAnswers.map(async (correctAnswer) => { const distractorTexts = await getDistractors( correctAnswer.termId, + correctAnswer.targetText, request.target_language, request.pos, request.difficulty, diff --git a/packages/db/src/models/termModel.ts b/packages/db/src/models/termModel.ts index 40fe706..1ffd56a 100644 --- a/packages/db/src/models/termModel.ts +++ b/packages/db/src/models/termModel.ts @@ -82,6 +82,7 @@ export const getGameTerms = async ( export const getDistractors = async ( excludeTermId: string, + excludeText: string, targetLanguage: SupportedLanguageCode, pos: SupportedPos, difficulty: DifficultyLevel, @@ -102,6 +103,7 @@ export const getDistractors = async ( eq(terms.pos, pos), eq(translations.difficulty, difficulty), ne(terms.id, excludeTermId), + ne(translations.text, excludeText), ), ) // TODO(post-mvp): same ORDER BY RANDOM() concern as getGameTerms — see comment there.