CS Quiz Question Pool Major Expansion + 5 New Categories + 'ALL' (Full Random) Filter

SummaryExpanded the CS quiz (/quiz) question pool from 150 to 350 (5 categories × 30 → 10 categories with augmented counts) and added a category 'ALL' (full random) filter. Wave A (infra): QuizCategory enum +5 + Palette added 20 CSS variable lines in globals.css for the 5 new categories (WCAG AA 4.5:1+ verified) + category-meta icon/var mapping. Wave B+C (content): 20 questions per new category + existing 5 categories 30→50 questions (HARD imbalance fix), globally unique IDs totaling 350, generated by 10 parallel Curator agents. Wave D ('ALL' filter): getQuestionsByFilter/getRandomQuestions accept category: 'ALL', QuizStart PillRadioGroup 'ALL' prepended (0 new tokens). Wave E (tests): +22 tests, global 1555 PASS. Lessons: per-file one-agent parallelism, single-quote string apostrophe syntax errors, within() scope queries, meta filter option zero-token pattern. Frontend only, merge ≠ live.

Date
ImpactCritical

Goal

  • Expand the CS quiz (/quiz) question pool from 150 to 350 (5 categories × 30 → 10 categories, existing 5 categories augmented from 30 to 50 each).
  • Add 5 new categories (Computer Architecture, Design Pattern, Web, Security, AI) with WCAG AA-verified CSS tokens and icons.
  • Add an 'ALL' (full random) filter to the category selector so users can practice across all categories at once.
  • Frontend only, pure data/UI expansion — merge ≠ live (post-redeploy live verification carries over to the quiz-ui-verification runbook).

Background

The CS quiz built from Sprint 215 onward had its UI, accessibility, and UX polished through Sprint 221~224, but the question pool remained limited at 5 categories × 30 questions = 150 items. Users exhausting a single category quickly, and the "shuffle all categories" practice scenario, were both unsupported.

Sprint 227 closes both gaps simultaneously:

  1. Category expansion: Add Computer Architecture, Design Pattern, Web, Security, and AI alongside the existing Network, OS, Database, Algorithm, and Data Structure categories.
  2. 'ALL' filter: Add an 'ALL' (full random) option to the category PillRadioGroup, drawing from the full 350-question pool at random.

Decision

D1. 5 New Category Enum, CSS Tokens, and Icons (Wave A)

5 new values added to the QuizCategory enum:

  • COMPUTER_ARCHITECTURE / DESIGN_PATTERN / WEB / SECURITY / AI

Palette added 20 lines of --quiz-cat-*-color / --quiz-cat-*-bg CSS variables (light + dark) to globals.css. WCAG AA 4.5:1+ contrast verified directly:

CategoryLight (fg)ContrastDark (fg)Hue distinction from existing 5
arch#B453094.81#FBBF24amber
dp#BE185D5.78#F472B6pink
web#4338CA7.56#818CF8indigo
sec#B91C1C6.19#F87171red
ai#4D7C0F4.78#A3E635lime

category-meta.ts updated with lucide icons (CircuitBoard / Shapes / Globe / ShieldCheck / BrainCircuit) and var-slug mappings for the 5 new categories.

i18n categories object extended with 5 new keys (ko + en) + categories.ALL.

D2. Large-Scale Content via Parallel Generation (Wave B+C)

10 Curator agents run in parallel, one agent per file:

  • 20 questions per new category (7E/7M/6H): computer-architecture.ts / design-pattern.ts / web.ts / security.ts / ai.ts
  • Existing 5 categories 30→50 questions (+20 each): HARD imbalance corrected (network HARD 4→17, os 5→17, database 7→17, targeting 16E/17M/17H each)

index.ts ALL_QUESTIONS integrates all 10 categories → QUIZ_CATEGORIES 10 entries, globally unique IDs totaling 350.

Integration-time discovery and fix: 2 unescaped apostrophes in English text inside single-quoted strings (Brewer's, process's) in database.ts and os.ts → converted to double-quoted strings to eliminate syntax errors.

