Unified User Group Model Technical Approach
1. Why This Document?
This document is part of the research phase for the unified user grouping model. It's meant to:
Present early design alternatives
Explore trade-offs around extensibility, maintainability, and alignment with existing systems
Help us move toward important decisions like:
User Grouping Model ADR: Defines the structure of user groups
Dynamic Group Freshness ADR: Describes how groups stay up to date
Group Umbrella ADR: Explains how the unified model replaces or complements existing systems (like cohorts, teams, and course groups)
Proof of Concept (POC): A lightweight implementation to test the chosen approach
This is an exploratory, spike-phase output. The goal is to support shared understanding, collect feedback early, and help guide the path toward a unified and extensible grouping system.
📢 This document will guide the team in choosing an approach and help us move towards finalizing Architectural Decision Records (ADRs) and starting POC development.
2. The Problem We're Solving
Today, Open edX uses different models for user grouping (cohorts, teams, course groups), each with its own limitations:
They don't work together well
They are hard to extend or customize
They require duplicate logic and effort
We want to define a single, flexible model for user groups that works for content control, collaboration, messaging, analytics, and more.
https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4901601287#What-We-Propose-to-Build
https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4901601287/WIP+User+Group+Strategy#Use-Cases
3. What this Needs to Support
For a more detailed understanding, please read:
https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4905762858
These requirements may evolve over time as the project progresses.
4. Model Components & Key Concepts
This section provides an overview of the main components in the proposed user grouping model. It outlines the core entities, their purpose, and how they relate to each other at a high level. The goal is to build a shared understanding of the model before going deeper into design options.
The table below lists the primary model entities and their roles:
Entity | Description | Notes |
User Group | Represents a group of users. When an admin creates a group, they must specify:
|
|
Users | Users who are associated with one or more groups. When an course team member creates a group, users can be:
|
|
Criteria | Represents a criterion that includes or excludes users from a user group based on shared characteristics or behaviors. This criterion determines which users meet a condition used to populate a group. |
|
Membership | Describes how user membership is managed within a group. It defines criteria and constraints for whether a user can be in one or more groups depending on how the criteria behaves. |
|
Scope | Defines where the group applies (e.g., a course, org, or site-wide). Includes |
|
For a clear understanding of a shared language and more detailed definitions and examples, please visit the Key Concepts document.
5. What Should the Extensions Mechanism Look Like?
This section outlines the expected behavior and requirements for making the model extensible. It focuses on what developers should be able to do, regardless of the internal structure.
Extensible Parts of the Model
The system must support extensions in the following areas:
Criteria: Developers should be able to define new ways of selecting users (e.g., “Visited unit X”) along with the logic and fields needed to evaluate them. The how will depend on the chose approach for the model structure: https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4917657604/Unified+User+Group+Model+Technical+Approach#8.-Design-Approaches-(Overview)
Data Sources: Developers should be able to connect new data sources by providing backend clients and registering them through a standard entry point. We propose two possible approaches for using data:
Criterion-owned queries: Each criterion builds and manages its own queries. The backend only provides helpers like
get_aspects_clientfor access and processing.Backend-managed loading: The backend handles data retrieval via registered clients. Criteria call backend methods and remain agnostic to how data is fetched.
Example Extension Flow
To illustrate what this should support, consider the following use case:
A developer wants to implement a new criterion: “Visited unit X”
The developer defines any required configuration fields for the criterion (e.g., unit ID)
The system provides reusable tools (e.g., query helpers, backend clients, etc.) to make it easier to get the needed data
The developer writes the logic that returns a list of user IDs matching this condition
They register the criterion through a straightforward mechanism (e.g., decorator, class inheritance, plugin config)
The system automatically discovers and integrates the new criterion
The new criterion is integrated into the workflow seamlessly
These are the extension requirements that the model must support. In the next sections, we'll look at how each design alternative meets (or struggles to meet) these expectations.
6. What Should Evaluating Criteria Look Like?
This section outlines the system's expected behavior and responsibilities when evaluating user group membership. It focuses on what should happen during evaluation, regardless of the underlying data model or implementation approach.
High-Level Evaluation Flow
Trigger Evaluation
The system initiates an evaluation of a user group, either on a schedule, through a manual request, or in response to a data change.Retrieve Group Definition
It fetches the group configuration, including its metadata, scope, and all associated criteria used to define group membership.Resolve Criteria Types
For each criterion type, the system must load the logic handler or evaluator (method) responsible for interpreting it, based on its type or identifier.Evaluate Criteria Individually
Each criterion is processed by its evaluator, which returns a set of users who meet the conditions for the criterion (e.g., “users who haven't logged in for 10 days”).Combine Results Across Criteria
The system applies a logical strategy (such as AND/OR) to combine the individual results into a final list of matching users.Update Group Membership
The final user list is saved or propagated to reflect the current membership of the group, either immediately or on the next scheduled update.
7. Runtime Components Overview
These runtime components support the dynamic evaluation of user groups. They are designed to work independently of the specific approach used (model-based, or mixed).
Criterion Registry
Tracks all available criterion types (per scope) that can be used when defining user groups.
Populated at application startup using decorators, entry points, or other discovery patterns
Provides access to metadata, configuration requirements, and evaluation logic per type
Enables the UI and services to list available criteria dynamically
Evaluation Engine (async)
A central service responsible for evaluating group membership by composing all the criteria associated with the group or calling the necessary evaluators to get the list of users.
Criterion Type with Evaluator (method)
Each criterion type includes its own evaluation logic, exposed through a callable (function or class method).
Defines how a criterion is evaluated (e.g., how to query progress, last login, enrollment track)
Uses configuration defined in the group's criteria (e.g., value thresholds, selected options)
The system doesn't need to hardcode logic per type, so the evaluation is encapsulated in the type itself
8. Architecture Diagram (Draft)
How is membership determined?
Workflow:
9. Design Approaches (Overview)
This section outlines the main design approaches we explored for building the unified user grouping model. While the overall structure of user groups remains similar, the key differences between these approaches lie in how criteria are defined, extended, and evaluated.
Each of the following approaches is linked to a separate section that includes its diagram, how it handles extensibility and evaluation, and its pros and cons. This format helps keep discussions focused and easier:
https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4923228186
https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4923785223
Here's a short summary of each:
Aspect | Model-Based | Redistry-based |
|---|---|---|
Definition | One model per criterion type. | A shared model combined with runtime registration and logic. |
Criteria Evaluation | Uses a method defined in the model instance associated with the group. | Loads criterion type class from the registry using a property (e.g., "last_login"). |
Extension | Add a new model subclass and link it via a 1:1 relation to | Register a new class with the registry; no need to modify the database schema. |
Maintainability | Requires managing one model per type and creating migrations for field changes. | Requires managing the registry and defining class validation logic. |
Criteria Configuration | Stored in model fields; validation and typing handled by Django. | Stored in a JSON field; needs external validation tied to the criterion type class. |
UI Support | Can dynamically load form fields and use Django validation. | Needs schema-based validation and UI logic to render fields based on type. |
11. Proposed Approach (So Far)
👀 Up to the discussions we've had so far, the chosen approach is Registry-Based Criteria Subtypes, specifically Option 1: GroupCriterion as an Instance of a Criterion Type. The ADR will be written based on the specificities of that approach.
12. How to Keep a Group Up-to-Date?
For a proposed approach to keeping dynamic user groups up-to-date, see the User Group Consistency and Refresh Framework document. It outlines mechanisms for event-based, scheduled, and manual updates, and proposes rules for handling inconsistencies, mutual exclusivity between criteria, and update priority when multiple methods are in use.
13. Migration: What Happens to Cohorts / Teams / Course Groups?
Review https://openedx.atlassian.net/wiki/spaces/OEPM/pages/4955668482 for more details.