In order to facilitate Master's-level learning on edX, we will need to support several capabilities:
The Neem Team's original approach to these issues was the creation of a Registrar service. This service would simultaneously fulfill primary purposes:
This design, while technically viable, raised architectural concerns. Specifically, Nimisha Asthagiri (Deactivated) and Dave Ormsbee pointed out that Registrar would simultaneously be (1) authoritatively storing program enrollment data, which is likely to become relevant to future edX services and frontends, and (2) aggregating and translating APIs for consumption by external systems. They believed that (1) should be performed by a core edX service such as the LMS or a theoretical "Enrollments Service", whereas (2) should be performed by a periphery service that is not depended upon by any other edX services. Furthermore, they believed that if the Registrar is a periphery integration service, the Master's Student Dashboard should pull data from core edX services instead.
One immediate resolution to the architectural concerns in Design A would be to continue having Registrar as an integration point, but moving the source of truth for program enrollments to the LMS, and having the Master's Student Dashboard use the LMS and Discovery Service as its backends. However, this has the effect of adding functionality and data to the LMS, which is already considered a bloated service.
Nimisha and Dave expressed that they would be open to having a separated "Enrollments Service" to authoritatively store program enrollment data (and, in the future, course enrollment data as well), on the condition that the service was not also designed to be an integration point for general "registrar" operations. That is, SISs would need to query other edX services for non-enrollment data; specifically, they would need to fetch program structure from Course Discovery and grades/attendance from the LMS.
In addition to the added complexity of the URL scheme exposed to SISs in this design, authorization becomes an issue. That is, in the previous two solutions, Registrar would be able to enforce permissions regarding read/write access to program metadata, enrollments, grades, etc. based on the API user and the organization they are associated with. However, in this solution, we would need to handle API authorization across three separate edX services, which would require either (1) devising a scheme to synchronize user permissions across services or (2) manually keeping each API user's permissions up to date on all three services.
A third alternative involves retaining the Enrollments Service, while additionally having a service or gateway between SISs and the edX services that host the relevant data. There are two variations of this design:
One detail that has been omitted from the four designs above for sake of simplicity is the concept of preemptive enrollments (sometimes referred to in discussions as pending enrollments, waiting enrollments, enrollment requests, future enrollments, etc.). Schools will need to be able to send edX a list of learners (identified by either .edu email address or student ID) to be enrolled in programs and/or courses. In the event that some of the learners do not already have edX accounts, we must store the preemptive enrollments. When a new edX account is created, any preemptive enrollments corresponding to it should be turned into true enrollments. For each design, preemptive enrollments would be instrumented in a different way:
For all designs in which a non-LMS service (specifically, Registrar or Enrollments) owns the preemptive enrollments, an issue arises: how do we know when an LMS user has been created? It is necessary to know when an LMS user as been created in order to turn their preemptive enrollments into true enrollments. Three options present themselves:
Finally, in all possible designs, there exists the issue of correctly linking preemptive enrollments to newly created accounts. That is, preemptive enrollments must be tagged with some piece of identifying information–say, a student email or student ID–so that when an LMS account is created, we can determine which (if any) preemptive enrollments belong to them. Currently, the LMS Enterprise application supports preemptive enrollments for enterprise users, referring to them as "pending enrollments". It links newly created LMS users to their pending enrollments using the email address associated with the account (see https://github.com/edx/edx-enterprise/blob/master/enterprise/signals.py#L19). However, it is not clear whether this is a viable option for preemptive enrollments for Master's programs/courses.
After consulting with members Architecture and Master's-Neem, Design B was decided upon. The driving factors in the decision were:
Furthermore, we decided to also store preemptive course and program enrollments in the LMS. This removes the issue of having to communicate LMS user creation to other services. When an LMS user is created, the User model's post_save signal will be captured elsewhere in the LMS, and any preemptive enrollments corresponding to the user will be created. We will create our new models for PreemptiveProgramEnrollment and PreemptiveCourseEnrollment.
Finally, we will likely require that the student identifier provided by school when creating preemptive enrollments be the same as the remote ID provided by the school's SAML IdP. More specifically: in LMS, the uid field of a UserSocialAuth record for a SAML sign-in takes the form "<school_slug>:<remote_id>". The remote_id should equal the student_id used to create preemptive enrollments. That way, we will be able to link together preemptive enrollments and LMS users.