0002 Architecture#

Status#

Provisional

Context#

  1. This Django app generates and shows user credentials.

  2. The models should store credential configurations. The credential types will vary between different course types. The available course types are:

    1. Course.

    2. Lesson.

    3. Pathway.

  3. This Django app uses celerybeat to periodically retrieve data from an API (either the platform’s Python API or the HTTP one). Retrieving this data is pluggable - it means that other developers can develop a Python package and install it to have a custom ways to retrieve data from different APIs.

  4. We decided not to use openedx-events because retrieving the eligible users can be a heavy operation. Doing it on every block completion or problem submission is likely to cause performance issues. We may consider this approach in the future, but now we want to avoid adding more complexity.

  5. If a user matches the criteria, the credentials will be generated from a PDF template (stored in the assets model). The PDF will be uploaded to S3, and the link will be sent to the user. The generation process should also be pluggable - it means that other developers can develop a Python package and install it to have custom ways to generate credentials.

Decision#

digraph G {
    node [shape=box, style=filled, fillcolor=gray95]
    edge [fontcolor=black, color=black]

    subgraph cluster_0 {
        label = "Open edX";
        style=filled;
        color=lightgrey;

        // Resources
        LMS;
    }

    subgraph cluster_1 {
        label = "learning-credentials";
        style=filled;
        color=lightgrey;

        // Resources/models
        CredentialType [label="CredentialType"]
        CourseConfiguration [label="CredentialConfiguration"]
        Credential [label="Credential"]
        Asset [label="CredentialAsset"]
        PeriodicTask
        Schedule

        // Processes
        Processing [shape=ellipse]
        Generation [shape=ellipse]

        // DB relations
        edge [fontcolor=black, color=gray50]
        CredentialType -> CourseConfiguration [dir=back, headlabel="0..*", taillabel="1   "]
        CourseConfiguration -> PeriodicTask [dir=both, headlabel="1   ", taillabel="1"]

        // Non-DB relations
        edge [fontcolor=black, color=blue]
        CourseConfiguration -> Generation
        Asset -> Generation
        PeriodicTask -> Schedule

        // Processes
        edge [fontcolor=black, color=red]
        Schedule -> Processing [label="trigger"]
        Processing -> Generation [label="provide eligible users"]
        Generation -> Credential [label="generate credentials"]
    }


    // Processes involving external APIs.
    edge [fontcolor=black, color=red]
    Processing -> LMS [label="pull data", dir=forward]

}

User stories#

TODO: Move this to the docs.

As an Instructor, I want to enable credential generation for a course.#

To do this, I should:

  1. Visit course credential admin page.

  2. Create a new entry with a course ID, credential type and an “Enabled” toggle.

  3. Internally, each of these entries will be a cron task. This way, we can set individual credential generation schedules. It means that an Instructor can schedule generating different credentials for the same course at different times.

Once done, the celery cron will be scheduled to run at the specified time. The celery task will:

  1. Retrieve data from the external API.

  2. Check which users are eligible for a credential.

  3. Generate credentials for the eligible users.

Questions:

  1. Should we use course’s start/end date to gate cert generation?

  2. Maybe we could disable the cron task when the course is closed?