(SP: 5) [Quiz] Redis caching + guest session fix + cleanup#263
(SP: 5) [Quiz] Redis caching + guest session fix + cleanup#263ViktorSvertoka merged 25 commits intodevelopfrom
Conversation
…(issues #181, #193, #194) - Refactor QaTabButton to shared CategoryTabButton component - Add category accent colors to QuizCard, buttons, progress indicators - Standardize colors with CSS variables, traffic light timer - Add DynamicGridBackground to quizzes list page - Border-only answer feedback, semi-transparent progress styles
Changed violationsCount > 3 to >= 3 in QuizResult points block to match the warning banner threshold at line 124.
- Configure Vitest for quiz module - Add test factories and setup utilities - Add quiz-crypto tests (13 tests) - Add quiz-session tests (12 tests)
…eat hook (#199) - verify-answer.test.ts: 8 tests for API endpoint - Correct/wrong answer verification - Validation errors (missing fields, tampered data) - Security: rejects modified encrypted answers - quiz-anticheat.test.ts: 10 tests for useAntiCheat hook - Detects copy, paste, context-menu, tab-switch events - Respects isActive flag - Reset and cleanup functionality Total quiz tests: 52 (9 setup + 25 unit + 18 integration)
…UI flow Add 28 new tests covering: - useQuizSession hook (6 tests) - useQuizGuards hook (8 tests) - guest-quiz storage (5 tests) - guest-result API route (5 tests) - quiz-slug API route (3 tests) - QuizContainer UI flow (1 test) Coverage: 35% -> 90.94% (quiz scope) Tests: 52 -> 80
Closes #260, #261, #262 - Add quiz-answers-redis.ts with getOrCreateQuizAnswersCache() - Cache correct answers per quiz (12h TTL) - Replace AES-256-GCM decryption with O(1) Redis lookup - Add initializeQuizCache server action - Update verify-answer route to use Redis - Allow restoring 'completed' sessions (not just 'in_progress') - Only clear session for authenticated users after submit - Guest result screen now survives language switch - Delete PendingResultHandler.tsx (never executes) - Delete start-session/route.ts (broken import, unused) - Delete quiz-crypto.ts (AES replaced by Redis) - Delete quiz-crypto.test.ts (tests dead code) - Rewrite verify-answer.test.ts for Redis API (8 tests) - Fix quiz-session.test.ts for completed session restore
Part of #262 cleanup - route had broken import after Redis migration.
- Validate seed param to prevent NaN breaking question shuffle - Add cache recovery in verify-answer when Redis cache expires - Add DB fallback in getCorrectAnswer when Redis unavailable
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughMigrates quiz answer verification from client-side encryption to a Redis-backed server cache. Adds cache utilities and initialization action, updates verify-answer API and quiz components to use cached answers, removes crypto module and PendingResultHandler, adds Redis debug routes, and performs widespread import/formatting cleanup. Changes
Sequence DiagramsequenceDiagram
participant Client as Quiz Client
participant Server as API Server
participant Redis as Redis Cache
participant DB as Database
rect rgba(100,150,200,0.5)
Note over Client,DB: Old Flow (Encryption-Based)
Client->>Client: Encrypt correct answers (client-side)
Client->>Server: POST /verify-answer with encryptedAnswers
Server->>Server: Decrypt encryptedAnswers
Server->>Server: Compare decrypted answer with submission
Server->>Client: Return isCorrect
end
rect rgba(150,200,100,0.5)
Note over Client,DB: New Flow (Redis-Cached)
Client->>Server: POST /quiz/[slug] (start)
Server->>Server: initializeQuizCache(quizId)
Server->>DB: Query correct answers for quizId
Server->>Redis: Cache answers (TTL: 12h)
Server->>Client: Quiz initialized
Client->>Server: POST /verify-answer { quizId, questionId, selectedAnswerId }
Server->>Redis: getCorrectAnswer(quizId, questionId)
Redis->>Server: Return correctAnswerId
Server->>Server: Compare selectedAnswerId === correctAnswerId
Server->>Client: Return { success, isCorrect }
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for develop-devlovers ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@frontend/app/`[locale]/quiz/[slug]/page.tsx:
- Around line 30-36: The code currently uses parseInt(seedParam, 10) without
validating the result, which can yield NaN and break
getQuizQuestionsRandomized/randomizeQuizQuestions; update the logic around
seedParam/parseInt to detect non-numeric or NaN seeds and handle them the same
way as a missing seed (i.e., perform the redirect to
`/${locale}/quiz/${slug}?seed=${Date.now()}`) so only a valid numeric seed is
passed into the seed variable and into getQuizQuestionsRandomized; ensure any
check covers empty string, non-digits, and NaN after parseInt.
In `@frontend/app/api/quiz/verify-answer/route.ts`:
- Around line 3-28: The handler POST currently returns 404 when
getCorrectAnswer(quizId, questionId) yields null even if the cache was evicted;
import and call getOrCreateQuizAnswersCache(quizId) as a fallback to rehydrate
the cache, then retry getCorrectAnswer(quizId, questionId) before returning the
404 via NextResponse; update imports to include getOrCreateQuizAnswersCache and
ensure behavior remains identical if the retry still returns null.
In `@frontend/lib/quiz/quiz-answers-redis.ts`:
- Around line 22-84: getCorrectAnswer returns null on cache miss (or when Redis
is disabled) causing the verify-answer route to 404 even though
getOrCreateQuizAnswersCache allowed the quiz to start; add a DB fallback or
cache rehydration so answer verification works. Update getCorrectAnswer (or the
verify-answer handler) to, on cache miss, either call
getOrCreateQuizAnswersCache(quizId) and re-read redis, or run the same DB query
used in getOrCreateQuizAnswersCache
(db.select(...).from(quizAnswers).innerJoin(quizQuestions,
eq(quizAnswers.quizQuestionId,
quizQuestions.id)).where(and(eq(quizQuestions.quizId, quizId),
eq(quizAnswers.isCorrect, true)))) to find the correct answer for questionId,
populate the answers map and (optionally) set the redis key via
getRedisClient()/getCacheKey with QUIZ_CACHE_TTL_SECONDS; return the found
answerId or null if none. Ensure to reference getOrCreateQuizAnswersCache,
getCorrectAnswer, quizAnswers, quizQuestions, getRedisClient, getCacheKey, and
QUIZ_CACHE_TTL_SECONDS when making the change.
🧹 Nitpick comments (3)
frontend/components/quiz/QuizResult.tsx (1)
15-27: Unused propquizSlugin interface.The
quizSlugprop is declared inQuizResultProps(line 22) but is no longer destructured or used in the component. This appears to be leftover from the redirect URL change.🧹 Remove unused prop from interface
interface QuizResultProps { score: number; total: number; percentage: number; answeredCount: number; violationsCount?: number; isGuest?: boolean; - quizSlug?: string; pointsAwarded?: number | null; isIncomplete?: boolean; onRestart: () => void; onBackToTopics: () => void; }frontend/components/quiz/QuizQuestion.tsx (1)
58-67: Redundantborderclass in conditional styling.Line 59 already includes
borderin the base class. Lines 64-65 addborder border-green-500andborder border-red-500, resulting in duplicateborderdeclarations.🧹 Remove redundant border class
isSelected && isAnswering && 'border-blue-500 bg-blue-50 dark:bg-blue-950', - showCorrect && 'border border-green-500', - showIncorrect && 'border border-red-500', + showCorrect && 'border-green-500', + showIncorrect && 'border-red-500', !isAnswering && 'cursor-default'frontend/lib/quiz/quiz-session.ts (1)
48-52: Comment is now outdated.The comment "Only restore in_progress sessions" no longer accurately describes the behavior. The condition now allows both
in_progressandcompletedsessions to be restored (onlyrulesstatus is cleared).📝 Update comment to reflect actual behavior
- // Only restore in_progress sessions + // Discard sessions that haven't started yet if (data.status === 'rules') { clearQuizSession(quizId); return null; }
* chore: bump Node.js to 20 for Netlify * feat(md) add netlify status (#234) * (SP 2) [Shop UI] Unify storefront styles across components and interactions (#236) * Host (#237) * feat(md) add netlify status * feat(files): add packages * fix(auth): use currentTarget for email input validity * Host (#238) * feat(md) add netlify status * feat(files): add packages * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget in password field * (SP 1) [Shop UI] Add page metadata across shop routes (#239) * (SP 2) [Shop UI] Unify storefront styles across components and interactions * (SP 1) [Shop UI] Add page metadata across shop routes * (SP: 3) [Cache] Add Upstash Redis cache for Q&A (#241) * feat(md) add netlify status * feat(files): add packages * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget in password field * feat(qa): add Redis cache layer for Q&A * Fix Q&A Redis cache parsing for Upstash REST (#243) * feat(md) add netlify status * feat(files): add packages * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget for email input validity * fix(auth): use currentTarget in password field * feat(qa): add Redis cache layer for Q&A * fix(qa): handle non-string Redis cache values * feat(Blog):Adding pagination (#244) * feat(Blog):fix for clickable link in post details, fix for author details * feat(Blog):refactoring after removing author modal * feat(Blog): fix unified date format * feat(Blog): Fix for click-outside-to-close search, recommended posts are limited to 3 * feat(Blog): selectedAuthorData fixed * feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders * feat(Blog): fix hover social links, fixed duplication not found search * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations * feat(Blog): Changed image size on the post details page * feat(Blog): added tests * feat(Blog): fix for big post on the post page, added tests * feat(Blog): resolving comments * feat(Blog): fixed hover for social links icins - dark theme * feat(Blog): bringing the style on the blog page to a single site style * feat(blog): aligning syles * feat(blog): resolving comment from CodeRabbit * feat(blog):fix comment for deployment * feat(Blog): adding pagination * feat(Blog): Addind Text formatting visibility * (SP:2) feat(api): clean up AI helper for Vercel & fix orders i18n (#245) - Refactor /api/ai/explain route for Vercel deployment - Replace dynamic import with static import of groq-sdk - Use request.json() instead of Netlify-safe body parsing - Add proper error handling with Groq.APIError types - Simplify GET health check endpoint - Update model from llama3-70b-8192 to llama-3.3-70b-versatile - Add table.openOrder and table.orderId to en/uk/pl locales * refactor(home): update button, cards, and online counter UI (#248) Improve primary button styles Fix card overflow and add subtle highlights Redesign online users counter and reduce font size * fix(api): enforce rate limiting (#246) * (SP:2) feat(api): clean up AI helper for Vercel & fix orders i18n - Refactor /api/ai/explain route for Vercel deployment - Replace dynamic import with static import of groq-sdk - Use request.json() instead of Netlify-safe body parsing - Add proper error handling with Groq.APIError types - Simplify GET health check endpoint - Update model from llama3-70b-8192 to llama-3.3-70b-versatile - Add table.openOrder and table.orderId to en/uk/pl locales * fix(api): enforce rate limiting --------- Co-authored-by: Viktor Svertoka <victor.svertoka@gmail.com> * feat(Blog):formating text (#249) * feat(Blog):fix for clickable link in post details, fix for author details * feat(Blog):refactoring after removing author modal * feat(Blog): fix unified date format * feat(Blog): Fix for click-outside-to-close search, recommended posts are limited to 3 * feat(Blog): selectedAuthorData fixed * feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders * feat(Blog): fix hover social links, fixed duplication not found search * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations * feat(Blog): Changed image size on the post details page * feat(Blog): added tests * feat(Blog): fix for big post on the post page, added tests * feat(Blog): resolving comments * feat(Blog): fixed hover for social links icins - dark theme * feat(Blog): bringing the style on the blog page to a single site style * feat(blog): aligning syles * feat(blog): resolving comment from CodeRabbit * feat(blog):fix comment for deployment * feat(Blog): adding pagination * feat(Blog): Addind Text formatting visibility * feat(Blog):adding text formating fix * ref(files): refactoring code & bag fix (#250) * chore(release): v0.5.2 * Lso/feat/shop design (#252) * feat(i18n): add translations for blog categories, and UI components (#253) - Translate blog category labels in mobile menu, cards, and filters - Add CTA hover variants translations - Add aria-label translations for theme toggle, cart, search, GitHub star - Update translation files for EN, UK, PL locales * feat blog: fix for paddings on mobile (#254) * feat(Blog):fix for clickable link in post details, fix for author details * feat(Blog):refactoring after removing author modal * feat(Blog): fix unified date format * feat(Blog): Fix for click-outside-to-close search, recommended posts are limited to 3 * feat(Blog): selectedAuthorData fixed * feat(Blog): Added description for /blog/[slug] metadata, Added Schema.org JSON‑LD for Article (BlogPosting) and BreadcrumbList , Added <time datetime> tags where blog dates renders * feat(Blog): fix hover social links, fixed duplication not found search * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added: breadcrumbs to the post details page and updated the BreadcrumbList, logo to the cocial links in User info, Fixed: main container alignment, category navigation in breadcrumbs * feat(Blog): Added scroll on the main blog page on filtering by author, fied breadcrumbs category translaion, added category to the recommended cards, fixed search for localisations * feat(Blog): Changed image size on the post details page * feat(Blog): added tests * feat(Blog): fix for big post on the post page, added tests * feat(Blog): resolving comments * feat(Blog): fixed hover for social links icins - dark theme * feat(Blog): bringing the style on the blog page to a single site style * feat(blog): aligning syles * feat(blog): resolving comment from CodeRabbit * feat(blog):fix comment for deployment * feat(Blog): adding pagination * feat(Blog): Addind Text formatting visibility * feat(Blog):adding text formating fix * chore(lint): finalize ESLint + Prettier (#256) * feat(leaderboard): finalize components and fix lint errors (#259) * (SP 1) [FIX] set up eslint/prettier + stabilize formatting workflow (own files only) (#264) * (SP 2) [Shop UI] Unify storefront styles across components and interactions * (SP 1) [Shop UI] Add page metadata across shop routes * (SP 1) [FIX] names of components, replacing tests, clean code * (SP 1) [FIX] remove magic constant and align restock sweep test typing * (SP 1) [FIX] remove duplicate * (SP 1) [FIX] set up eslint/prettier + stabilize formatting workflow (own files only) * (SP 1) [FIX] Tailwind hints * (SP 1) [FIX] Tailwind hints revert * (SP: 5) [Quiz] Redis caching + guest session fix + cleanup (#263) * feat(quiz-ui): quiz UI polish - tabs, category accents, color scheme (issues #181, #193, #194) - Refactor QaTabButton to shared CategoryTabButton component - Add category accent colors to QuizCard, buttons, progress indicators - Standardize colors with CSS variables, traffic light timer - Add DynamicGridBackground to quizzes list page - Border-only answer feedback, semi-transparent progress styles * docs: update .gitignore * fix(quiz): align disqualification threshold with warning banner Changed violationsCount > 3 to >= 3 in QuizResult points block to match the warning banner threshold at line 124. * feat(quiz-testing): add quiz unit tests - Configure Vitest for quiz module - Add test factories and setup utilities - Add quiz-crypto tests (13 tests) - Add quiz-session tests (12 tests) * test(quiz): add integration tests for verify-answer API and useAntiCheat hook (#199) - verify-answer.test.ts: 8 tests for API endpoint - Correct/wrong answer verification - Validation errors (missing fields, tampered data) - Security: rejects modified encrypted answers - quiz-anticheat.test.ts: 10 tests for useAntiCheat hook - Detects copy, paste, context-menu, tab-switch events - Respects isActive flag - Reset and cleanup functionality Total quiz tests: 52 (9 setup + 25 unit + 18 integration) * test(quiz): expand test coverage to 90%+ with hooks, API routes, and UI flow Add 28 new tests covering: - useQuizSession hook (6 tests) - useQuizGuards hook (8 tests) - guest-quiz storage (5 tests) - guest-result API route (5 tests) - quiz-slug API route (3 tests) - QuizContainer UI flow (1 test) Coverage: 35% -> 90.94% (quiz scope) Tests: 52 -> 80 * chore: remove coverage-quiz from git, add to .gitignore * chore: add coverage-quiz to .gitignore, fix quiz guards test * fix(a11y): improve quiz accessibility and i18n compliance * fix(sl/feat/quiz): replace with correct name for react icon * feat(quiz): implement Redis caching + session fixes + cleanup Closes #260, #261, #262 - Add quiz-answers-redis.ts with getOrCreateQuizAnswersCache() - Cache correct answers per quiz (12h TTL) - Replace AES-256-GCM decryption with O(1) Redis lookup - Add initializeQuizCache server action - Update verify-answer route to use Redis - Allow restoring 'completed' sessions (not just 'in_progress') - Only clear session for authenticated users after submit - Guest result screen now survives language switch - Delete PendingResultHandler.tsx (never executes) - Delete start-session/route.ts (broken import, unused) - Delete quiz-crypto.ts (AES replaced by Redis) - Delete quiz-crypto.test.ts (tests dead code) - Rewrite verify-answer.test.ts for Redis API (8 tests) - Fix quiz-session.test.ts for completed session restore * chore(quiz): delete unused start-session route Part of #262 cleanup - route had broken import after Redis migration. * git commit -m "fix(quiz): add NaN seed validation and cache/DB fallback - Validate seed param to prevent NaN breaking question shuffle - Add cache recovery in verify-answer when Redis cache expires - Add DB fallback in getCorrectAnswer when Redis unavailable * chore: remove redis ttl for static quiz and qa caches (#265) * fix(layout): remove duplicate padding from quiz routes (#266) * feat(quiz-ui): quiz UI polish - tabs, category accents, color scheme (issues #181, #193, #194) - Refactor QaTabButton to shared CategoryTabButton component - Add category accent colors to QuizCard, buttons, progress indicators - Standardize colors with CSS variables, traffic light timer - Add DynamicGridBackground to quizzes list page - Border-only answer feedback, semi-transparent progress styles * docs: update .gitignore * fix(quiz): align disqualification threshold with warning banner Changed violationsCount > 3 to >= 3 in QuizResult points block to match the warning banner threshold at line 124. * feat(quiz-testing): add quiz unit tests - Configure Vitest for quiz module - Add test factories and setup utilities - Add quiz-crypto tests (13 tests) - Add quiz-session tests (12 tests) * test(quiz): add integration tests for verify-answer API and useAntiCheat hook (#199) - verify-answer.test.ts: 8 tests for API endpoint - Correct/wrong answer verification - Validation errors (missing fields, tampered data) - Security: rejects modified encrypted answers - quiz-anticheat.test.ts: 10 tests for useAntiCheat hook - Detects copy, paste, context-menu, tab-switch events - Respects isActive flag - Reset and cleanup functionality Total quiz tests: 52 (9 setup + 25 unit + 18 integration) * test(quiz): expand test coverage to 90%+ with hooks, API routes, and UI flow Add 28 new tests covering: - useQuizSession hook (6 tests) - useQuizGuards hook (8 tests) - guest-quiz storage (5 tests) - guest-result API route (5 tests) - quiz-slug API route (3 tests) - QuizContainer UI flow (1 test) Coverage: 35% -> 90.94% (quiz scope) Tests: 52 -> 80 * chore: remove coverage-quiz from git, add to .gitignore * chore: add coverage-quiz to .gitignore, fix quiz guards test * fix(a11y): improve quiz accessibility and i18n compliance * fix(sl/feat/quiz): replace with correct name for react icon * feat(quiz): implement Redis caching + session fixes + cleanup Closes #260, #261, #262 - Add quiz-answers-redis.ts with getOrCreateQuizAnswersCache() - Cache correct answers per quiz (12h TTL) - Replace AES-256-GCM decryption with O(1) Redis lookup - Add initializeQuizCache server action - Update verify-answer route to use Redis - Allow restoring 'completed' sessions (not just 'in_progress') - Only clear session for authenticated users after submit - Guest result screen now survives language switch - Delete PendingResultHandler.tsx (never executes) - Delete start-session/route.ts (broken import, unused) - Delete quiz-crypto.ts (AES replaced by Redis) - Delete quiz-crypto.test.ts (tests dead code) - Rewrite verify-answer.test.ts for Redis API (8 tests) - Fix quiz-session.test.ts for completed session restore * chore(quiz): delete unused start-session route Part of #262 cleanup - route had broken import after Redis migration. * git commit -m "fix(quiz): add NaN seed validation and cache/DB fallback - Validate seed param to prevent NaN breaking question shuffle - Add cache recovery in verify-answer when Redis cache expires - Add DB fallback in getCorrectAnswer when Redis unavailable * fix(layout): remove duplicate padding from quiz routes Add isQuizzesPath to MainSwitcher to exclude /quiz and /quizzes routes from extra px-6 padding, matching Q&A page behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: liudmylasovetovs <127711697+liudmylasovetovs@users.noreply.github.com> Co-authored-by: KomrakovaAnna <komrakova.anna@gmail.com> Co-authored-by: Tetiana Zorii <131365289+TiZorii@users.noreply.github.com> Co-authored-by: Yuliia Nazymko <122815071+YNazymko12@users.noreply.github.com> Co-authored-by: AlinaRyabova <115992255+AlinaRyabova@users.noreply.github.com> Co-authored-by: Lesia Soloviova <106915140+LesiaUKR@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Summary
Closes #260
Closes #261
Closes #262
Issues Closed
Changes
Redis Cache (#260)
initializeQuizCacheserver actionGuest Language Switch Fix (#261)
completedstatus is now restoredCodebase Cleanup (#262)
PendingResultHandler.tsxstart-session/route.tsquiz-crypto.tsquiz-crypto.test.tsWCAG Accessibility
Known Limitations (documented)
Test Results
verify-answer.test.tsrewritten for Redis APITest plan
Summary by CodeRabbit
New Features
Improvements
Bug Fixes