openfreebooks-bookgenerator/.agents/skills/ofb/curriculum-data.md

5.1 KiB
Raw Permalink Blame History

Curriculum & catalog data

data/catalog.json

Site-wide catalog chrome.

{
  "title": "Curriculum Catalog",
  "subtitle": "Browse chapters by subject and curriculum",
  "curriculums": ["Foundation", "DSE", "IB", "A-Level", "AP", "IGCSE", "Common Core"],
  "subjects": [
    { "id": "math", "name": "Mathematics" }
  ]
}
Field Rules
id kebab-case, URL-safe; becomes ?subject= and path prefix /{id}/
name Display label in sidebar
curriculums Union of all filter chips; add new labels here first

data/{subject}-curriculum.json

Example: data/math-curriculum.json.

{
  "title": "Mathematics",
  "subtitle": "Optional; deprecated — do not use HKDSE-only framing. Catalog chrome uses data/catalog.json.",
  "intro": "Optional subject-level intro (not shown in catalog UI today)",
  "intro": "Optional; was used by old book page",
  "graph": {
    "edges": [
      { "from": "quadratic-equations", "to": "sequences-series" },
      { "from": "quadratic-equations", "to": "functions-graphs" },
      { "from": "functions-graphs", "to": "linear-programming" }
    ]
  },
  "strands": [
    {
      "id": "number-algebra",
      "title": "Number & Algebra",
      "chapters": [
        {
          "slug": "quadratic-equations",
          "title": "Quadratic equations",
          "description": "One or two sentences shown in list and map views.",
          "status": "live",
          "curriculums": ["DSE", "IB"]
        }
      ]
    }
  ]
}

Chapter fields

Field Required Notes
slug yes Matches content/{subject}/{slug}/; kebab-case
title yes Catalog list + map node label
description yes 1–2 sentences; shown in list and map cards (clamped to 3 lines on map)
status yes live (link to chapter) or planned (no link)
curriculumCoverage yes (math) Object mapping framework label → core | extension | related (Compare matrix + filters)
curriculums legacy Deprecated array; use curriculumCoverage instead
tier no foundation (default) or non-foundation — shows an Extension badge on cards (DSE M2-style topics)

Graph model (map)

Rule Detail
Scope DSE compulsory topic units (~25–35 chapters); primary/junior not in JSON yet
Edges Required prerequisites only; graph.edges is the sole source (no auto chain from strand array order)
Scope of from/to Any chapter slug — cross-strand edges allowed (arrows may cross columns)
Levels Longest-path from roots: level = 1 + max(level(parent)); roots at 0
List order strands[].chapters[] array order is for the list tab only (authoring / ToC)
Roots Multiple level-0 chapters per strand OK; edgeless placeholders OK while drafting

Graph edges

  • from / to are chapter slugs (not node ids).
  • Edges must form a DAG (no cycles). Map builder throws on cycles.
  • One prerequisite → add one edge. Multiple parents → multiple edges into the same to.
  • Branches: one from → many to (e.g. quadratics → sequences and functions-graphs).
  • Merges: many from → one to (e.g. functions + sequences → linear programming).

Wiring into catalog

themes/openfreebooks/templates/catalog.html exposes strands + graph in #catalog-data by loading data/{subject.id}-curriculum.json for each catalog subject.

{% for subject in catalog.subjects %}
{% set subject_curriculum = load_data(path="data/" ~ subject.id ~ "-curriculum.json", format="json") %}
...
"strands": {{ subject_curriculum.strands | default(value=[]) | json_encode() | safe }}
{% endfor %}

Status: planned vs live

status Catalog list Map node Content required
planned Shown, “Coming soon” badge Card shown; title not linked Only JSON entry
live Full card links to chapter Title links to chapter (→ + underline); rest of card not clickable content/ + HTML partial + template wiring

Map view is Mermaid-based (CatalogMermaidView + catalog-to-mermaid.ts) and uses graph.edges as the source-of-truth DAG.

Adding a curriculum label

  1. Add string to data/catalog.json → curriculums.
  2. Tag chapters with that string in curriculums arrays.
  3. Add .catalog-badge--{name} in _catalog.scss (see existing --dse, --ib, …).
  4. Optional: curriculumBadgeClass() in frontend/src/lib/catalog-badge.ts (defaults exist).

Map card heights (agents)

Do not hand-place map node positions. The pipeline is:

  1. subjectToMermaid() builds Mermaid source from strands + graph.edges.
  2. CatalogMermaidView renders with Mermaid (theme: "base" + hex theme variables).
  3. enhanceStrandClusterHeaders() post-processes strand header chrome in SVG.

Card markup must stay in sync between catalog-chapter-card.tsx (Solid + renderCatalogChapterCardElement) and _catalog.scss (especially .catalog-chapter-card--map).

Validation

  • bun run validate:curriculum (scripted checks for slugs, curricula labels, live content paths, and DAG acyclicity).
  • bun run build succeeds.