SB-26582 Optional Material in a course
Requirement
Courses need to support optional material that do not contribute to overall progress of the course , or to the overall score computation for the course.
Jira Id : https://project-sunbird.atlassian.net/browse/SB-26582
ED Story: https://project-sunbird.atlassian.net/browse/ED-258
Discussion Thread : https://github.com/orgs/Sunbird-Ed/discussions/34#discussioncomment-4465619
Proposed UI : https://projects.invisionapp.com/share/SX133YUE5F27#/screens/471152108
The design approach should focus on below points:
The Optional material shouldn’t contribute to the progress % of the trackable collection and hence doesn’t contribute in the completion certificate criteria.
The optional material shouldn’t contribute to the final score calculation of the collection and hence doesn’t contribute in the merit certificate criteria.
The optional material progress should not be reflected in the progress exhaust.
Problem Statement
Adding a new property ‘optional’ for leaf nodes in Course relational metadata by Sunbird Knowlg
Relation Cache updater should update optional nodes in redis
Filter out optionalNodes during course progress update
Exclude optionalNodes in score computation
Exclude optionalNodes from course progress reports
Exclude optionalNodes while showing progress in course page.
Design
Course Relational Metadata changes by Sunbird Knowlg
Design from Sunbird Knowlg: https://project-sunbird.atlassian.net/wiki/spaces/~5a5de7e408790741d1ff75a1/pages/3253338150
To support optional material in courses, specify optional:boolean
as a new property in course relational metadata.
Hierarchy child levels can be max 7, default is 4 now
Last level node will be leaf node
In between the hierarchy levels, all children are units /folders
Relational meta data only in the leaf node level
Leaf node mimetype will be specific to the content, till leaf node all other nodes will have mimetype as collection
Other than course unit and textbook unit as primary category, everything else can be leaf node now.
2. RelationCacheUpdater - update the optional nodes list
After fetching course hierarchy data from dev_hierarchy_store
.content_hierarchy
table in cassandra, job should check the relational metadata of the leaf node for optional property.
If the optional property i set to true, fetch the identifier and add it to optionalNodes list.
This should be saved to redis.database.index : 10 along with leafnodes and ancestors.
Scenario1: There wont be a content in a course, which is mandatory in unit1 and optional in unit2 as per current design. Refer : https://project-sunbird.atlassian.net/browse/ED-258
When same content is added to different units of a course, leafNodes and optional nodes list will have the content id one time only, and leaf node list and count in hierarchy also will not consider duplicate content ids.
With respect to above scenario, when a content is added to multiple units, either in all unit it will be mandatory or in all units it will be optional.
Scenario2: Same content in a course is mandatory in unit1 and optional in unit2 - This scenario is invalid as per user story.
In the scenario, where same content in a course is mandatory in unit1 and optional in unit2; then on overall course level we will have to consider it as mandatory for computing total progress and completion count. In this case, relation cache implementation has to change so that, course level optional node list in cache will not have the optional node if atleast in one unit it is mandatory. But unit level optional node list in cache will have the optional node.
So before storing ourse level optional node list in cache, we need to remove the particular optional node which is mandatory in atleast one unit of the course. For implementing this, fetch all mandatory node list and remove those from the course level optional node list before storing it in cache.
3. Activity_Aggregator - Filter out optional Nodes from LeafNodes and calculate the progress
In ActivityAggreagtor job, get the optional nodes along with leafnodes for course id from relational data cache(redis.database.index : 10).
On Course Level Aggregation, remove the optionalNodes contentids from leafNodes before calculating the overall progress and completion count
In user_activity_agg
table ‘aggregates’ column, ‘completedCount’ attribute which is calculated by ActivityAggreagtor job should exclude optional node count. The same ‘completedCount’ is stored as progress in user_enrolments table by ActivityAggreagtor job. But other attributes in ‘aggregates’ column like attempt id, score, max score can be have the same existing logic. These are updated by AssessmentAggregator job. ‘aggregates’ column stores best score of the user in an assessment.
'agg_details' column in user_activity_agg
table is updated by AssessmentAggregator job.
Change required in user_enrolments table progress column update. ‘completedCount’ attribute which is calculated by ActivityAggreagtor job should exclude optional node count.
No change required in assessment_aggregator table update.
3. Assessment Aggregator - Ignore optional nodes from LeafNodes for score computation - Assessment cannot be optional as per the ED-258 story
On consuming i/p event in UserScoreAggregateFunction, get the list of optionalNodes contentIds from relation cache.
On quering assessment_aggregator tbl to get the total_max_score, total_score and score, filter out the optionalNodes contentIds.
In assessment_aggregator table, data is stored content-attempt wise.
4. Reports
Progress Exhaust:
After loading data from content_hierarchy table, 'leafNodesCount' calculation
has to be added to exclude optional nodes count. And to compute the completionPercentage
of the course for displaying total progress, optional nodes' ids has to be excludes from content ids in 'contentstatus' column in user_enrolment table.
For this contentstatus column is used because eventually user_enrolment.progess and user_activity_agg
.aggregates{completedCount} was supposed to be deprecated. These both columns save same value, total no of leafnodes user completed consumption.
As per this Jira ticket https://project-sunbird.atlassian.net/browse/ED-258. score calculation is not affected, because an assessment cannot be optional.
Edge User case Queries
Case 1: if a user have consumed the course. After that course is update for a existing content as optional content. How do we need to update the user consumption and user assessment aggregate?
Case 2: As batch service does not store the optional field, whoever does the progress calculation using API will have to call content-service also to check if the leaf node is optional or not
Case 3: In a collection, if unit 1 and unit 2 has same content with same content id, and in unit 1 the content is mandatory and unit 2 it is optional, how should the calculation should be handled? How to restrict same content being added as optional and mandatory in different units of same course?
Assumptions:
An assessment cannot be optional.
Same content cannot be optional in one unit and mandatory in another unit of the same course.