openedx / openedx/openedx-platform
ADR: API Endpoint for User Exam Due Dates in the Mobile App
@kdmccormick is already working on this.
Since Oct 17, 2025.
- Dominant language
- Python
- Stars
- 8.2k
- Forks
- 4.4k
- Avg merge
- 6d 18h
- Merged PRs (30d)
- 42
Description
Context
To improve the Open edX mobile experience, we need to provide learners with a fast, accurate list of upcoming exam and assignment due dates across all of their enrolled courses. This is critical for enabling mobile-first learning workflows, proactive planning, and push notifications.
The current approach, which relies on get_course_date_blocks() and modulestore traversal, is inefficient, especially for multi-course scenarios. The Open edX community has committed to limiting modulestore usage in runtime systems (ADR 0011) and modularizing content and date management.
Solution Summary
We are going to reuse and extend the edx-when application as the unified backend for both course-level and user-level due dates:
- Use
ContentDateto store published due dates from course metadata - Use
UserDateto store user-specific overrides, including:- Personalized schedules (self-paced)
- Instructor-granted extensions
- Create a new API endpoint to return a merged and filtered list of upcoming due dates for the authenticated user
Rejected Alternatives
The following approaches were considered during the design phase but ultimately rejected due to technical or architectural limitations:
1. Continue Using Only XBlock Metadata for Dates
- Description: Store all
start,due, andgraceperiodfields in the modulestore within XBlock definitions. - Reason for Rejection:
- No support for user-level overrides.
- Requires course republishing for any change.
- Cannot support dynamic scheduling, self-paced courses, or extensions.
2. Use Only the schedules App to Drive Dates
- Description: Centralize all date logic through
schedules.Scheduleandschedules.CourseDateOverride. - Reason for Rejection:
- Not designed for block-level (e.g., exam-specific) due dates.
- Cannot serve instructor-paced or hybrid course modes.
- Adds significant refactor requirements to upstream LMS and Mobile APIs.
3. Store Dates in a Separate Custom Table or External Service
- Description: Introduce a new app or microservice for handling exam due dates independently of
edx-when. - Reason for Rejection:
- Duplicates functionality already available in
edx-when. - Adds operational and architectural overhead.
- Increases latency and coupling across services.
- Duplicates functionality already available in
4. Compute Dates On-the-Fly at Runtime
- Description: Dynamically calculate due/start dates based on enrollment and pacing without persisting them.
- Reason for Rejection:
- Degrades performance at scale.
- No audit trail or persistence for extension history.
- Makes date behavior inconsistent and hard to debug.
The final decision to use and extend the edx-when data model preserves flexibility, supports both default and override scenarios, and ensures consistent integration across all platform interfaces (LMS, MFE, Mobile).
Impact on Existing Functionality
Based on our review of the current Open edX codebase, the ContentDate and UserDate models from the edx-when module are not widely integrated into core platform components at this time. Their usage appears to be limited, with no direct dependencies from LMS rendering paths or block structure transformers in the default configuration of the platform.
As a result, the changes proposed in this ADR are not expected to impact existing functionality. The models in question do not currently serve as a critical path for date resolution in standard learner-facing APIs or courseware behavior.
Architecture Overview
✅ What We Reuse
| Component | Role |
|---|---|
edx-when.ContentDate |
Stores canonical due dates published for each course content element |
edx-when.UserDate |
Stores per-user overrides (e.g., extensions, personalized pacing) |
Schedules |
Provides start_date for self-paced learners (used in overrides) |
🆕 What We Add
| Component | Purpose |
|---|---|
| New API | Returns all due dates visible to the user across their courses |
| Runtime logic | Merges ContentDate and UserDate, applies filtering/visibility |
Data Flow
- Studio authors define dates → written to
ContentDatevia publishing - Overrides from instructors or learners → stored in
UserDate - Mobile client calls new API
/api/user-due-dates/ - Backend logic:
- Loads enrolled courses
- Retrieves corresponding
ContentDateandUserDaterecords - Applies overrides and visibility checks
- Returns sorted, paginated results
API Responsibilities
The new API will:
- Authenticate the user
- Retrieve the list of enrolled courses
- Fetch all related
ContentDateandUserDateentries - Apply overrides and enforce content visibility
- Return fields such as:
course_idtitledue_datefirst_component_block_idoverride_source(if applicable)
Scope Limitations
❌ CCX courses (Custom Courses for EdX) are excluded from this implementation due to their unique override structure and management.
Benefits
- ✅ Performance: Indexed queries instead of runtime block traversal
- ✅ Consistency: All dates managed in one canonical system
- ✅ Maintainability: No need to create redundant data models
- ✅ Scalability: Reusable for LMS, mobile, and analytics
- ✅ Forward-compatible: Aligned with plans to remove MongoDB and improve RBAC
Next Steps
- Ensure publishing pipeline writes dates to
ContentDate - Use
UserDateto record instructor and learner overrides - Build new endpoint
/api/user-due-dates/ - Merge base and override dates at runtime
- Implement access control and visibility filtering
- Monitor for latency, accuracy, and correctness
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.