From 306d91be368b4836d205e82595dbfe4aec728a07 Mon Sep 17 00:00:00 2001 From: Agrendalath Date: Thu, 20 Aug 2026 19:40:36 +0200 Subject: [PATCH 1/3] docs: add ADR for pathway catalog and content split --- .../0004-pathway-catalog-content-split.rst | 75 +++++++++++++++++++ .../images/pathway-catalog-content.dot | 21 ++++++ .../images/pathway-catalog-content.svg | 66 ++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst create mode 100644 docs/openedx_learning/decisions/images/pathway-catalog-content.dot create mode 100644 docs/openedx_learning/decisions/images/pathway-catalog-content.svg diff --git a/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst new file mode 100644 index 000000000..61a609f4c --- /dev/null +++ b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst @@ -0,0 +1,75 @@ +.. _openedx-learning-adr-0004: + +4. Pathways: Split Between Catalog and Content +============================================== + +Status +------ + +Draft + +Context +------- + +Courses in ``openedx-core`` already separate the *catalog* side (``openedx_catalog``: ``CatalogCourse``, +``CourseRun`` - what learners browse and enroll against) from the *content* side (``openedx_content`` - what is +authored, versioned, and published). Pathways have the same two aspects, and the same reasons to keep them apart: + +- **Different change rates.** The display name, description shown in the catalog, and SEO metadata are revised + frequently and casually. The definition of what a learner must do to complete the Pathway changes rarely and + deliberately. +- **Different people doing the editing.** Catalog data is typically maintained by marketing or communications staff; + the Pathway definition is maintained by content authors. Both are visible to learners, so the distinction is about + who edits what, not about who can see it. +- **Different permissions follow from that.** We expect instances to want to let marketing staff update catalog + copy without granting them the ability to change what learners must complete, and vice versa. Keeping the two + apart makes that possible without inventing field-level permissions. +- **Auditability.** Progress and credentials must be judged against the definition that was in effect at the time, + which requires versioning the definition - but versioning catalog copy would be pure overhead. + +Decisions +--------- + +1. A Pathway is split into two parts: + + - **Catalog Pathway** - the learner-browsable, enrollable thing. It includes the display name, the description + shown in the catalog, SEO metadata, and a **Category**: a student-facing label for the kind of Pathway it is + (e.g. "Master's Degree", "Annual Training"). If it is specified, learners see the Category instead of the word + "Pathway". The Catalog Pathway is **not versioned**. + + - **Pathway content** - the definition of the Pathway: its Items and its completion criteria. The content is + **versioned**, so that we can always tell what the definition was at the moment a learner enrolled or earned a + credential. + +2. In authoring contexts (Studio, Django admin, code, docs), the terminology is always "Pathway", with the Category + shown explicitly. Relabelling is a learner-facing concern of the catalog side only. + +3. Learners enroll against the Catalog Pathway. Progress and credential evaluation run against a version of the + Pathway content. + +Example content of each model: + +============================ ========================== +Catalog Pathway Pathway content +============================ ========================== +Display name Pathway Items +Category Completion criteria +Description +SEO metadata +Enrollment +============================ ========================== + +.. Run `dot -Tsvg images/pathway-catalog-content.dot > images/pathway-catalog-content.svg` to regenerate the diagram + after making changes to `images/pathway-catalog-content.dot`. + +.. image:: images/pathway-catalog-content.svg + :alt: Catalog Pathway vs versioned Pathway content + :width: 100% + +Consequences +------------ + +- Catalog edits never create new content versions; definition edits (Items, criteria) always do. +- Credential and progress records can reference the exact content version in effect at the time, keeping them + auditable after the Pathway changes. +- The unversioned Catalog Pathway can be long-lived even if its content definition is changed significantly over time. diff --git a/docs/openedx_learning/decisions/images/pathway-catalog-content.dot b/docs/openedx_learning/decisions/images/pathway-catalog-content.dot new file mode 100644 index 000000000..892a70951 --- /dev/null +++ b/docs/openedx_learning/decisions/images/pathway-catalog-content.dot @@ -0,0 +1,21 @@ +digraph pathway_catalog_content { + rankdir=LR; + fontname="Helvetica"; + node [shape=box, style=rounded, fontname="Helvetica", fontsize=11]; + edge [fontname="Helvetica", fontsize=10]; + + learner [label="Learner", shape=ellipse]; + catalog [label="Catalog Pathway\n(not versioned)\nname, Category,\nmarketing, SEO"]; + + subgraph cluster_content { + label="Pathway content (versioned)"; + fontsize=11; + style=dashed; + v1 [label="v1: Items, criteria"]; + v2 [label="v2: Items, criteria"]; + v1 -> v2 [style=dotted, label="revision"]; + } + + learner -> catalog [label="browses / enrolls"]; + catalog -> v2 [label="current definition"]; +} diff --git a/docs/openedx_learning/decisions/images/pathway-catalog-content.svg b/docs/openedx_learning/decisions/images/pathway-catalog-content.svg new file mode 100644 index 000000000..050606d86 --- /dev/null +++ b/docs/openedx_learning/decisions/images/pathway-catalog-content.svg @@ -0,0 +1,66 @@ + + + + + + +pathway_catalog_content + + +cluster_content + +Pathway content (versioned) + + + +learner + +Learner + + + +catalog + +Catalog Pathway +(not versioned) +name, Category, +marketing, SEO + + + +learner->catalog + + +browses / enrolls + + + +v2 + +v2: Items, criteria + + + +catalog->v2 + + +current definition + + + +v1 + +v1: Items, criteria + + + +v1->v2 + + +revision + + + From 9218009000d111731295eab09692538f234d7d35 Mon Sep 17 00:00:00 2001 From: Agrendalath Date: Tue, 25 Aug 2026 20:04:26 +0200 Subject: [PATCH 2/3] fixup! docs: add ADR for pathway catalog and content split --- .../0004-pathway-catalog-content-split.rst | 44 ++++-- .../images/pathway-catalog-content.dot | 37 +++-- .../images/pathway-catalog-content.svg | 131 ++++++++++++------ 3 files changed, 147 insertions(+), 65 deletions(-) diff --git a/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst index 61a609f4c..96eaf13d8 100644 --- a/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst +++ b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst @@ -33,31 +33,43 @@ Decisions 1. A Pathway is split into two parts: - **Catalog Pathway** - the learner-browsable, enrollable thing. It includes the display name, the description - shown in the catalog, SEO metadata, and a **Category**: a student-facing label for the kind of Pathway it is - (e.g. "Master's Degree", "Annual Training"). If it is specified, learners see the Category instead of the word - "Pathway". The Catalog Pathway is **not versioned**. + shown in the catalog, SEO metadata, and a **Category**. It is **not versioned**. - **Pathway content** - the definition of the Pathway: its Items and its completion criteria. The content is - **versioned**, so that we can always tell what the definition was at the moment a learner enrolled or earned a - credential. + **versioned**, so that we can always tell what the definition was at any given moment. A version of the Pathway + content *implements* a Catalog Pathway. -2. In authoring contexts (Studio, Django admin, code, docs), the terminology is always "Pathway", with the Category +2. The **Category** is a student-facing label for the kind of Pathway (e.g. "Master's Degree", "Annual Training"). + Learners see the Category rather than the word "Pathway". It is always required: rather than falling back to + "Pathway" in code, we ship a default database entry with that name, so the behavior is uniform and operators can + rename or extend the set without a code change. + +3. In authoring contexts (Studio, Django admin, code, docs), the terminology is always "Pathway", with the Category shown explicitly. Relabelling is a learner-facing concern of the catalog side only. -3. Learners enroll against the Catalog Pathway. Progress and credential evaluation run against a version of the - Pathway content. +4. **Dependency direction**: ``openedx_content`` knows about ``openedx_catalog``, never the reverse. This has the + following consequences: + + - Pathway Items may reference ``CourseRun`` entities directly. + - The link from a Catalog Pathway to the Pathway content that implements it lives on the content side. + - Anything that has to tie the two sides together belongs in ``openedx_content``, or in something downstream of + it, but never in ``openedx_catalog``. + +5. **Enrollment** ties a learner to a Catalog Pathway. Progress is evaluated against the currently published + content version, not against a version frozen at enrollment time, so that authoring changes reach learners who + are already enrolled. Example content of each model: -============================ ========================== +============================ =================================== Catalog Pathway Pathway content -============================ ========================== +============================ =================================== Display name Pathway Items Category Completion criteria -Description -SEO metadata +Description References to CourseRuns +SEO metadata Link to the related Catalog Pathway Enrollment -============================ ========================== +============================ =================================== .. Run `dot -Tsvg images/pathway-catalog-content.dot > images/pathway-catalog-content.svg` to regenerate the diagram after making changes to `images/pathway-catalog-content.dot`. @@ -70,6 +82,8 @@ Consequences ------------ - Catalog edits never create new content versions; definition edits (Items, criteria) always do. -- Credential and progress records can reference the exact content version in effect at the time, keeping them - auditable after the Pathway changes. +- Because evaluation follows the published version rather than the enrollment-time version, edits to a Pathway apply + to learners who are already enrolled, which is what we want, but it means edits need care and re-evaluation. - The unversioned Catalog Pathway can be long-lived even if its content definition is changed significantly over time. +- The dependency direction means a Catalog Pathway cannot, on its own, tell which content implements it. Queries in + that direction start from the content side. diff --git a/docs/openedx_learning/decisions/images/pathway-catalog-content.dot b/docs/openedx_learning/decisions/images/pathway-catalog-content.dot index 892a70951..10bafb89f 100644 --- a/docs/openedx_learning/decisions/images/pathway-catalog-content.dot +++ b/docs/openedx_learning/decisions/images/pathway-catalog-content.dot @@ -1,21 +1,40 @@ digraph pathway_catalog_content { rankdir=LR; fontname="Helvetica"; + compound=true; node [shape=box, style=rounded, fontname="Helvetica", fontsize=11]; edge [fontname="Helvetica", fontsize=10]; - learner [label="Learner", shape=ellipse]; - catalog [label="Catalog Pathway\n(not versioned)\nname, Category,\nmarketing, SEO"]; + subgraph cluster_catalog { + label="openedx_catalog (not versioned)"; + fontsize=10; + fontcolor="#4d4d4d"; + style=dashed; + color="#b3b3b3"; + catalog [label="Catalog Pathway\n\nname, category,\ndescription, SEO"]; + courserun [label="CourseRun"]; + } subgraph cluster_content { - label="Pathway content (versioned)"; - fontsize=11; + label="openedx_content (versioned)"; + fontsize=10; + fontcolor="#4d4d4d"; style=dashed; - v1 [label="v1: Items, criteria"]; - v2 [label="v2: Items, criteria"]; - v1 -> v2 [style=dotted, label="revision"]; + color="#b3b3b3"; + v1 [label="content v1\n\nItems, criteria"]; + v2 [label="content v2\n\nItems, criteria\n(currently published)"]; + v1 -> v2 [style=dotted, color="#808080", arrowsize=0.7, label="revision"]; } - learner -> catalog [label="browses / enrolls"]; - catalog -> v2 [label="current definition"]; + user [label="User", shape=ellipse]; + enrollment [label="Enrollment"]; + + user -> enrollment [label="learner"]; + enrollment -> catalog [label="enrolled in"]; + enrollment -> v2 [label="progress evaluated\nagainst the currently\npublished version", style=dashed, color="#808080", fontcolor="#4d4d4d"]; + + v2 -> catalog [label="implements"]; + v2 -> courserun [label="Items reference"]; + + direction [label="dependency direction:\nopenedx_content knows about\nopenedx_catalog, never the reverse", shape=plaintext, fontsize=10, fontcolor="#4d4d4d"]; } diff --git a/docs/openedx_learning/decisions/images/pathway-catalog-content.svg b/docs/openedx_learning/decisions/images/pathway-catalog-content.svg index 050606d86..df9a619a9 100644 --- a/docs/openedx_learning/decisions/images/pathway-catalog-content.svg +++ b/docs/openedx_learning/decisions/images/pathway-catalog-content.svg @@ -4,63 +4,112 @@ - - + + pathway_catalog_content - + +cluster_catalog + +openedx_catalog (not versioned) + + cluster_content - -Pathway content (versioned) + +openedx_content (versioned) - + -learner - -Learner +catalog + +Catalog Pathway +name, category, +description, SEO - + -catalog - -Catalog Pathway -(not versioned) -name, Category, -marketing, SEO +courserun + +CourseRun - - -learner->catalog - - -browses / enrolls + + +v1 + +content v1 +Items, criteria v2 - -v2: Items, criteria - - - -catalog->v2 - - -current definition - - - -v1 - -v1: Items, criteria + +content v2 +Items, criteria +(currently published) v1->v2 - - -revision + + +revision + + + +v2->catalog + + +implements + + + +v2->courserun + + +Items reference + + + +user + +User + + + +enrollment + +Enrollment + + + +user->enrollment + + +learner + + + +enrollment->catalog + + +enrolled in + + + +enrollment->v2 + + +progress evaluated +against the currently +published version + + + +direction +dependency direction: +openedx_content knows about +openedx_catalog, never the reverse From 4966440538ca61fc1a53db74fef729fcce9128f1 Mon Sep 17 00:00:00 2001 From: Agrendalath Date: Thu, 27 Aug 2026 19:00:20 +0200 Subject: [PATCH 3/3] fixup! docs: add ADR for pathway catalog and content split --- .../decisions/0004-pathway-catalog-content-split.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst index 96eaf13d8..262dbe5ad 100644 --- a/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst +++ b/docs/openedx_learning/decisions/0004-pathway-catalog-content-split.rst @@ -23,7 +23,8 @@ authored, versioned, and published). Pathways have the same two aspects, and the who edits what, not about who can see it. - **Different permissions follow from that.** We expect instances to want to let marketing staff update catalog copy without granting them the ability to change what learners must complete, and vice versa. Keeping the two - apart makes that possible without inventing field-level permissions. + apart makes that possible without inventing field-level permissions. However, with the new RBAC system, this + may be less of a concern. - **Auditability.** Progress and credentials must be judged against the definition that was in effect at the time, which requires versioning the definition - but versioning catalog copy would be pure overhead.