Quiz JSON schema
Every quiz is one JSON file at content/quizzes/<slug>.json. The filename must
match the slug field. Here is a complete example:
{
"slug": "which-element-are-you",
"title": "Which Element Are You?",
"description": "Discover your dominant element.",
"enabled": true,
"questions": [
{
"id": "q1",
"text": "Pick a place to relax.",
"options": [
{ "id": "q1-a", "text": "A windy cliff", "scores": { "air": 2, "fire": 1 } },
{ "id": "q1-b", "text": "A warm hearth", "scores": { "fire": 3 } }
]
}
],
"results": [
{ "id": "air", "title": "Air", "description": "Free-spirited and curious." },
{ "id": "fire", "title": "Fire", "description": "Passionate and bold." }
]
} Top-level fields
| Field | Type | Rules |
|---|---|---|
slug | string | lowercase kebab-case (a-z, 0-9, hyphens); must equal the filename |
title | string | shown on the homepage and quiz page; 1–200 chars |
description | string | one-paragraph intro; 1–500 chars |
enabled | boolean | false hides the quiz from the public site (admins still see it) |
questions | array | 1–100 questions; order = play order |
results | array | 1–20 results; order = tie-break order |
Question fields
| Field | Type | Rules |
|---|---|---|
id | string | unique within the quiz; convention is q1, q2, … |
text | string | the question shown to the player |
options | array | 2–10 options |
Option fields
| Field | Type | Rules |
|---|---|---|
id | string | unique within its question; convention q1-a, q1-b, … |
text | string | the answer label |
scores | object | maps result id → integer points (see below) |
scores must only reference result ids that exist in results, and values must
be integers. An option may feed multiple results, e.g. { "air": 2, "fire": 1 }.
Result fields
| Field | Type | Rules |
|---|---|---|
id | string | unique; referenced by scores |
title | string | headline of the result card |
description | string | body of the result card |
Validation
Before a quiz can be enabled it must pass validation:
- valid JSON, all required fields present;
- slug matches filename and kebab-case;
- every question and option id unique;
- every option has ≥ 2 sibling options and valid
scores; - every
scoreskey references an existing result; - at least one result is reachable (a warning, not an error).
A quiz that fails validation shows Broken in the admin dashboard and displays a friendly “this quiz is broken” page on its public link.