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.
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-verificationrunbook).
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:
- Category expansion: Add Computer Architecture, Design Pattern, Web, Security, and AI alongside the existing Network, OS, Database, Algorithm, and Data Structure categories.
- '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:
| Category | Light (fg) | Contrast | Dark (fg) | Hue distinction from existing 5 |
|---|---|---|---|---|
| arch | #B45309 | 4.81 | #FBBF24 | amber |
| dp | #BE185D | 5.78 | #F472B6 | pink |
| web | #4338CA | 7.56 | #818CF8 | indigo |
| sec | #B91C1C | 6.19 | #F87171 | red |
| ai | #4D7C0F | 4.78 | #A3E635 | lime |
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 fullALL_QUESTIONSpool (mirrors the existing difficulty'ALL'pattern)- Per-category filtering logic unchanged
QuizStart category PillRadioGroup gets an 'ALL' option prepended:
Shuffleicon + primary tone- Zero new design tokens —
getOptionStylereturnsundefinedfor'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 file | Change |
|---|---|
QuizStart.test | Full 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.test | New +12 — 350-question unique ID, category, bilingual integrity |
category-meta.test | 5 new category var-slug assertions |
page.test | Key updates reflecting 'ALL' default |
Global: 1533 → 1555 tests (+22).
Implementation
Total atomic commits (start 66820e0):
| Commit | Agent | Content |
|---|---|---|
229da66 | Palette + Herald | Wave A — QuizCategory +5, globals.css 20 lines, category-meta icons/vars, i18n +5 keys + ALL |
f8660d1 | Curator×10 + Herald | Wave B+C — 5 new categories 20 questions each, existing 5 +20 each (HARD fix), index.ts ALL_QUESTIONS merge, apostrophe fix ×2 |
09dc639 | Herald | Wave D — getQuestionsByFilter/getRandomQuestions 'ALL' support, QuizStart 'ALL' prepend, page.tsx propagation, stats 'ALL' ignore |
2912955 | Herald + Librarian | Wave 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]/quiz84.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.