コンテンツにスキップ

ありがとうございます。

ここから 第14段階:受講機能(LMS機能)設計 に進みます。

これまでの設計では、

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
教材管理(LCMS)

教師
 ↓
教材作成
 ↓
管理者承認
 ↓
公開


受講管理(LMS)

受講者
 ↓
コース受講
 ↓
学習進捗管理

という2つの領域に分けています。

今回は 受講者が学習するための機能 を設計します。


第14段階の対象機能

今回実装対象:

機能 概要
受講登録 受講者がコースを開始
コース進捗 何%完了したか管理
レッスン進捗 閲覧済み・完了管理
動画視聴履歴 視聴時間管理
クイズ回答 回答履歴管理
修了判定 コース完了判定
学習ダッシュボード 進捗表示

1. 受講関連テーブル構成

全体:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
User
 |
 |
Enrollment
 |
 |
Course
 |
 |
CourseSection
 |
 |
Lesson
 |
 |
Content


LearningProgress

QuizAnswerHistory

VideoWatchHistory

2. 受講登録(Enrollment)

役割

「誰が、どのコースを受講しているか」

を管理します。


テーブル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
CREATE TABLE enrollments (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    user_id BIGINT NOT NULL,

    course_id BIGINT NOT NULL,

    status VARCHAR(30) NOT NULL,

    started_at DATETIME,

    completed_at DATETIME,

    created_at DATETIME NOT NULL,

    UNIQUE(
        user_id,
        course_id
    )

);

3. Enrollment Entity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Entity
@Table(name="enrollments")
@Getter
@Setter
public class Enrollment {


    @Id
    @GeneratedValue(
        strategy=GenerationType.IDENTITY
    )
    private Long id;


    @ManyToOne(fetch=FetchType.LAZY)
    private User user;


    @ManyToOne(fetch=FetchType.LAZY)
    private Course course;


    @Enumerated(EnumType.STRING)
    private EnrollmentStatus status;


    private LocalDateTime startedAt;


    private LocalDateTime completedAt;


    private LocalDateTime createdAt;

}

4. 受講状態

1
2
3
4
5
6
7
8
9
public enum EnrollmentStatus {

    ACTIVE,

    COMPLETED,

    CANCELLED

}

5. 受講開始処理

URL:

1
/student/course/{id}/start

Service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Service
@RequiredArgsConstructor
public class EnrollmentService {


    private final EnrollmentRepository repository;


    @Transactional
    public void start(
            User user,
            Course course){


        Enrollment enrollment =
            new Enrollment();


        enrollment.setUser(
            user
        );


        enrollment.setCourse(
            course
        );


        enrollment.setStatus(
            EnrollmentStatus.ACTIVE
        );


        enrollment.setStartedAt(
            LocalDateTime.now()
        );


        repository.save(
            enrollment
        );

    }

}

6. レッスン進捗管理

目的

例えば:

1
2
3
4
5
6
7
8
9
Java基礎

第1章

✓ Lesson1
✓ Lesson2
△ Lesson3

進捗 66%

を表示します。


7. LearningProgressテーブル

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE learning_progress (

    id BIGINT AUTO_INCREMENT PRIMARY KEY,

    user_id BIGINT NOT NULL,

    lesson_id BIGINT NOT NULL,

    status VARCHAR(30),

    started_at DATETIME,

    completed_at DATETIME,

    UNIQUE(
        user_id,
        lesson_id
    )

);

8. Progress Entity

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Entity
@Table(name="learning_progress")
@Getter
@Setter
public class LearningProgress {


    @Id
    @GeneratedValue(
        strategy=GenerationType.IDENTITY
    )
    private Long id;


    @ManyToOne(fetch=FetchType.LAZY)
    private User user;


    @ManyToOne(fetch=FetchType.LAZY)
    private Lesson lesson;


    @Enumerated(EnumType.STRING)
    private ProgressStatus status;


    private LocalDateTime startedAt;


    private LocalDateTime completedAt;

}

9. ProgressStatus

1
2
3
4
5
6
7
8
9
public enum ProgressStatus {

    NOT_STARTED,

    LEARNING,

    COMPLETED

}

10. レッスン完了処理

受講者が「完了」ボタンを押します。


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Transactional
public void completeLesson(
        User user,
        Long lessonId){


    LearningProgress progress =
        repository
        .findByUserIdAndLessonId(
            user.getId(),
            lessonId
        )
        .orElseGet(
            LearningProgress::new
        );


    progress.setUser(
        user
    );


    progress.setLesson(
        lessonRepository
        .getReferenceById(
            lessonId
        )
    );


    progress.setStatus(
        ProgressStatus.COMPLETED
    );


    progress.setCompletedAt(
        LocalDateTime.now()
    );


    repository.save(
        progress
    );

}

