Skip to content

Implement Media Asset Management as a first class entity #499

@ormsbee

Description

@ormsbee

This feature was originally proposed by @holaontiveros and @rodmgwgu, in a workshop session during the Axim/WGU dev summit in Feb '26, though I'm reframing it somewhat here. All of this is subject to Product approval, of course.

Use Cases

Western Governors University uses a Digital Asset Management System for its various media files. This serves to provide a centralized, searchable repository of such assets, as well as providing a way to remove assets if it becomes necessary for copyright reasons. In their current deployment of Open edX platform, WGU stores nothing in course Files and Uploads, and uses links for all assets.

The goals for this would be:

  1. Create a system that allows for centralized Media asset management in Open edX Platform.
  2. Allow for pluggable integration with external digital asset management systems, where libraries contain local references and metadata, but the actual asset is stored and served via that external system.
  3. Use this foundation to re-platform course Files and Uploads on top of openedx-core, and help to unblock the migration of course data.

Non-goal: We are not trying to grow Open edX Platform to be a first-in-class Digital Asset Management System. We basically want our platform to be good enough for the 80% use case that includes centralized management for copyright reasons, as well as being able to serve assets at scale.

The current state of media files in openedx-core

We currently support the storage of media assets with the media applet in openedx_content. However, the media app is a very low-level system, and only really gives us blob storage. The only place where media assets can be leveraged by end-users is through the components applet, which has models that map a particular component-local path name with a corresponding media file, e.g. static/diagram.webpMedia:

class ComponentVersionMedia(models.Model):
"""
Determines the Content for a given ComponentVersion.
An ComponentVersion may be associated with multiple pieces of binary data.
For instance, a Video ComponentVersion might be associated with multiple
transcripts in different languages.
When Content is associated with an ComponentVersion, it has some local
key that is unique within the the context of that ComponentVersion. This
allows the ComponentVersion to do things like store an image file and
reference it by a "path" key.
Content is immutable and sharable across multiple ComponentVersions.
"""
component_version = models.ForeignKey(ComponentVersion, on_delete=models.CASCADE)
media = models.ForeignKey(Media, on_delete=models.RESTRICT)
# "key" is a reserved word for MySQL, so we're temporarily using the column
# name of "_key" to avoid breaking downstream tooling. A possible
# alternative name for this would be "path", since it's most often used as
# an internal file path. However, we might also want to put special
# identifiers that don't map as cleanly to file paths at some point.
key = key_field(db_column="_key")

(Note: the comments say "Content" here, when they should say "Media"--I missed this in the refactoring.)

High Level Proposal

  1. Create a new assets applet in openedx_content.
  2. Create a new publishable model called Asset.
  3. Design it such that Assets can be backed either by local file storage via the media app, or act as local references to external digital asset management systems.
  4. Use Assets as the basis for course Files and Uploads.
  5. Use Assets as an alternative method of storage for Components that want to store media. An Asset would become a publishing dependency of the Components in which it is used, giving us a similar version vs. side-effect semantics as we currently have with container parents and children.

Open Questions

  1. Would we migrate current component/media associations in libraries to use assets, or allow for both modes?
  2. What sort of access control is practical on the LMS side?
  3. How will namespacing work, e.g. importing multiple courses into the same library without causing collisions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    archArchitecturedata modelAnything relating to the relational models or more abstract "model" concepts around Learning Core.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions