ありがとうございます。
ここからがこのシステムの設計で最も重要な部分になります。
前回のDB設計でも十分実装できますが、実際のLMS(Learning Management System)では以下の問題が発生します。
公開済み教材を修正すると、受講者が見ている教材まで変更されてしまう
例えば
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
これは企業向け教材ではほぼNGです。
そのため、多くのLMSでは
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
という運用をしています。
第3段階 設計改善(実運用レベル)
全体イメージ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
ポイントは
Contentを親
ContentVersionを子
にすることです。
なぜVersionを作るのか
例えば
1 | |
という教材があるとします。
Content
1 2 3 | |
Version
1 2 3 | |
教師が修正
1 2 3 | |
受講者は
1 | |
を見ています。
管理者が承認すると
1 2 3 | |
になります。
つまり
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
ができます。
Content
Contentは固定情報だけ。
1 2 3 4 5 6 7 8 9 10 11 | |
ContentVersion
ここに本文を持たせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
status
1 2 3 4 5 6 7 8 9 | |
Video
1 2 3 4 5 6 7 8 9 | |
Versionに紐付きます。
Text
1 2 3 4 5 6 7 | |
Markdownなら
1 2 3 4 5 6 7 8 9 | |
Quiz
1 2 3 4 5 6 7 8 9 10 11 | |
Choice
1 2 3 4 5 6 7 8 9 | |
File
1 2 3 4 5 6 7 8 9 | |
承認フロー
教師
1 2 3 4 5 | |
↓
申請
1 | |
↓
管理者
1 | |
↓
公開日時
1 | |
↓
公開終了
1 | |
スケジュール公開
公開日時を持たせます。
1 2 3 | |
例えば
1 2 3 4 5 6 7 | |
これだけで
1 2 3 4 5 | |
で公開できます。
公開対象
将来のために
1 | |
を追加します。
1 2 3 4 5 | |
コースもVersion管理する?
ここが設計の分かれ目です。
私は
コースもVersion管理する
ことをおすすめします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
理由
1 2 3 4 5 6 7 8 9 | |
からです。
SectionもVersion管理する?
ここは不要です。
Sectionは
1 | |
に属せば十分です。
1 2 3 4 5 6 7 8 9 | |
で問題ありません。
LessonもVersion管理する?
これも不要です。
1 2 3 4 5 | |
だけで十分です。
Lessonは
1 2 3 | |
程度なのでVersion化のメリットが少ないです。
将来追加できるもの
この設計なら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
全部
1 | |
を増やすだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
この設計で追加できる運用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
すべて対応できます。
ここでさらに改善したい点
ここまででかなり実運用に近い設計になりますが、企業向けLMSとして考えると、さらに次の3点を最初から取り入れることを強くおすすめします。
1. Lesson と Content の関係を見直す
現在は
1 2 3 | |
ですが、実際には「レッスン内で複数コンテンツを自由に並び替えたい」「同じコンテンツを別レッスンでも利用したい」という要件が出やすいです。
そのため、
1 2 3 4 5 | |
とすると、コンテンツの再利用や並び順管理が柔軟になります。
2. 添付ファイルを共通化する
動画・テキスト・クイズそれぞれに画像やPDFを添付したくなることがあります。
1 2 3 | |
という共通添付テーブルを持たせると、サムネイルや補足資料を一元管理できます。
3. コンテンツタイプごとのテーブルをなくす選択肢
Spring Boot + JPAでは、ContentVersion を継承の親エンティティとし、VideoContent、TextContent、QuizContent などを継承エンティティとして扱う方法もあります。
ただし、JPA継承は複雑なJOINやMyBatisとの併用時に扱いが難しくなるため、このシステムでは現在提案している「共通テーブル + タイプ別詳細テーブル」の構成の方が保守しやすいと考えます。
次の第4段階
ここからはいよいよSpring Bootの実装を見据えた設計に入ります。
第4段階では、以下をまとめて設計します。
-
パッケージ構成
-
Entity一覧と継承関係
-
Repository / MyBatis Mapper の責務分担
-
DTO・Form・SearchCondition の設計
-
Service層の責務
-
Controller構成
-
Spring Security(認証・認可)設計
-
画面一覧とURL設計
この段階まで設計すると、そのまま実装を開始できるレベルのアーキテクチャになります。
ご提案の以下2点については、改善をしてもう一度設計をお願いします。 1. Lesson と Content の関係を見直す 2. 添付ファイルを共通化する
この2点は、実際のLMS(Moodle、Canvas、Udemy Business、社内教育システムなど)でも重要になる部分です。
結論から言うと、私は以下のように変更することをおすすめします。
-
Lesson と Content は直接紐付けない
-
Content は教材ライブラリとして独立させる
-
LessonContent(中間テーブル)でレッスンへ配置する
-
添付ファイルは Attachment として共通化する
これにより、コンテンツの再利用・バージョン管理・添付ファイル管理が非常にシンプルになります。
新しい教材構造
まず教材構造を変更します。
従来
1 2 3 4 5 6 7 | |
↓
改善後
1 2 3 4 5 6 7 8 9 10 11 | |
ここで LessonContent を追加します。
なぜ LessonContent が必要なのか
例えば
1 2 3 4 5 6 7 | |
があります。
ところが
1 2 3 4 5 6 | |
でも利用したくなる可能性があります。
現在の設計では
1 2 3 4 5 | |
なので
Javaとは
をコピーするしかありません。
コピーすると
1 2 3 4 5 6 7 | |
になります。
これは教材管理では非常によくある失敗例です。
中間テーブル方式
そこで
1 2 3 4 5 6 7 8 9 | |
にします。
例えば
1 2 3 4 5 | |
これを
1 2 3 4 5 | |
1 2 3 4 5 | |
のように配置できます。
つまり
1 2 3 4 5 | |
になります。
これはCMS(WordPress等)の記事と同じ考え方です。
LessonContent
新しいテーブル
1 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
required_flag
1 | |
なら必須教材
false
なら参考資料
にもできます。
Content
Contentは教材そのものです。
1 2 3 4 5 6 7 8 9 | |
Lessonとの関係は持ちません。
ContentVersion
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
ここに本文があります。
コンテンツタイプ
1 2 3 4 5 6 7 | |
今まで通りです。
添付ファイルを共通化
ここはぜひ改善したいところです。
現在
1 2 3 | |
1 2 3 | |
1 2 3 | |
など
種類ごとに持とうとしていました。
しかし
実際には
テキスト教材にも
1 2 3 4 5 6 7 | |
を添付したくなります。
動画にも
1 2 3 4 5 | |
を付けたくなります。
なので
Attachmentを共通化します。
Attachment
新テーブル
1 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
attachment_type
ここが重要です。
1 2 3 4 5 6 7 8 9 10 11 | |
例えば
動画なら
1 2 3 4 5 | |
テキストなら
1 2 3 4 5 | |
全部同じテーブルになります。
storage_type
1 2 3 4 5 6 7 8 9 | |
Cloudflare R2へ移行しても
変更不要になります。
TextContent
かなりシンプルになります。
1 2 3 4 5 | |
画像は
Attachment
になります。
VideoContent
1 2 3 4 5 6 7 8 9 | |
サムネイル
字幕
資料
は
Attachment
になります。
QuizContent
1 2 3 4 5 6 7 8 9 | |
画像問題なら
Attachment
に画像を登録するだけです。
FileContent
ここだけ少し考え方が変わります。
以前
1 2 3 4 5 | |
でした。
でも
Attachmentがあるので
1 2 3 4 5 | |
にします。
1 2 3 | |
実際のファイルは
Attachment
になります。
つまり
Attachmentの
1 2 3 4 5 | |
になります。
新ER
これが私なら採用する構造です。
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 | |
この設計のメリット
| 改善点 | メリット |
|---|---|
| LessonContent追加 | 同じ教材を複数レッスンで再利用できる |
| Contentを独立 | 教材ライブラリとして管理できる |
| ContentVersion | 公開版・下書きを共存できる |
| Attachment共通化 | 画像・PDF・字幕・ZIP・サムネイルを一元管理 |
| FileContent簡素化 | ファイル管理の重複がなくなる |
| Cloudflare R2対応 | 保存先を変更してもDB設計は変わらない |
| 将来の拡張 | 音声・ライブ・AI教材なども追加しやすい |
さらに実運用を見据えた改善案
このシステムを企業向け・商用レベルまで発展させるなら、Content(教材ライブラリ)と Course(コース)を完全に分離することをおすすめします。
つまり、教師は最初に「教材ライブラリ」でコンテンツを作成・承認し、その後コースのレッスンへドラッグ&ドロップのような感覚で配置する構成です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
この構成であれば、
-
同じ教材を複数コースで再利用できる
-
教材を更新すると、どのコースで利用されているか追跡できる
-
「教材ライブラリ」と「コース設計」が分離され、運用しやすい
-
将来的に教材の販売や共有、教材テンプレート機能なども追加しやすい
という大きな利点があります。
この設計は、これまでのご要望(JPA + MyBatis + Spring Security + Thymeleaf)とも非常に相性が良く、長期運用を前提とした教材管理システムとしておすすめできる構成です。
ありがとうございます。「教材ライブラリ」の設計を採用してください。
ありがとうございます。
私もこのシステムであれば、「教材ライブラリ」方式が最適だと思います。
ここまでのお話を踏まえると、このシステムは「教材管理システム」ではなく、LMS(Learning Management System)+ LCMS(Learning Content Management System) に近い構成になります。
-
LCMS:教材(コンテンツ)を作成・管理・承認・バージョン管理する
-
LMS:教材を組み合わせてコースを作成し、受講・進捗管理を行う
この2つを最初から分離しておくと、将来的な拡張性が非常に高くなります。
最終アーキテクチャ
大きく4つのドメインに分けます。
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 | |
コンテンツライブラリ
ここが教師の作業場所になります。
1 2 3 4 5 6 7 8 9 10 | |
教師はここで教材を作成します。
まだコースには所属しません。
コース作成
教材を組み合わせます。
例えば
1 | |
を作るとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
この「配置」だけを管理します。
教材自体はコピーしません。
LessonContent
ここが重要になります。
1 2 3 4 5 6 7 8 9 | |
例えば
1 2 3 | |
には
1 2 3 4 5 | |
を配置。
別の
1 | |
では
1 2 3 | |
だけ利用できます。
Content
Contentは教材そのものです。
1 2 3 4 5 6 7 8 9 | |
ここには
本文はありません。
ContentVersion
ここに教材があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
詳細テーブル
1 2 3 4 5 6 7 8 9 10 11 | |
この考えは変えません。
Attachment
全コンテンツ共通になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
例えば
1 2 3 4 5 6 7 8 9 10 11 | |
全部ここです。
コースバージョン
ここは以前より強くおすすめします。
1 2 3 4 5 | |
理由
公開中コース
1 | |
に
1 | |
を追加したい。
でも
受講中の人は
旧版
を見せたい。
なので
1 2 3 4 5 | |
は必須になります。
教材配置
最終的には
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
になります。
ここが最終形です。
Section
Sectionは無限階層です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
parent_section_id
だけで実現します。
公開フロー
教材
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
コース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
教材とコースを分離します。
受講者
受講者は
1 | |
しか見えません。
中では
1 2 3 4 5 | |
の
公開版だけ
取得します。
将来追加予定の機能
この設計なら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
全部追加できます。
私が追加したい設計
ここからは、このシステムを企業向け・商用レベルにするために、ぜひ最初から取り入れたい設計です。
① ContentTag(教材タグ)
カテゴリとは別にタグを持たせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
ライブラリ検索が圧倒的に使いやすくなります。
② ContentRelation(関連教材)
教材同士を関連付けます。
1 2 3 4 5 6 7 8 9 10 11 | |
受講画面にも表示できます。
③ ContentUsage(教材利用状況)
これを追加すると
1 2 3 4 5 6 7 8 9 10 11 | |
がすぐ分かります。
これは非常に重要です。
教材を修正するとき
1 2 3 4 5 6 7 | |
と表示できます。
次の設計で追加したいもの
ここまでくると、Spring Boot実装前に「ドメインモデル」を確定させたい段階です。
次は単なるテーブル一覧ではなく、
-
Entityクラス一覧
-
Entity同士の関連(
@OneToMany、@ManyToOneなど) -
JPAで管理するEntity
-
MyBatisで取得するDTO
-
RepositoryとMapperの責務
-
Service間の依存関係
まで含めた実装レベルのアーキテクチャ設計を行うことをおすすめします。
ここまで設計すれば、そのままSpring Boot 3 + JPA + MyBatis + Spring Securityで実装を開始できるレベルになります。