feat: scaffold quiz API vertical slice

- Add GameRequestSchema and derived types to packages/shared
- Add SupportedLanguageCode, SupportedPos, DifficultyLevel type exports
- Add getGameTerms() model to packages/db with pos/language/difficulty/limit filters
- Add prepareGameQuestions() service skeleton in apps/api
- Add createGame controller with Zod safeParse validation
- Wire POST /api/v1/game/start route
- Add scripts/gametest/test-game.ts for manual end-to-end testing
This commit is contained in:
lila 2026-04-09 13:47:01 +02:00
parent 13cc709b09
commit 9fc3ba375a
11 changed files with 99 additions and 94 deletions

View file

@ -4,7 +4,7 @@ import { apiRouter } from "./routes/apiRouter.js";
export function createApp() {
const app: Express = express();
app.use(express.json());
app.use("/api/v1", apiRouter);
return app;

View file

@ -1,8 +1,17 @@
import type { Request, Response } from "express";
import { prepareQuestions } from "../services/gameService.js";
import { GameRequestSchema } from "@glossa/shared";
import { prepareGameQuestions } from "../services/gameService.js";
export const getGame = async (req: Request, res: Response) => {
const query = gameRequestSchema.parse(req.query);
const questions = await prepareQuestions(query);
res.json({ success: true, data: questions });
export const createGame = async (req: Request, res: Response) => {
const gameSettings = GameRequestSchema.safeParse(req.body);
// TODO: remove when global error handler is implemented
if (!gameSettings.success) {
res.status(400).json({ success: false });
return;
}
const gameQuestions = await prepareGameQuestions(gameSettings.data);
res.json({ success: true, data: gameQuestions });
};

View file

@ -4,4 +4,4 @@ import { createGame } from "../controllers/gameController.js";
export const gameRouter: Router = express.Router();
gameRouter.get("/", createGame);
gameRouter.post("/start", createGame);

View file

@ -1,3 +1,16 @@
export const prepareQuestions = async (params: object) => {
console.log(params);
import type { GameRequestType } from "@glossa/shared";
import { getGameTerms } from "@glossa/db";
export const prepareGameQuestions = async (gameSettings: GameRequestType) => {
const { source_language, target_language, pos, difficulty, rounds } =
gameSettings;
const terms = await getGameTerms(
source_language,
target_language,
pos,
difficulty,
Number(rounds),
);
return terms;
};

View file

@ -2,7 +2,7 @@
"extends": "../../tsconfig.base.json",
"references": [
{ "path": "../../packages/shared" },
{ "path": "../../packages/db" }
{ "path": "../../packages/db" },
],
"compilerOptions": {
"module": "NodeNext",
@ -10,7 +10,7 @@
"outDir": "./dist",
"resolveJsonModule": true,
"rootDir": ".",
"types": ["vitest/globals"]
"types": ["vitest/globals"],
},
"include": ["src", "vitest.config.ts"]
"include": ["src", "vitest.config.ts", "../../packages/db/src/models"],
}