11. コース進捗計算

計算例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
全Lesson数

10


完了Lesson数

7


進捗

70%

MyBatisで集計します。


CourseProgressDto

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Data
public class CourseProgressDto {


    private Long courseId;


    private String courseName;


    private Integer totalLessons;


    private Integer completedLessons;


    public int getProgressRate(){

        if(totalLessons==0){
            return 0;
        }

        return
        completedLessons
        *100
        /
        totalLessons;

    }

}

12. CourseProgressMapper

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Mapper
public interface CourseProgressMapper {


    CourseProgressDto findProgress(
        Long userId,
        Long courseId
    );

}

13. SQL

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<select id="findProgress"
resultType="CourseProgressDto">

SELECT

c.id course_id,

c.name course_name,


COUNT(l.id)
AS total_lessons,


COUNT(lp.id)
AS completed_lessons


FROM courses c


JOIN lessons l

ON l.course_id=c.id


LEFT JOIN learning_progress lp

ON lp.lesson_id=l.id

AND lp.user_id=#{userId}


WHERE c.id=#{courseId}


GROUP BY c.id


</select>

14. 動画視聴履歴

動画教材の場合、

単純な完了だけでは不足します。

例:

1
2
3
4
5
動画60分

現在視聴

35分

を保持します。


VideoWatchHistory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CREATE TABLE video_watch_history (

id BIGINT AUTO_INCREMENT PRIMARY KEY,

user_id BIGINT,

lesson_id BIGINT,

watched_seconds INT,

last_position INT,

updated_at DATETIME

);

Entity:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Entity
@Getter
@Setter
public class VideoWatchHistory {


@Id
@GeneratedValue
private Long id;


@ManyToOne
private User user;


@ManyToOne
private Lesson lesson;


private Integer watchedSeconds;


private Integer lastPosition;


private LocalDateTime updatedAt;


}

15. クイズ回答履歴

設計

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
受講者

↓

Quiz

↓

回答

↓

正誤

QuizAnswerHistory

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CREATE TABLE quiz_answer_history (

id BIGINT AUTO_INCREMENT PRIMARY KEY,

user_id BIGINT,

quiz_id BIGINT,

answer_correct BOOLEAN,

score INT,

answered_at DATETIME

);

16. 修了判定

条件例:

1
2
3
4
5
6
7
8
9
全Lesson完了

+

必須Quiz合格

↓

修了

CompletionService

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Service
@RequiredArgsConstructor
public class CompletionService {


public boolean checkComplete(
        Long userId,
        Long courseId){


    int lessonRate =
        progressMapper
        .completedRate(
            userId,
            courseId
        );


    int quizRate =
        quizMapper
        .scoreRate(
            userId,
            courseId
        );


    return
    lessonRate==100
    &&
    quizRate>=80;

}

}

17. 受講者画面

コース一覧

1
/student/course

表示:

1
2
3
4
5
Java基礎講座

進捗 70%

[学習開始]

学習画面

1
/student/lesson/{id}

表示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Javaとは

----------------

動画

▶ 再生


概要


[完了]

18. メンター対応準備

今回は画面を作りませんが、

将来:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Mentor

↓

Student

↓

Enrollment

↓

LearningProgress

を見るだけなので、

現在の設計で対応可能です。

追加予定:

1
2
3
4
5
mentor_assignments

mentor_id

student_id

19. 第14段階終了時点の構成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
                 Course

                    |
                    |
               Enrollment

                    |
                  Student


                    |
                    v

             LearningProgress

                    |

       +------------+------------+

       VideoWatch          QuizHistory


                    |

             Completion

第14段階終了時点

実装できる機能:

✅ コース受講登録
✅ レッスン進捗管理
✅ 動画視聴履歴
✅ クイズ回答履歴
✅ コース進捗率計算
✅ 修了判定設計
✅ メンター拡張準備


次の 第15段階 では、教材システムの検索・管理機能を強化します。

内容:

  1. 教材ライブラリ画面完成

  2. 高度な検索

  3. タグ管理

  4. カテゴリ管理

  5. 教材再利用機能

  6. お気に入り教材

  7. 教材評価・レビュー

  8. ダッシュボード集計

へ進みます。