feat: guest play — allow singleplayer quiz without auth

- Add optionalAuth middleware: attaches session when present,
  never blocks (guests pass through)
- Make game endpoints (start/answer) accept optional auth
- GameSessionStore.userId: string → string | null
- Rate limiter falls back to IP for unauthenticated users
- Frontend: remove /play route guard, show 'Create account' CTA
  on score screen for guests
- Add tests for guest session creation, answer submission,
  and cross-user session isolation
This commit is contained in:
lila 2026-05-31 21:28:08 +02:00
parent d55a1ed648
commit 0118798e36
11 changed files with 298 additions and 32 deletions

View file

@ -19,7 +19,7 @@ import { shuffleArray } from "../lib/utils.js";
export const createGameSession = async (
request: GameRequest,
store: GameSessionStore,
userId: string,
userId: string | null,
): Promise<GameSession> => {
const terms = await getGameTerms(
request.source_language,
@ -87,11 +87,15 @@ export const createGameSession = async (
export const evaluateAnswer = async (
submission: AnswerSubmission,
store: GameSessionStore,
userId: string,
userId: string | null,
): Promise<AnswerResult> => {
const session = await store.get(submission.sessionId);
if (!session || session.userId !== userId) {
if (!session) {
throw new NotFoundError(`Game session not found: ${submission.sessionId}`);
}
if (session.userId !== userId) {
throw new NotFoundError(`Game session not found: ${submission.sessionId}`);
}