Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: ADRs for modeling containers capability #251

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2906792
docs: add ADR for generalized containers capability
mariajgrimaldi Oct 25, 2024
b1b1a88
docs: add ADR for units
mariajgrimaldi Oct 28, 2024
413b66c
fix: reference content flexibility ADR
mariajgrimaldi Oct 28, 2024
0deab25
docs: add containers DB schema
mariajgrimaldi Oct 28, 2024
22eb1ae
docs: add containers and units db schema
mariajgrimaldi Oct 28, 2024
db61fda
docs: correct list ordering
mariajgrimaldi Oct 29, 2024
b5f05d8
refactor: improve writing and drop too implementation specific decisions
mariajgrimaldi Oct 30, 2024
9d2c62d
docs: take container decisions and make them unit-specific
mariajgrimaldi Oct 30, 2024
8648f16
docs: add more decisions on version control and publishing
mariajgrimaldi Oct 31, 2024
80cf370
refactor: drop decision about creating new EntityLists with each version
mariajgrimaldi Nov 4, 2024
b98c02c
docs: Update 0017-generalized-containers.rst
mariajgrimaldi Nov 5, 2024
ccada60
docs: Update docs/decisions/0017-generalized-containers.rst
mariajgrimaldi Nov 5, 2024
778ce2b
docs: Update docs/decisions/0017-generalized-containers.rst
mariajgrimaldi Nov 5, 2024
e738778
docs: reference other types of content based on containers
mariajgrimaldi Nov 5, 2024
3a28fa5
docs: Update docs/decisions/0017-generalized-containers.rst
mariajgrimaldi Nov 5, 2024
bbce789
docs: Update docs/decisions/0017-generalized-containers.rst
mariajgrimaldi Nov 5, 2024
af7dce4
refactor: add section for container states and intro to each section
mariajgrimaldi Nov 12, 2024
506d9cd
refactor: address PR reviews
mariajgrimaldi Nov 12, 2024
466b450
refactor: address PR reviews
mariajgrimaldi Nov 12, 2024
46999f8
refactor: address PR reviews
mariajgrimaldi Nov 14, 2024
0c426d2
docs: add empty ADR for dynamically selected content
mariajgrimaldi Nov 14, 2024
46dfa9e
refactor: reduce ambiguity and address reviews
mariajgrimaldi Nov 14, 2024
d37a414
refactor: write containers capability as a concrete use-case with units
mariajgrimaldi Nov 14, 2024
64e4db9
refactor: address PR reviews
mariajgrimaldi Nov 14, 2024
46e5a09
docs: Update 0017-generalized-containers.rst
mariajgrimaldi Nov 14, 2024
822d9a0
docs: add decisions for pruning according to available info
mariajgrimaldi Nov 19, 2024
8646225
docs: Update 0017-generalized-containers.rst
mariajgrimaldi Nov 19, 2024
1f1c962
docs: Update 0018-units-as-containers.rst
mariajgrimaldi Nov 19, 2024
f260756
docs: add first version for selectors high-level decisions
mariajgrimaldi Nov 19, 2024
86141e5
refactor: add examples to better illustrate decisions
mariajgrimaldi Nov 20, 2024
aff8b9b
refactor!: drop db diagrams for containers to avoid too much specificity
mariajgrimaldi Nov 20, 2024
76e89d5
refactor: add examples to better illustrate selectors
mariajgrimaldi Nov 20, 2024
6ecde96
docs: apply suggestions from code review
mariajgrimaldi Nov 20, 2024
f7cc446
docs: improve readability
mariajgrimaldi Dec 5, 2024
dc5a0a2
docs: address PR reviews
mariajgrimaldi Dec 5, 2024
d0f1fc8
fix: use other approach for linking references
mariajgrimaldi Dec 5, 2024
83f8d04
fix: reference documents from current dir
mariajgrimaldi Dec 5, 2024
8fa418e
docs: update unit ADR with latest changes
mariajgrimaldi Dec 5, 2024
6fd6864
docs: apply suggestions from code review
mariajgrimaldi Dec 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/decisions/0017-generalized-containers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
17. Modeling Containers as a Generalized Capability for Holding Content
========================================================================

