# FablePool Content Schemas (v1) This directory contains the canonical [JSON Schema (draft 2020-12)](https://json-schema.org/draft/2020-12) definitions for all structured content stored and exchanged by FablePool. They are the single source of truth referenced by: - the API layer (request/response validation for authoring endpoints), - the editor (client-side validation before submission), - the import/export pipeline (OER bundles), - the widget registry (manifest validation at publish time), - the grading service (answer-spec and submission validation). ## Files | File | `$id` | Purpose | |---|---|---| | `problem.schema.json` | `https://schemas.fablepool.org/v1/problem.schema.json` | A single **ProblemVersion** document: statement, metadata, rich content model (shared `$defs`), attribution, assets, embedded answer spec / hints / solutions. | | `course.schema.json` | `https://schemas.fablepool.org/v1/course.schema.json` | A single **CourseVersion** document: modules → lessons → items (problem references, quizzes, projects). | | `hint-solution.schema.json` | `https://schemas.fablepool.org/v1/hint-solution.schema.json` | Reusable `Hint` and `Solution` structures (referenced by `problem.schema.json`). | | `widget-manifest.schema.json` | `https://schemas.fablepool.org/v1/widget-manifest.schema.json` | The `widget.json` manifest every sandboxed widget package must ship. | | `attempt-answer.schema.json` | `https://schemas.fablepool.org/v1/attempt-answer.schema.json` | `AnswerSpec` (grading configuration, one variant per problem type), `Submission` (learner answer payloads), `Attempt`, and `AttemptResult`. | ## Resolution model Schemas cross-reference each other with **relative `$ref`s** (e.g. `"$ref": "problem.schema.json#/$defs/RichContent"`), which resolve against each schema's `$id` base URI. Validators must preload all five documents into a shared registry; no network resolution is performed at runtime. - **TypeScript / Node:** Ajv 8 — `ajv.addSchema(...)` each file, then `ajv.getSchema("https://schemas.fablepool.org/v1/problem.schema.json")`. - **Python:** `jsonschema` ≥ 4.18 — build a `referencing.Registry` from the five documents and validate with `Draft202012Validator`. ## Authoring vs. delivery views Schemas describe the **authoring/storage** form, which includes grading keys (correct choices, canonical expressions, hidden test cases). Content served to learners is a **delivery view** derived server-side by stripping the key fields listed in `attempt-answer.schema.json` → `$defs/AnswerSpec` → `x-fablepool-secret` annotations. Grading keys must never reach the client for auto-graded types. See `docs/architecture/03-content-format.md` §6. ## Versioning of the schemas themselves Every document carries a required `schemaVersion` (currently `"1"`). Breaking changes bump the path segment (`/v1/` → `/v2/`) and ship with a migration in the backend. Additive, backward-compatible changes (new optional fields, new enum values guarded by feature detection) do not bump the version. All historical schema versions remain in the repository so archived `ProblemVersion` rows stay validatable forever (see `docs/architecture/04-versioning-and-forking.md`). ## Conventions - All identifiers (`assetId`, choice/item ids, widget names) are constrained to conservative character sets so they are safe in URLs and filenames. - All human-visible strings live in rich-content structures or plain strings — never raw HTML. Sanitization happens at render time from structured data. - Accessibility fields (`alt` on images, `alt` on display math, widget text fallbacks) are **required**, not optional, wherever the schema can enforce it. - LaTeX strings are rendered with KaTeX in `throwOnError: false` mode; schemas cap their length to bound render cost on low-end devices.