From ce6dc4fa3285b835beb544d5eb1d9bd99de1e370 Mon Sep 17 00:00:00 2001 From: lila Date: Fri, 10 Apr 2026 21:43:53 +0200 Subject: [PATCH] feat(shared): add quiz session Zod schemas Add the shared schemas for the quiz request/response cycle, defining the contract between the API and the frontend. - Reorganise packages/shared: move schemas into a schemas/ subdirectory grouped by domain. Delete the old flat schema.ts. - Add AnswerOption, GameQuestion, GameSession, AnswerSubmission, and AnswerResult alongside the existing GameRequest. - optionId is an integer 0-3 (positional, shuffled at session-build time so position carries no information). - questionId and sessionId are UUIDs (globally unique, opaque, natural keys for Valkey storage later). - gloss is rather than optional, for a predictable shape on the frontend. - options array enforced to exactly 4 elements at the schema level. --- packages/shared/src/index.ts | 2 +- packages/shared/src/schema.ts | 18 --------- packages/shared/src/schemas/game.ts | 57 +++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 19 deletions(-) delete mode 100644 packages/shared/src/schema.ts create mode 100644 packages/shared/src/schemas/game.ts diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 2137233..ff5f988 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,2 +1,2 @@ export * from "./constants.js"; -export * from "./schema.js"; +export * from "./schemas/game.js"; diff --git a/packages/shared/src/schema.ts b/packages/shared/src/schema.ts deleted file mode 100644 index a0647a1..0000000 --- a/packages/shared/src/schema.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as z from "zod"; - -import { - SUPPORTED_LANGUAGE_CODES, - SUPPORTED_POS, - GAME_ROUNDS, - DIFFICULTY_LEVELS, -} from "./constants.js"; - -export const GameRequestSchema = z.object({ - source_language: z.enum(SUPPORTED_LANGUAGE_CODES), - target_language: z.enum(SUPPORTED_LANGUAGE_CODES), - pos: z.enum(SUPPORTED_POS), - difficulty: z.enum(DIFFICULTY_LEVELS), - rounds: z.enum(GAME_ROUNDS), -}); - -export type GameRequestType = z.infer; diff --git a/packages/shared/src/schemas/game.ts b/packages/shared/src/schemas/game.ts new file mode 100644 index 0000000..420b9ee --- /dev/null +++ b/packages/shared/src/schemas/game.ts @@ -0,0 +1,57 @@ +import * as z from "zod"; + +import { + SUPPORTED_LANGUAGE_CODES, + SUPPORTED_POS, + GAME_ROUNDS, + DIFFICULTY_LEVELS, +} from "../constants.js"; + +export const GameRequestSchema = z.object({ + source_language: z.enum(SUPPORTED_LANGUAGE_CODES), + target_language: z.enum(SUPPORTED_LANGUAGE_CODES), + pos: z.enum(SUPPORTED_POS), + difficulty: z.enum(DIFFICULTY_LEVELS), + rounds: z.enum(GAME_ROUNDS), +}); + +export type GameRequest = z.infer; + +export const AnswerOptionSchema = z.object({ + optionId: z.number().int().min(0).max(3), + text: z.string().min(1), +}); + +export type AnswerOption = z.infer; + +export const GameQuestionSchema = z.object({ + questionId: z.uuid(), + prompt: z.string().min(1), + gloss: z.string().min(1).nullable(), + options: z.array(AnswerOptionSchema).length(4), +}); + +export type GameQuestion = z.infer; + +export const GameSessionSchema = z.object({ + sessionId: z.uuid(), + questions: z.array(GameQuestionSchema), +}); + +export type GameSession = z.infer; + +export const AnswerSubmissionSchema = z.object({ + sessionId: z.uuid(), + questionId: z.uuid(), + selectedOptionId: z.number().int().min(0).max(3), +}); + +export type AnswerSubmission = z.infer; + +export const AnswerResultSchema = z.object({ + questionId: z.uuid(), + isCorrect: z.boolean(), + correctOptionId: z.number().int().min(0).max(3), +}); + +export type AnswerResult = z.infer;