Context
-------

This ADR proposes a model for containers that can hold different types of content and can be used to model other content types with similar behavior, such as units, subsections, sections, or courses. The model defines containers' core structure and purpose, the types of containers, content constraints, container children, version control, publishing, and pruning.

Decisions
---------

1. Core Structure and Purpose of Containers
===========================================

This section defines the purpose and structure of containers, explaining how they are designed to hold various types of content through a parent-child setup.

- A container is designed as a generalized capability to hold different types of content.
- A container is a publishable content type that holds other content types through a parent-child relationship. For example, sections, subsections and units.
- The generalized container capability will have its own Django application as part of the authoring application allowing other types of containers and content types will build on top of. For instance:

- Generalized containers (containers app is lowest level of these applications)
- Selectors for dynamically selecting 0-N PublishableEntities, i.e., how we're going to do things like SplitTest and Randomized (a selectors Django application that builds on containers).
- Units (units Django application, builds on containers and selectors).

2. Container Types and Content Constraints
==========================================

This section defines container types, content constraints, hierarchy, and extensibility. It introduces the main types of containers and outlines how content limitations and configurations are handled at the application level to support flexible content structures.

- A container marks any PublishableEntity, such as sections, subsections, units, or any other custom content type, as a type that can hold other content.
- Containers can be nested within other containers, allowing for complex content structures. For example, subsections can contain units.
- Containers might be of different types, with each type potentially having different restrictions on the type of content it can hold but that will not be enforced by containers.
- Content restrictions for containers are implemented at the app layer, allowing specific container types, like units, to limit their children to particular content types, e.g., units are restricted to contain only components.
- The course hierarchy Course > Section > Subsection > Unit will be implemented as relationships between containers, with each level acting as a container that holds other content. The hierarchy will be enforced by the content restrictions of each particular container but allowed to be overridden to support `Approach to Content Flexibility <0002-content-flexibility.rst>`_.
- Containers will follow extensibility principles in `Content Extensibility Through Model Relations <0003-content-extensibility.rst>`_ for creating new container types or subtypes.

3. Container Children and Relationships
=======================================

This section defines container children, their order, and relationships, covering flexible connections and support for draft and published states of their children.

- Each container version holds a list of children that the author has defined for that version.
- The author-defined list is used to show the content of a container version as the author specified it
mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved
- The author-defined list won't change for a specific container version even if its members change. E.g., a unit version UV1 with three components (CV1, CV2, CV3) will always have those three components in the author-defined list, even if one of the components is soft-deleted or a new version for the component is created.
- The children of a container can be any type of publishable content. E.g., sections, subsections, units, components, and any other publishable thing. For more details on publishable content, see `PublishableEntity`_.
- Children within a container are maintained in a specific order as an ordered list. E.g., components within a unit, or units within a subsection, are presented in a specific order.
- Containers represent their content hierarchy through a structure, like Course > Section > Subsection > Unit > Component, which defines parent-child relationships at each level.
- Containers can reference a specific version of their children or be set to point to their latest versions. For instance, component V1 might be used in a unit instead of its latest version. The latest version of a child can be referenced by setting its version to ``None`` which consists of the chosen standard for this representation.
- A single child (publishable entity) can be shared by multiple containers, allowing for reuse of content across different containers. For instance, a component can be shared by multiple units.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to be more specific about the unit, is the unit in a content library o within the context of a course?


4. Next Container Versions
==========================

This section defines the rules for version control in containers, explaining when new versions are created based on changes to container structure or metadata.

- A new version is created if and only if the container itself changes (e.g., title, ordering of children, adding or removing children) and not when its children change (e.g., a component in a Unit is updated with new text). For instance, a new version of a unit is created when a component is removed, not when a new version of a component is created.
- No external change to a child will trigger the creation of a new version for the container. For example, updating or soft-deleting a component will not trigger the creation of a new version for the unit.
- Containers with invalid references (e.g., references to soft-deleted children) will be filtered out as needed to ensure consistency.

5. Publishing
Copy link
Member Author