D3. 'ALL' Filter Addition (Wave D)

index.ts getQuestionsByFilter / getRandomQuestions now accept category: QuizCategory | 'ALL':

  • 'ALL': draws from the full ALL_QUESTIONS pool (mirrors the existing difficulty 'ALL' pattern)
  • Per-category filtering logic unchanged

QuizStart category PillRadioGroup gets an 'ALL' option prepended:

  • Shuffle icon + primary tone
  • Zero new design tokensgetOptionStyle returns undefined for 'ALL' (guard: 'ALL' has no entry in the category meta, so style falls back gracefully)
  • Default selected value changed to 'ALL'

page.tsx Session.category / start parameter propagate 'ALL'. Storage key is ALL::difficulty automatically. stats aggregation ignores 'ALL' key (QUIZ_CATEGORY_META own-key check, meta-mode guard).

D4. Test Suite Full Refresh (Wave E)

Test fileChange
QuizStart.testFull refresh — two 'ALL' ("전체") labels in category + difficulty radiogroups caused getByRole ambiguity → within() scoping, default category 'ALL', 4 new ALL-category tests
index.test+5 — 'ALL' filter behavior
data-integrity.testNew +12 — 350-question unique ID, category, bilingual integrity
category-meta.test5 new category var-slug assertions
page.testKey updates reflecting 'ALL' default

Global: 1533 → 1555 tests (+22).

Implementation

Total atomic commits (start 66820e0):

CommitAgentContent
229da66Palette + HeraldWave A — QuizCategory +5, globals.css 20 lines, category-meta icons/vars, i18n +5 keys + ALL
f8660d1Curator×10 + HeraldWave B+C — 5 new categories 20 questions each, existing 5 +20 each (HARD fix), index.ts ALL_QUESTIONS merge, apostrophe fix ×2
09dc639HeraldWave D — getQuestionsByFilter/getRandomQuestions 'ALL' support, QuizStart 'ALL' prepend, page.tsx propagation, stats 'ALL' ignore
2912955Herald + LibrarianWave E — test suite refresh +22, data-integrity.test new, ADR sprint-227 KR+EN, README 164→165

Verification

  • tsc: 0 errors (apostrophe fixes included)
  • next lint (rtk proxy actual binary): 0 errors / 487 warnings (all pre-existing inline token var() warnings, 0 new)
  • jest: 152 suites / 1555 PASS (+22, 0 failures)
  • Global coverage: lines 88.03% / branches 79.37% (gate 83/71 — pass)
  • Quiz components and data: lines 100% / branches 98.59% (data-integrity /* istanbul ignore */ branches excluded)
  • next build: ✓ /[locale]/quiz 84.8kB (Sprint 224 was 40.2kB → increase: 350 bilingual questions now included in the client bundle per the existing architecture; see Lesson ⑤)
  • ADR gates: index count (sprint 165) / adr-en coverage (KR/EN 1:1) / adr-links 0 broken / doc-refs no broken

Critic Cross-Review

  • Tool: Codex codex-cli 0.130.0, codex review --base 66820e0 -c model=gpt-5.5
  • Rounds: 2

R1 — [P2] 1 finding: The new default category 'ALL' and the 5 new categories were rejected by the backend quiz-record DTO allowlists (original 5 only), so authenticated saveResult (best-effort, swallowed error) silently fails — best records are never saved or merged up. Fixed in fcb1800: identity entity enum +5 / identity & gateway DTO allowlist = 10 categories + 'ALL' / regression specs (gateway +12, identity +13). DB column is varchar(30) so no migration is needed.

R2 — CLEAN (0 P-findings): "The changes type-check across the frontend, gateway, and identity service, and the updated category/ALL flow appears consistently propagated through data, UI, and persistence DTOs. I did not find a discrete introduced bug that would warrant an inline finding." (Codex ran tsc across frontend/gateway/identity.)

Overall verdict: ✅ Mergeable — R1 P2 (missing backend allowlist) fixed, then R2 CLEAN. Global 1555 PASS + backend regression specs; coverage and ADR gates all pass.