Browser-playable multilingual quizzes from a verified English bank, AI used only to translate + to craft quizzes via a chat-bubble wizard.
1. π /ymlsum
project: QuizWizz π§
type: WordPress plugin (FOSS, GPLv2+)
one_liner: Browser-playable multilingual quizzes from a verified English bank,
AI used only to translate + to craft quizzes via a chat-bubble wizard.
platform: {wp: "7.0 Armstrong", php: "8.5 (min 8.3)", db: "MySQL/MariaDB", react: 18}
principle: DATASET-IS-TRUTH βΈ no fact-generation. AI scope = {batch_translate, chat_craft} only.
data_model: # native, no bloat
cpts: [quiz, question] # custom post types
taxes: [subject, difficulty, language, tag]
store: question{stem, type, choices[], correct_idx, explanation, src, lang}
note: Uses PDO SQLite database (opentdb.sqlite) instead of wp_remote_get for zero-latency lookups
quiz_sources:
primary: OpenTDB (Bundled local SQLite DB, ultra-fast ORDER BY RANDOM() LIMIT, pre-translated swarm localization)
big_bank: TriviaQA (~95k) # volume, human-authored, CC BY 4.0 (open-answerβ1Γ distractor prep)
academic: Global-MMLU # 42 langs PRE-translated, 57 subjects (skip translation!)
ai:
gateway: OpenRouter # OpenAI-compatible /chat/completions, SSE streaming
picker: GET /api/v1/models?order=newest # cache+refresh hourly β model dropdown
selectable:[model, prompt] # both user-editable, every call
cost_ctrl: [":floor variant", "max_tokens cap", "BYOK", spend-limit]
jobs:
translate: batch job (WP-Cron) β store per-language question sets
agent: "Magical Quiz Wizz" floating chat bubble β NL input β quiz draft
json: response_format=json_schema # reliable question objects
key: server-side only (wp-config/env) β NEVER client JS
play: # "on location, simply in browser"
engine: Alpine.js (~7kB, no build) renders + grades client-side
data: quiz JSON localized via wp_localize_script / REST
resume: localStorage (real plugin only; not in WP artifacts)
modes: [practice, timed, shuffle, Form-A/B/C]
output:
print: window.print() + @media print CSS # zero-dep results sheet + answer key
pdf_srv: mPDF 8.3.1 (optional, for saved/emailed/non-Latin)
share: Web Share API (navigator.share) + Open Graph meta
admin: # most-genius WP 7.0 backend
ui: Data Views (filter/sort quizzes & questions, native 7.0)
ability: register quiz-gen as a WP Abilities API ability (plugs into 7.0 AI hub)
settings: @wordpress/components React page β /wp/v2/settings (show_in_rest)
block: dynamic block apiVersion 3 (embed quiz on any page)
security: [cap_check β nonce β sanitize β ESCAPE, $wpdb->prepare(%s %d %i),
"defined('ABSPATH')||exit", permission_callback on EVERY route,
sanitize HTML before mPDF]
qa: [Plugin Check (mandatory), PHPCS+WPCS, PHPUnit, 2FA on wp.org acct]
i18n: __()/esc_html__() + .pot
milestones:
m1: CPT + OpenTDB import + Alpine browser play + print sheet # playable MVP
m2: OpenRouter model-picker + batch translate + Data Views admin # multilingual + backend
m3: "Magical Quiz Wizz" chat-bubble agent (NLβquiz) + share # the magic
m4: security pass + Plugin Check green β package/ship
non_goals: [LMS/courses, payments, per-user accounts (v1), server-side grading]
foss_purity: OpenRouter = the ONLY SaaS dep; swap for LibreTranslate + Ollama/vLLM = 100% self-host
risks: [MT loses cultureβspot-check, distractor driftβre-validate,
mPDF dated CSSβuse print/headless-chrome, SSE bufferingβnon-stream fallback]2. π Rollout
| Phase | Build | β Done when |
|---|---|---|
| β 1 MVP | CPT + OpenTDB import + Alpine play + print sheet | quiz is playable & printable |
| β 2 Multi | model picker + batch translate + Data Views admin | quiz works in N languages |
| [ ] 3 Magic | π§ chat-bubble wizard (NLβquiz) + share | promptβquiz in one chat |
| [ ] 4 Ship | security pass + Plugin Check green | zero errors β package |
3. π YAGNI Loop
Copy-paste, point at any builder piece (form/route/admin/code), run until it self-certifies. Philosophy: perfection = 0 defects on required scope + 0 unrequired scope. Adding is easier than fixing, so cut first, then polish.
ROLE: Ruthless senior reviewer. MANDATE: make it perfectly do EXACTLY what the SPEC needs β nothing more.
SPEC (the only thing that matters):
User picks {category(ies), count, difficulty, mode β {online, print}, language}
β a correct, valid quiz is produced, every time, on every edge case.
ARTIFACT UNDER REVIEW: <paste code / component / route / admin feature>
ββββββββββββββββ THE LOOP (repeat each pass) ββββββββββββββββ
1. βοΈ YAGNI SWEEP β for every field/feature/branch/dependency/abstraction:
ask 3: (a) Required by SPEC *now*? (b) Does removing it break SPEC? (c) Cheaper to add later than carry now?
β if NOT-required & doesn't-break & cheaper-later β CUT IT (log as βοΈ). List all cuts first.
2. π SCAN the 8 LENSES β log EVERY issue found.
3. π·οΈ CLASSIFY each by severity (rubric below).
4. π§ FIX only the highest-severity batch β one concern at a time, smallest change.
5. β
VERIFY the fix + scan for regressions it introduced.
6. β» RE-RUN from step 1 on the changed artifact.
EXIT (stop, do NOT gold-plate) when ALL true:
β’ 0 P0 and 0 P1 issues
β’ YAGNI sweep finds nothing left to cut
β’ every SPEC acceptance test passes (incl. edge cases)
ββββββββββββββββ 8 LENSES ββββββββββββββββ
β
Correctness edge cases: 0 results Β· count > pool Β· empty category Β· all-difficulties Β· mixed split Β· RTL/non-Latin lang Β· mode switch mid-build
π Security capβnonceβsanitizeβescape Β· count clamped SERVER-side Β· key never client-side Β· $wpdb->prepare(%s %d %i)
βΏ A11y keyboard-only Β· ARIA roles/labels Β· focus mgmt Β· contrast
π± UX states present (empty/loading/error/success) Β· mobile Β· one obvious action
β‘ Perf no N+1 Β· pool-count & model-list cached Β· minimal payload
π§© Simplicity fewest moving parts Β· no dead code Β· no unused deps Β· no premature abstraction β YAGNI lives here
π i18n strings wrapped Β· translated data renders Β· fonts load
π’ Ship Plugin Check Β· WPCS Β· clear names Β· docblocks on public API
ββββββββββββββββ SEVERITY ββββββββββββββββ
P0 broken / insecure / data-loss β fix immediately
P1 wrong on an edge case / SPEC gap β fix this pass
P2 UX / perf friction β fix if cheap
P3 cosmetic polish β fix only if free
ββββββββββββββββ OUTPUT EACH PASS ββββββββββββββββ
1) βοΈ CUTS: bullet list of everything removed/deferred + why
2) ISSUE TABLE: | # | Lens | Sev | Issue | Fix / βοΈCUT |
3) REVISED ARTIFACT: the diff (changed lines only)
4) VERDICT: π LOOP AGAIN | β
PERFECT (SPEC met Β· nothing to cut Β· all tests green)Contents
- π π Documentation