@mariajgrimaldi mariajgrimaldi Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question:
What I'm still missing here is the behavior of publishing containers when they're being reused somewhere and modified in some way. I understand we discussed this in our last meeting, but it's still not clear to me what our approach should be from the modeling point of view.

=============

This section explains the publishing process for containers, detailing how containers and their children become accessible, either together or independently, based on their publication state. The publishing process happens on container versions, but throughout this section we'd call them containers for simplicity.

- Containers can be published, allowing their content to be accessible from where the container is being used.
- When a draft container is published, all its draft children are also published. For instance, after publishing a draft version of subsection which contains a draft unit with an updated title, the latest published version of the unit will be the one with the updated title, reflecting the changes made previously.
- Children of a container can be published independently of the container itself. E.g., a shared component can be published independently of the unit if it also exists outside the unit.
- Containers are not affected by the publishing process of its children. This means that publishing a component won't trigger new publishing processes for a container.

6. Pruning
==========

This section defines the rules for pruning container versions, explaining when a container version can be pruned and the effects of pruning on the container and its children.

- A container version can be pruned if it's not being used by any other container, it's not a published version and it's not the latest version of the container.
- In a top-down approach, start the deletion process with the parent container and work your way down to its children. E.g., when pruning Section V2 > Subsection V1 > Unit V3, the deletion process starts in the greater container working its way down to the smaller.
- Pruning a container version will not affect the container's history or the children of other container versions, so containers will not be deleted if they are shared by other containers.

.. _PublishableEntity: https://github.com/openedx/openedx-learning/blob/main/openedx_learning/apps/authoring/publishing/models.py#L100-L184
78 changes: 78 additions & 0 deletions docs/decisions/0018-units-as-containers.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
18. Modeling Units as a Concrete Implementation of the Container Capability
mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Member Author

@mariajgrimaldi mariajgrimaldi Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this requires its own ADR, but it helps illustrate the decisions using a more familiar concept like units.

===========================================================================

Context
-------

The container capability is a generalized capability to hold different types of content. This decision focuses on modeling units as a concrete implementation of the container capability.

Decisions
---------

All decisions from `0017-generalized-containers.rst`_ are still valid but are written here alongside unit-specific decisions for better illustration.

.. _`0017-generalized-containers.rst`: 0017-generalized-containers.rst

1. Units as Containers
=======================

- A unit is a concrete type of container that holds components.
- A unit is a container, making it also a publishable entity.
- A Django application, which builds on the container application definitions, will an API and enough definitions for other unit subtypes to use.

2. Unit Types and Content Constraints
======================================

- Units can only hold components as their members but will not enforce this restriction at the model level.
- Units are the first level of nested content types Unit > Components.
- Content restrictions for units are implemented at the app layer, allowing units to limit their members to only components.
- Unit subtypes can be created by following the extensibility principles in `0003-content-extensibility.rst`_.

3. Unit Members and Relationships
==================================

- The members of a unit can only be components.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these decisions be part of this ADR as well?

  • Unit members can exist as standalone items outside the unit.
  • Members should indicate which unit they belong to.
  • Members can be duplicated from units but keeping original references.

- Components are referenced as an ordered list in a unit.
- Units can hold both static and dynamic content, such as user-specific variations.
- Units can reference pinned and unpinned versions of its components.
- The latest draft or publish version of a component can be set by using `None` in thr parent-child relationship between units-components.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The latest draft or publish version of a component can be set by using `None` in thr parent-child relationship between units-components.
- The latest draft or publish version of a component can be set by using `None` in the parent-child relationship between units-components.

- A single component can be reference by multiple units.

4. Unit Version History
============================

- Each unit version holds different list of components to support rollback operations and history tracking.
- The author-defined list is the list of components defined by the author for a specific unit version.
- The author-defined list of components won't change for a specific version.
- The initial list is a copy of the author-defined list that has all components pinned to the versions at the time of the unit version creation.
- The initial list is immutable for a unit version.
- The frozen list refers to the list of components at the time when the next version of the unit is created.
- When creating the author-defined list of a new version with pinned references, then the author-defined list is the same as the initial and frozen list. When creating a new version with unpinned references, then the frozen list starts as `None` and should be updated with the author-defined components pinned when a new version is created.
- The author-defined list is used to show the content of a unit version as the author specified it, the frozen list can be used for discard operations on a draft version and the initial-list is part of the history of evolution of the unit.
- These lists allow history tracking of a unit version and revert operations.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to self: This needs to be updated according the latest changes in the container ADR.


