diff --git a/lms/djangoapps/certificates/docs/diagrams/README.rst b/lms/djangoapps/certificates/docs/diagrams/README.rst new file mode 100644 index 000000000000..071f4d34e2cc --- /dev/null +++ b/lms/djangoapps/certificates/docs/diagrams/README.rst @@ -0,0 +1,4 @@ +Certificate management workflows are spread across a few different apps of edx-platform and can be hard to trace and +understand. This folder contains high level visualizations to help maintainers understand how the Certificate awarding +and revoking flows work, and how they interact with other pieces of the Open edX ecosystem (e.g. the Credentials IDA and +the Event Bus). diff --git a/lms/djangoapps/certificates/docs/diagrams/certificate_generation.dsl b/lms/djangoapps/certificates/docs/diagrams/certificate_generation.dsl new file mode 100644 index 000000000000..beef611e4393 --- /dev/null +++ b/lms/djangoapps/certificates/docs/diagrams/certificate_generation.dsl @@ -0,0 +1,66 @@ +/* + * This is a high level diagram visualizing how the system awards course and program certificates. It is written using + * Structurizr DSL (https://structurizr.org/). + */ +workspace { + model { + properties { + "structurizr.groupSeparator" "/" + } + event_bus = softwareSystem "Event Bus" + + group "LMS" { + grades_app = softwareSystem "Grades Django app" + verify_student_app = softwareSystem "Verify Student app" + student_app = softwareSystem "Student app" + group "Certificates app" { + signal_handlers = softwareSystem "Certificates Signal Handlers" + generation_handler = softwareSystem "Certificates Generation Handler" + allowlist = softwareSystem "Certificate AllowList" + } + credentials_app = softwareSystem "Credentials Django app" + programs_app = softwareSystem "Programs Django App" + celery = softwareSystem "Celery" + database = softwareSystem "Database" + } + + group "Credentials IDA" { + credentials_ida_consumer = softwareSystem "Credentials Event Bus Consumer" + credentials_api_app = softwareSystem "Credentials API Django App" + credentials_credentials_app = softwareSystem "Credentials Django App" + } + + grades_app -> signal_handlers "Emits COURSE_GRADE_NOW_PASSED signal" + verify_student_app -> signal_handlers "Emits LEARNER_NOW_VERIFIED signal" + student_app -> signal_handlers "Emits ENROLLMENT_TRACK_UPDATED signal" + allowlist -> signal_handlers "Emits APPEND_CERTIFICATE_ALLOWLIST signal" + signal_handlers -> generation_handler "Invokes generate_allowlist_certificate()" + signal_handlers -> generation_handler "Invokes generate_regular_certificate()" + generation_handler -> celery "Enqueues generate_certificate_task task" + celery -> database "UPSERT certificate record to database" + database -> event_bus "Emits a CERTIFICATE_CREATED event" + database -> programs_app "Emits a COURSE_CERT_CHANGED signal" + credentials_ida_consumer -> event_bus "Listening for Certificate events" + database -> programs_app "If passing, emits a COURSE_CERT_AWARDED signal" + programs_app -> celery "Enqueue award_course_certificate task" + programs_app -> celery "Enqueue award_program_certificate task" + celery -> credentials_app "Process award_course_certificate task" + celery -> credentials_app "Process award_program_certificate task" + credentials_app -> credentials_api_app "POST request to award course credential" + credentials_app -> credentials_api_app "POST request to award program credential" + credentials_ida_consumer -> credentials_credentials_app "Award Certificate record" + } + + views { + systemLandscape "SystemLandscape" { + include * + autolayout lr + } + + styles { + element "Database" { + shape Cylinder + } + } + } +} diff --git a/lms/djangoapps/certificates/docs/diagrams/certificate_revocation.dsl b/lms/djangoapps/certificates/docs/diagrams/certificate_revocation.dsl new file mode 100644 index 000000000000..5b768c56cbf0 --- /dev/null +++ b/lms/djangoapps/certificates/docs/diagrams/certificate_revocation.dsl @@ -0,0 +1,58 @@ +/* + * This is a high level diagram visualizing how the system revokes course and program certificates. It is written using + * Structurizr DSL (https://structurizr.org/). + */ +workspace { + model { + properties { + "structurizr.groupSeparator" "/" + } + event_bus = softwareSystem "Event Bus" + + group "LMS" { + grades_app = softwareSystem "Grades Django app" + group "Certificates app" { + signal_handlers = softwareSystem "Certificates Signal Handlers" + } + credentials_app = softwareSystem "Credentials Django app" + programs_app = softwareSystem "Programs Django App" + celery = softwareSystem "Celery" + database = softwareSystem "Database" + } + + group "Credentials IDA" { + credentials_ida_consumer = softwareSystem "Credentials Event Bus Consumer" + credentials_api_app = softwareSystem "Credentials API Django App" + credentials_credentials_app = softwareSystem "Credentials Django App" + } + + grades_app -> signal_handlers "Emits COURSE_GRADE_NOW_FAILED signal" + signal_handlers -> database "Update certificate's status to NOT_PASSING" + database -> event_bus "Emits a CERTIFICATE_REVOKED event" + credentials_ida_consumer -> event_bus "Listening for Certificate events" + credentials_ida_consumer -> credentials_credentials_app "Revoke Certificate record" + database -> programs_app "On save(), emits a COURSE_CERT_CHANGED signal" + database -> programs_app "On save(), emits a COURSE_CERT_REVOKED signal" + // The following line is correct, an `award_course_certificate` task is queued whether we award or revoke a + // course certificate. It handles both operations. + programs_app -> celery "Enqueue award_course_certificate task" + programs_app -> celery "Enqueue revoke_program_certificate task" + celery -> credentials_app "Process award_course_certificate task" + celery -> credentials_app "Process revoke_program_certificate task" + credentials_app -> credentials_api_app "POST request to revoke course credential" + credentials_app -> credentials_api_app "POST request to revoke program credential" + } + + views { + systemLandscape "SystemLandscape" { + include * + autolayout lr + } + + styles { + element "Database" { + shape Cylinder + } + } + } +} diff --git a/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_generation.png b/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_generation.png new file mode 100644 index 000000000000..b5403c885406 Binary files /dev/null and b/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_generation.png differ diff --git a/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_revocation.png b/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_revocation.png new file mode 100644 index 000000000000..83e46d33c05d Binary files /dev/null and b/lms/djangoapps/certificates/docs/diagrams/rendered/certificate_revocation.png differ