# Data Structure for Learning Paths and Courses in Ontology School: A Technical Deep Dive

> Explore Ontology School's data structure for learning paths and courses. Discover how LearnCourse and LearnArticle objects organize content from Markdown into typed JSON manifests. Learn more at Microsoft Ontology Playground.

- Repository: [Microsoft/Ontology-Playground](https://github.com/microsoft/Ontology-Playground)
- Tags: deep-dive
- Published: 2026-07-23

---

**Ontology School implements a hierarchical curriculum model where `LearnCourse` objects containing ordered arrays of `LearnArticle` objects are compiled from Markdown front-matter into a typed JSON manifest at build time.**

The Microsoft Ontology-Playground repository defines the data structure for learning paths and courses in Ontology School through a strongly-typed TypeScript hierarchy. This architecture separates course metadata from individual article content, enabling static site generation while maintaining strict runtime type safety.

## Core TypeScript Interfaces

The fundamental types reside in **[`src/types/learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/types/learn.ts)**, establishing a three-tier hierarchy:

- **`LearnArticle`** – Represents a single learning unit with fields for `slug`, `title`, `description`, numeric `order`, optional `embed` (ontology ID), optional `reviewStatus`, and rendered `html` content
- **`LearnCourse`** – Aggregates articles into a learning path or hands-on lab, containing `slug`, `title`, `description`, `type` (`'path'` | `'lab'`), `icon` (emoji), and an array of `LearnArticle` objects
- **`LearnManifest`** – The root container generated at build time, recording the generation timestamp and exposing an array of `LearnCourse` objects

## Content Organization and Metadata

The curriculum content lives in the `content/learn/` directory, using Markdown files with YAML front-matter to populate the TypeScript interfaces.

**Course-level metadata** is defined in [`_meta.md`](https://github.com/microsoft/Ontology-Playground/blob/main/_meta.md) files within each course subdirectory. For example, [`content/learn/ontology-fundamentals/_meta.md`](https://github.com/microsoft/Ontology-Playground/blob/main/content/learn/ontology-fundamentals/_meta.md) provides the required fields for the `LearnCourse` interface:

```markdown
---
title: Ontology Fundamentals
slug: ontology-fundamentals
description: Core concepts for building knowledge graphs
type: path
icon: 🧠
---

```

**Article front-matter** in individual `*.md` files supplies the data for `LearnArticle` objects. Each article specifies its display sequence via the `order` field:

```markdown
---
title: What Is a Graph?
slug: what-is-a-graph
description: An overview of nodes, edges, and properties
order: 1
---

# What Is a Graph?

A graph consists of **nodes** and **edges**...

```

## Build-Time Compilation Process

The **[`scripts/compile-learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/scripts/compile-learn.ts)** utility transforms the Markdown source into the `LearnManifest` structure. The `compile()` function performs the following operations:

1. **Directory scanning** – Recursively reads `content/learn/` subdirectories
2. **Metadata extraction** – Parses [`_meta.md`](https://github.com/microsoft/Ontology-Playground/blob/main/_meta.md) front-matter to instantiate `LearnCourse` objects
3. **Article processing** – Reads each article file, converts Markdown to sanitized HTML using `marked` and `sanitizeLearnHtml`, and constructs `LearnArticle` instances
4. **Manifest generation** – Assembles the hierarchy and writes [`public/learn.json`](https://github.com/microsoft/Ontology-Playground/blob/main/public/learn.json)

This static compilation step ensures the frontend receives pre-rendered HTML and a fully typed data structure, eliminating runtime Markdown parsing overhead.

## Runtime Data Access

At runtime, the React application fetches the compiled manifest from [`/learn.json`](https://github.com/microsoft/Ontology-Playground/blob/main//learn.json) and consumes the typed hierarchy:

```typescript
import { useEffect, useState } from 'react';
import type { LearnManifest } from '@/src/types/learn';

export const LearnPage = () => {
  const [manifest, setManifest] = useState<LearnManifest | null>(null);

  useEffect(() => {
    fetch('/learn.json')
      .then((r) => r.json())
      .then(setManifest);
  }, []);

  if (!manifest) return <div>Loading…</div>;

  return (
    <div>
      {manifest.courses.map((course) => (
        <section key={course.slug}>
          <h2>{course.icon} {course.title}</h2>
          <ul>
            {course.articles.map((a) => (
              <li key={a.slug}>{a.title}</li>
            ))}
          </ul>
        </section>
      ))}
    </div>
  );
};

```

## Summary

- **Three-layer hierarchy** – `LearnManifest` contains `LearnCourse` arrays, which contain ordered `LearnArticle` arrays
- **Static compilation** – [`scripts/compile-learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/scripts/compile-learn.ts) processes Markdown front-matter and content at build time, outputting typed JSON to [`public/learn.json`](https://github.com/microsoft/Ontology-Playground/blob/main/public/learn.json)
- **Strict typing** – All curriculum entities are strongly typed in [`src/types/learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/types/learn.ts), ensuring compile-time safety for both content creators and frontend developers
- **Separation of concerns** – Course metadata ([`_meta.md`](https://github.com/microsoft/Ontology-Playground/blob/main/_meta.md)) is decoupled from article content, enabling flexible content management while maintaining structural integrity

## Frequently Asked Questions

### What is the relationship between courses and articles in Ontology School?

A `LearnCourse` acts as a container for an ordered collection of `LearnArticle` objects. The course defines the curriculum metadata (title, description, type, icon), while articles represent individual learning units with specific display orders determined by their `order` field.

### How does the build process convert Markdown to the data structure?

The `compile()` function in **[`scripts/compile-learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/scripts/compile-learn.ts)** scans the `content/learn/` directory, parses front-matter from [`_meta.md`](https://github.com/microsoft/Ontology-Playground/blob/main/_meta.md) and article files, converts Markdown bodies to sanitized HTML using `marked` and `sanitizeLearnHtml`, and assembles the results into a `LearnManifest` written to [`public/learn.json`](https://github.com/microsoft/Ontology-Playground/blob/main/public/learn.json).

### What distinguishes a learning path from a lab?

The distinction is captured in the `type` field of the `LearnCourse` interface, which accepts the string literal union `'path' | 'lab'`. Learning paths typically contain sequential theoretical articles, while labs represent hands-on exercises, though both share the same underlying data structure.

### Where is the compiled curriculum data stored and accessed?

The build script generates **[`public/learn.json`](https://github.com/microsoft/Ontology-Playground/blob/main/public/learn.json)**, which serves as the runtime data source. The React frontend fetches this file via standard HTTP requests and casts the response to the `LearnManifest` type defined in [`src/types/learn.ts`](https://github.com/microsoft/Ontology-Playground/blob/main/src/types/learn.ts).