LMS Progress Tracking System Development
Progress Tracking in LMS is more than "completed X of Y lessons." Full system tracks second-level activity, analyzes learning patterns, and identifies students at risk of dropping out.
What and How to Track
Lesson level:
- Open and close times
- Video completion % (not just "opened" but "watched 85%")
- Text content scrolling
- Interactive element clicks
Course level:
- % completed lessons
- % completed assignments
- Last activity date
- Streak (consecutive days)
Platform level:
- Average session length
- Device types and peak activity times
- Cohort retention (% students active after 7/14/30 days)
Data Model
CREATE TABLE lesson_progress (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
student_id UUID REFERENCES users(id),
lesson_id UUID REFERENCES lessons(id),
course_id UUID REFERENCES courses(id),
status VARCHAR(30) DEFAULT 'not_started', -- not_started, in_progress, completed
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
video_progress JSONB, -- { "duration_ms": 3600000, "watched_ms": 3060000 }
time_spent_secs INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_lesson_progress_student ON lesson_progress(student_id, created_at);
Event Tracking (Client)
// Track video progress every 30 seconds
video.addEventListener('timeupdate', debounce(() => {
fetch('/api/lessons/track/video-progress', {
method: 'POST',
body: JSON.stringify({
lessonId,
currentTime: video.currentTime,
duration: video.duration,
}),
});
}, 30000));
// Track lesson completion
async function completeLesson(lessonId) {
await fetch(`/api/lessons/${lessonId}/complete`, {
method: 'POST',
body: JSON.stringify({ completedAt: new Date() }),
});
}
Risk Detection
-- Students at risk of dropping out
SELECT u.id, u.email, c.name, datediff(day, lp.started_at, NOW()) AS days_inactive
FROM lesson_progress lp
JOIN users u ON u.id = lp.student_id
JOIN courses c ON c.id = lp.course_id
WHERE lp.status = 'in_progress'
AND datediff(day, lp.started_at, NOW()) > 14
AND u.email NOT IN (SELECT email FROM support_tickets WHERE status != 'closed')
ORDER BY days_inactive DESC;
Timeline
Basic progress tracking—3–5 days. Risk detection with notifications—1–2 weeks.