5. Next Unit Versions
======================

- A new version is created if and only if the unit itself changes (e.g., title, ordering of components, adding or removing components) and not when its components change (e.g., a component in a Unit is updated with new text).
- When a shared component is soft-deleted in a different unit, a new unit version should be created for all containers referencing it without the component.

6. Publishing
==============

- Units can be published, allowing their content to be accessible from where the unit is being used.
- When a draft unit is published, all its draft components are also published.
- Components within a unit can be published independently of the unit itself.
- When a new draft, created for a unit when a shared component is soft-deleted, is published then all units referencing the component will be force-published.
- Units are not affected by the publishing process of its components.

7. Pruning
===========

- A unit version can be pruned if:
#. It's not being used by any subsections.
#. It's not a published version.
#. It's not the latest version of the unit.
- In a top-down approach, start with the unit and work your way down to its component versions.
- Component versions will not be deleted if they are shared by other units.
- Pruning a unit version will not affect the unit's history or the components of other unit versions.
40 changes: 40 additions & 0 deletions docs/decisions/0019-selectors.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Selectors for Dynamically Selecting Content
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm currently working on this section. Thanks!

Copy link
Member Author

@mariajgrimaldi mariajgrimaldi Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the first version of selectors based on the information that's available. I haven't considered these comments yet, but I'll make sure to include reference them since that might impact their design. Also, for the container history.

mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved
===========================================

Context
-------

This ADR proposes a way to represent dynamic members of a container, where dynamic means selecting members from a specified pool. Some examples of dynamic selection are:

1. A/B Testing: testing two different groups of components to see which perform better.
2. Per Student: randomly selecting three problems from a set of 20 per student.

And any other custom use case to dynamically select members for a container. This proposal introduces the concepts of selectors and variants to implement this type of dynamic selection.

1. Core Structure
=================

This section explains the concepts and behaviors used to build dynamic selection, selectors and variants.

- Selectors determine what the container should display based on the selector type. For example, based on the nature an A/B split test or a randomization selector members of the container would vary.
- Selectors are used to dynamically select 0-N publishable entities from a specified pool. E.g., take 5 components from this pool of 20.
- The logic for pushing members into variants depends on the selector selection method. For example, A/B split testing two different sets of components or select three problems from a set of twenty.
- Variants hold the members selected for a container based on what the selection method is. E.g., if the selector is "select 5 components out this pool of 20 components" then the variant would be the 5 components selected for the user.
- Variants are build on the parent-child relationship used for containers and their members, storing the dynamically selected content as an ordered list as containers do.

2. Selector Types and Selecting Content
=======================================

This section describes how different types of selectors work and how they handle the selection of dynamic content.

- A selector can be of any type, which means it can implement any method to select members from a pool. Therefore, selectors will follow extensibility principles in `0003-content-extensibility.rst`_ for creating new selector types.
mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved
- Selection versions encode the rules and holds useful details for the selection process like: where to get members from, number of items to select, and other criteria. For instance, for the "select 5 components out of this pool of 20 components" its selector version would encode where to get the 20 components, how many to get for each user and any other detail needed to create the specific variants.
- Depending on the size of the pool of members, variants can be generated at publishing time or on-demand. This behavior should be determined by the selector version based on high vs low permutation scenarios.
- A compositor is responsible for populating the variants but will not be implemented as part of the selector application which belongs to the authoring app.

3. Versioning
=============

A new version of a selector is created whenever the pool of concent changes by adding, removing or reordering existing members.

.. _0003-content-extensibility.rst: docs/decisions/0003-content-extensibility.rst
mariajgrimaldi marked this conversation as resolved.
Show resolved Hide resolved
Loading