Aliases: outline schema, outline json, course outline json, modules topics sections schema

Outline Schema

This document describes the JSON shape of the outline object produced by the course structure pipeline and emitted by the outline-generation workflow before it is merged into the full course record.

This version covers the persisted outline shape, including localized titles and the format-specific payload fields that appear on sections after localization and section generation.

The outline is a nested object with this shape:

modules → topics → sections

For the full course object that contains this outline under course.outline, see Course Schema.


JSON Schema

The schema below mirrors the workflow export in workflows/course/outline-generation/outline-generation.raw.yml, but expands it to include the localization fields and the section payloads used by downstream production workflows.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://fraya.local/schemas/outline.schema.json",
  "title": "Fraya Outline",
  "type": "object",
  "additionalProperties": false,
  "required": ["modules"],
  "properties": {
    "modules": {
      "type": "array",
      "description": "List of course modules",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/Module"
      }
    }
  },
  "$defs": {
    "Module": {
      "type": "object",
      "additionalProperties": false,
      "required": ["title", "topics", "summary", "position"],
      "properties": {
        "title": {
          "type": "string",
          "description": "Module title without numbering prefix"
        },
        "localized_title": {
          "type": "string",
          "description": "Localized module title"
        },
        "summary": {
          "type": "string",
          "description": "Module summary"
        },
        "position": {
          "type": "string",
          "description": "Module position, for example \"1\""
        },
        "topics": {
          "type": "array",
          "description": "List of topics inside the module",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/Topic"
          }
        }
      }
    },
    "Topic": {
      "type": "object",
      "additionalProperties": false,
      "required": ["title", "position", "blueprint", "sections"],
      "properties": {
        "title": {
          "type": "string",
          "description": "Topic title without numbering prefix"
        },
        "localized_title": {
          "type": "string",
          "description": "Localized topic title"
        },
        "position": {
          "type": "string",
          "description": "Topic position in the form [module].[topic], for example \"1.3\""
        },
        "blueprint": {
          "type": "string",
          "description": "Topic blueprint"
        },
        "sections": {
          "type": "array",
          "description": "List of sections inside the topic",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/Section"
          }
        }
      }
    },
    "Section": {
      "type": "object",
      "additionalProperties": false,
      "required": ["section_type", "title", "position", "blueprint", "format"],
      "properties": {
        "section_type": {
          "type": "string",
          "description": "Semantic section type"
        },
        "title": {
          "type": "string",
          "description": "Section title without numbering prefix"
        },
        "localized_title": {
          "type": "string",
          "description": "Localized section title, when present"
        },
        "section_title": {
          "type": "string",
          "description": "Localized section title used by localization workflows"
        },
        "position": {
          "type": "string",
          "description": "Section position in the form [module].[topic].[section], for example \"2.3.10\""
        },
        "blueprint": {
          "type": "string",
          "description": "Section blueprint"
        },
        "format": {
          "type": "string",
          "description": "Presentation format identifier"
        },
        "content": {
          "type": "string",
          "description": "HTML content or script text, depending on the format"
        },
        "content_rendered": {
          "type": "string",
          "description": "Rendered HTML with the media asset embedded"
        },
        "image_data": {
          "$ref": "#/$defs/ImageData"
        },
        "video_data": {
          "$ref": "#/$defs/VideoData"
        },
        "questions": {
          "type": "array",
          "description": "Question blocks for ChoiceQuestions sections",
          "items": {
            "$ref": "#/$defs/QuestionItem"
          }
        },
        "correct_feedback_text": {
          "type": "string",
          "description": "Feedback shown when the full answer set is correct"
        },
        "incorrect_feedback_text": {
          "type": "string",
          "description": "Feedback shown when the answer set is incorrect"
        },
        "placeholders": {
          "type": "array",
          "description": "Blank placeholders for FillTheBlanks sections",
          "items": {
            "$ref": "#/$defs/FillPlaceholder"
          }
        },
        "question_data": {
          "$ref": "#/$defs/QuestionData"
        },
        "artifact_data": {
          "$ref": "#/$defs/ArtifactData"
        }
      },
      "oneOf": [
        {
          "properties": {
            "format": {
              "const": "Text"
            }
          },
          "required": ["content"]
        },
        {
          "properties": {
            "format": {
              "enum": ["VideoPresentation", "VideoTalkingHead", "VideoScenario"]
            }
          },
          "required": ["content", "video_data"]
        },
        {
          "properties": {
            "format": {
              "enum": [
                "TextWithPhoto",
                "TextWithIllustration",
                "TextWithPortrait",
                "TextWithDiagram"
              ]
            }
          },
          "required": ["content", "content_rendered", "image_data"]
        },
        {
          "properties": {
            "format": {
              "const": "ChoiceQuestions"
            }
          },
          "required": ["questions"]
        },
        {
          "properties": {
            "format": {
              "const": "FillTheBlanks"
            }
          },
          "required": [
            "content",
            "correct_feedback_text",
            "incorrect_feedback_text",
            "placeholders"
          ]
        },
        {
          "properties": {
            "format": {
              "const": "QuestionWithFeedback"
            }
          },
          "required": ["content", "question_data"]
        },
        {
          "properties": {
            "format": {
              "const": "Artifact"
            }
          },
          "required": ["content", "artifact_data"]
        }
      ]
    },
    "ImageData": {
      "type": "object",
      "additionalProperties": false,
      "required": ["url"],
      "properties": {
        "prompt": {
          "type": "string",
          "description": "Optional image generation prompt"
        },
        "url": {
          "type": "string",
          "format": "uri",
          "description": "Image URL"
        }
      }
    },
    "VideoData": {
      "type": "object",
      "additionalProperties": false,
      "required": ["platform", "video_id"],
      "properties": {
        "platform": {
          "type": "string",
          "description": "Video platform identifier"
        },
        "video_id": {
          "type": "string",
          "description": "Platform video identifier"
        }
      }
    },
    "ArtifactData": {
      "type": "object",
      "additionalProperties": false,
      "required": ["path"],
      "properties": {
        "path": {
          "type": "string",
          "description": "Artifact path"
        }
      }
    },
    "QuestionItem": {
      "oneOf": [
        {
          "$ref": "#/$defs/SingleChoiceQuestion"
        },
        {
          "$ref": "#/$defs/MultiChoiceQuestion"
        }
      ]
    },
    "SingleChoiceQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "question", "possible_answers"],
      "properties": {
        "type": {
          "type": "string",
          "const": "SingleChoiceQuestion"
        },
        "question": {
          "type": "string",
          "description": "Question text"
        },
        "possible_answers": {
          "type": "array",
          "description": "Answer options",
          "items": {
            "$ref": "#/$defs/SingleChoiceAnswer"
          }
        }
      }
    },
    "MultiChoiceQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "type",
        "question",
        "possible_answers",
        "correct_feedback_text",
        "incorrect_feedback_text"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "MultiChoiceQuestion"
        },
        "question": {
          "type": "string",
          "description": "Question text"
        },
        "possible_answers": {
          "type": "array",
          "description": "Answer options",
          "items": {
            "$ref": "#/$defs/MultiChoiceAnswer"
          }
        },
        "correct_feedback_text": {
          "type": "string",
          "description": "Feedback for correct multi-answer combinations"
        },
        "incorrect_feedback_text": {
          "type": "string",
          "description": "Feedback for incorrect multi-answer combinations"
        }
      }
    },
    "SingleChoiceAnswer": {
      "type": "object",
      "additionalProperties": false,
      "required": ["text", "correct", "feedback_text"],
      "properties": {
        "text": {
          "type": "string",
          "description": "Answer option text"
        },
        "correct": {
          "type": "boolean",
          "description": "Whether the answer is correct"
        },
        "feedback_text": {
          "type": "string",
          "description": "Answer-specific feedback text"
        }
      }
    },
    "MultiChoiceAnswer": {
      "type": "object",
      "additionalProperties": false,
      "required": ["text", "correct"],
      "properties": {
        "text": {
          "type": "string",
          "description": "Answer option text"
        },
        "correct": {
          "type": "boolean",
          "description": "Whether the answer is part of the correct set"
        }
      }
    },
    "FillPlaceholder": {
      "type": "object",
      "additionalProperties": false,
      "required": ["index", "type", "options"],
      "properties": {
        "index": {
          "type": "integer",
          "description": "Placeholder index"
        },
        "type": {
          "type": "string",
          "enum": ["dropdown", "input"]
        },
        "options": {
          "type": "array",
          "description": "Answer options for the blank",
          "items": {
            "$ref": "#/$defs/FillOption"
          }
        }
      }
    },
    "FillOption": {
      "type": "object",
      "additionalProperties": false,
      "required": ["text", "correct"],
      "properties": {
        "text": {
          "type": "string",
          "description": "Option text"
        },
        "correct": {
          "type": "boolean",
          "description": "Whether the option is correct"
        }
      }
    },
    "QuestionData": {
      "type": "object",
      "additionalProperties": false,
      "required": ["question", "criteria"],
      "properties": {
        "question": {
          "type": "string",
          "description": "Question text"
        },
        "criteria": {
          "type": "string",
          "description": "Evaluation criteria"
        }
      }
    }
  }
}

Structural Rules

  • modules is required and must contain at least one module.
  • Each module must have title, summary, position, and topics.
  • localized_title is optional on modules and topics.
  • Each topic must have title, position, blueprint, and sections.
  • localized_title and section_title are optional on sections.
  • Each section must have section_type, title, position, blueprint, and format.
  • ChoiceQuestions sections use questions with SingleChoiceQuestion and MultiChoiceQuestion items.
  • FillTheBlanks sections use placeholders plus the feedback fields shown above.
  • QuestionWithFeedback sections use question_data.question and question_data.criteria.
  • Artifact sections use artifact_data.path.
  • additionalProperties is false at every object level.
  • Titles in the outline JSON are plain strings without numbering prefixes.
  • position values are hierarchical strings and must preserve the source outline order.
  • The disabled Question format is intentionally excluded from this active schema.