02

Modeling the Curriculum as a Graph

A build retrospective on the adaptive knowledge graph behind Amal, a kids' Arabic-learning app used by 95,000+ families. • Day 2 makes the graph concrete: the exact tables that store the concepts, the prerequisite edges between them, and the pictures and audio each concept carries.

The three things a curriculum graph needs to store

Day 1 made the bet: store the curriculum as a graphnodes (the things you teach) joined by edges (how they depend on each other) — instead of a flat list. To turn that idea into a real database, you need to store exactly three things, and it helps to name them before seeing any code:

  • Concepts — the nodes. One teachable idea each: the letter ب, the sound /b/, "addition up to 10", a Quran surah. This is what there is to learn.
  • Dependencies — the edges. "Concept A must come before concept B." This is the order knowledge has to be learned in.
  • Assets — the pictures, audio, and media that let a concept actually be shown to a child. A concept is an idea; an asset is how that idea appears on screen.

Amal stores each of these as its own table. The names below are the real ones from the system, and the rest of this day walks through each in turn.

The diagram shows the shape: one table of concept nodes, one table of prerequisite edges pointing between those nodes, and one table of assets hanging off each node. Everything else in this course reads from these three tables.

   THE CURRICULUM GRAPH = THREE TABLES

   ┌─────────────────────┐        ┌────────────────────────┐
   │ curriculum_concepts │◄──────┤ concept_dependencies   │
   │   (the NODES)       │  edges │   (the EDGES)          │
   └──────────┬──────────┘        └────────────────────────┘
              │ has media
              ▼
   ┌─────────────────────┐
   │  concept_assets     │
   │  (images / audio)   │
   └─────────────────────┘

The nodes: `curriculum_concepts`

A node is a single row in curriculum_concepts, and it represents one concept — the smallest teachable unit the curriculum knows about. "The letter baa (ب)" is one concept; "the sound /b/" is another; "the word baab" is another. Keeping concepts small is deliberate: the smaller each node, the more precisely the system can later say "this exact idea is the thing this child is missing."

Think of each row as carrying an id, a human label, and which domain it belongs to (Arabic, Math, English, Grammar):

-- one row per teachable concept (a graph NODE)
SELECT id, label, domain
FROM curriculum_concepts
WHERE domain = 'arabic'
LIMIT 3;

-- id    | label           | domain
-- b_ltr | letter baa (ب)  | arabic
-- b_snd | sound /b/       | arabic
-- baab  | word "baab"     | arabic

That is the entire idea of a node: a stable id you can point at, a label a human can read, and enough metadata to find it. Nothing about order lives here — a concept does not know what comes before or after it. That relationship is stored separately, on purpose, which is the next table.

The edges: `concept_dependencies`

An edge is a single row in concept_dependencies, and it records one prerequisite: "concept X must be learned before concept Y." Storing order between concepts rather than inside them is the key modeling choice — it is what lets the same concept sit in many different learning paths without being rewritten.

Each row is just a pair of concept ids — a "from" (the prerequisite) and a "to" (the thing it unlocks):

-- one row per prerequisite (a graph EDGE: prereq -> unlocks)
SELECT prerequisite_id, concept_id
FROM concept_dependencies;

-- prerequisite_id | concept_id
-- b_ltr           | b_snd        -- know the letter before its sound
-- b_snd           | baab         -- know the sound before the word

Because edges are their own rows, the graph can branch and merge freely: one concept can be a prerequisite for many others, and one concept can require several prerequisites at once. That is exactly the structure a flat list could not express. It is also what lets the software, later, walk backwards from "the word baab" and discover every foundation it rests on.

The assets: `concept_assets`

An asset is a row in concept_assets, and it is the media that makes a concept showable — the picture of a door for baab, the letter glyph for ب, the audio clip that pronounces /b/. A concept is an abstract idea; a child cannot see an idea, so every concept that appears on screen needs at least one asset tied to it.

-- media attached to a concept (so it can be SHOWN)
SELECT concept_id, kind, url
FROM concept_assets
WHERE concept_id = 'baab';

-- concept_id | kind  | url
-- baab       | image | .../door.png
-- baab       | audio | .../baab.mp3

Separating assets from concepts matters for the same reason separating edges did: one concept can carry many assets (an image, an audio clip, a letter form), and swapping a nicer picture later never touches the concept or its place in the graph. The idea and its presentation are kept apart, so either can change without disturbing the other.

Worked example: the letter ب becomes a small graph

Now put the three tables together on one real example — the path from the letter ب to reading the word baab ("door") — because seeing the whole thing assembled is what makes the model click.

The concept ب (baa) is a node. Knowing the letter is a prerequisite for knowing its sound /b/, which is a prerequisite for reading a word that uses it, like baab. And baab also depends on knowing how Arabic letters change shape when they join — the connected forms — because the ب in baab is written in its joined form, not its isolated one. Each of those is an edge; each concept carries its own assets.

The diagram is the payoff of the whole day: three concept nodes, the prerequisite edges that order them (letter → sound → word), a fourth concept (connected forms) that the word also depends on, and the assets that let each concept be shown. This tiny four-node graph is a real slice of the curriculum — and the full Amal graph is thousands of nodes just like these, wired together the same way.

Two properties of this structure carry the rest of the course:

  • You can traverse it. Starting from any concept, you can follow edges backward to find every prerequisite, or forward to find everything it unlocks. Days 4–5 turn that traversal into each child's personal path.
  • It is presentation-free. The graph stores ideas and their order, not finished screens. Nothing here says "app lesson" or "PDF" — that is why one node can later feed every surface (Days 6–7).
   ONE SMALL CURRICULUM GRAPH (nodes + edges + assets)

   ┌──────────────┐  edge   ┌──────────────┐  edge   ┌──────────────┐
   │ letter baa   │────────►│  sound /b/   │────────►│ word "baab"  │
   │   (ب)        │         │              │         │  (door)      │
   └──────┬───────┘         └──────────────┘         └──────┬───────┘
          │ asset                                           │ asset
          ▼                                                 ▼
     [ ب glyph ]                                    [ door image + audio ]

              ┌───────────────────┐    edge
              │ connected forms   │────────────────────────┘
              │ (joined letters)  │
              └───────────────────┘

Key takeaways

  • A curriculum graph needs exactly three kinds of storage: concepts (nodes), dependencies (edges), and assets (media), and Amal stores each as its own table.
  • curriculum_concepts holds one row per small teachable concept — an id, a label, a domain — and deliberately stores no ordering inside the node.
  • concept_dependencies holds one row per prerequisite edge (prerequisite → unlocks); keeping order in its own table lets one concept live in many paths and lets the graph branch and merge.
  • concept_assets holds the images and audio that make a concept showable, kept separate so presentation can change without touching the idea or its place in the graph.
  • The worked ب → /b/ → baab graph (plus a "connected forms" prerequisite) is a real slice of the curriculum; the full graph is thousands of such nodes, traversable and presentation-free — the two properties every later day relies on.

Checklist

  • [ ] I can name the three tables and say what each stores (curriculum_concepts, concept_dependencies, concept_assets).
  • [ ] I can explain why order is stored as edges between concepts rather than inside each concept.
  • [ ] I can explain why assets are kept in their own table separate from concepts.
  • [ ] I can draw the ب → /b/ → baab graph and mark which arrows are prerequisite edges.
  • [ ] I can state the two properties — traversable and presentation-free — that the rest of the course builds on.