インディーハッカー道
LMSをゼロから自作した理由と設計思想
開発記

LMSをゼロから自作した理由と設計思想

·10分で読める
平城寿
平城寿
@SOHO創業者 / インディーハッカー

この記事のポイント

  • 既製品のLMSを使わず
  • 学習管理システムをゼロからNext.js + Express + PostgreSQLで自作した理由と
  • 設計で重視したポイントを解説します

LMSをゼロから自作した理由と設計思想

「LMSなんて自作する必要はない。既製品を使えばいい」

99%の場合、これは正しいアドバイスです。

Teachable、Thinkific、Udemy。

既製品のLMS(Learning Management System:学習管理システム)は数多くあり、どれも十分に成熟しています。

ところが、私はあえてゼロから自作するという道を選びました。

なぜか。

この記事では、その理由と設計思想を包み隠さず書きます。

「車輪の再発明はするな」という格言を破ってまで自作した、その判断の背景を。

既製品LMSの限界

試したサービスたち

LMSの自作を決断する前に、私は複数の既製品を試しました。

Teachable

月額$39〜$199

UIは洗練されており、動画コンテンツの配信に強い。

ところが、カスタマイズ性が低いのが致命的でした。

コースの構成、進捗管理のロジック、修了証の発行条件。

これらを自分の仕様に合わせようとすると、すぐに壁にぶつかります。

「この機能はProプランにアップグレードすれば使えます」というアップセルの壁です。

Thinkific

月額$49〜$199

Teachableと似た機能セットですが、より柔軟なカスタマイズが可能。

ただし、日本語対応が不十分でした。

UIの一部が英語のまま残り、日本語のフォント表示も微妙。

日本のユーザー向けのサービスとしては、ユーザー体験が満足できるレベルではありませんでした。

Moodle(オープンソース)

無料で使えるオープンソースLMS。

機能は豊富ですが、UIが2010年代で止まっているという印象でした。

また、PHPベースで構築されているため、私の技術スタック(Next.js + Express)との親和性が低い。

カスタマイズしようとすると、PHPとMoodleの独自アーキテクチャを深く理解する必要があり、学習コストが高すぎました。

既製品を使わないと決めた3つの理由

1. 月額料金の積み重なり: Teachableの場合、年間$2,388(約36万円)。5年で180万円。自作すれば、サーバー代の月数千円で運用できる 2. ベンダーロックイン: 既製品にコンテンツを蓄積した後、他のサービスに移行するのは非常に困難。自作なら、データは常に自分のPostgreSQLにある 3. 差別化の不可能性: 既製品を使う限り、同じサービスを使っている競合と同じUXになる。独自のユーザー体験を提供したいなら、自作しかない

設計思想:「学習者ファースト」

LMSの設計で最も重要なのは、学習者の体験です。

管理者にとって便利であることよりも、学習者が「学びやすい」「続けやすい」と感じることを最優先にしました。

設計原則1:摩擦を最小にする

学習の最大の敵は摩擦です。

ログインが面倒、次のレッスンへの遷移が複雑、進捗がわかりにくい。

こうした小さな摩擦が積み重なると、学習者は離脱します。

Duolingoのデータによると、学習アプリのユーザーは最初の1週間で70%が離脱するそうです。

この数字を聞いた時、「いかに学習を続けさせるか」がLMSの最大の課題だと確信しました。

私のLMSでは、以下の工夫をしています。

  • ログイン不要でサンプルレッスンを閲覧可能: 登録のハードルを下げる
  • 前回の続きから自動的に再開: ブラウザを閉じても、次回アクセス時に前回の位置から始まる
  • 次のレッスンへのワンクリック遷移: レッスン完了後、ボタン1つで次に進める
  • 進捗バーの常時表示: 「あと何%で完了するか」が常にわかる

設計原則2:小さなフィードバックループ

学習の継続には、「できた」という実感が欠かせません。

私のLMSでは、各レッスンの最後に小さなクイズを配置しています。

レッスン視聴(5〜10分)
    ↓
理解度チェック(3〜5問のクイズ)
    ↓
正解フィードバック + 次のレッスンへの導線

このサイクルを15分以内で1周できるように設計しました。

心理学の研究では、学習のフィードバックは即時であるほど効果的だとされています(Hattie & Timperley, 2007)。

1時間の動画を見た後にまとめてテスト、ではなく、5〜10分の動画ごとにクイズ。

この小さなフィードバックループが、学習の定着率を大幅に向上させます。

設計原則3:進捗の可視化

人間は、ゴールまでの距離がわかるとモチベーションが維持しやすくなります。

これは心理学で『目標勾配効果(Goal Gradient Effect)』と呼ばれています。

ゴールに近づくほど、努力量が増加する現象です。

スタンプカードの例がわかりやすいです。

10個中8個のスタンプが溜まっている人は、2個中0個の人よりも熱心にスタンプを集めようとします。

LMSでも同じ原理を活用しています。

  • コース全体の進捗率をパーセンテージと進捗バーで表示
  • 完了したレッスンにはチェックマークを表示
  • 修了まであと何レッスンかを数値で表示

「あと3レッスンで修了」と表示されると、「もう少しだから頑張ろう」と思えるものです。

技術スタックと全体設計

技術スタック

フロントエンド: Next.js + React + Tailwind CSS
バックエンド:   Express.js + TypeScript
データベース:   PostgreSQL (Supabase)
認証:          Supabase Auth
ストレージ:     Supabase Storage(動画・画像)
決済:          Stripe

すべて、私が日常的に使い慣れている技術です。

LMSのために新しい技術を学ぶ必要はありませんでした。

これは1人開発の大きな利点です。

チーム開発では「このプロジェクトに最適な技術」を選ぶ必要がありますが、1人開発では「自分が最も生産性の高い技術」を選べばいいのです。

データベース設計

LMSの核心は、「誰が、何を、どこまで学習したか」を正確に記録することです。

主要なテーブルは以下の通りです。

-- コース
CREATE TABLE courses (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  title TEXT NOT NULL,
  description TEXT,
  price INTEGER NOT NULL DEFAULT 0,  -- 0は無料
  published BOOLEAN DEFAULT FALSE,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- レッスン
CREATE TABLE lessons (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  course_id UUID REFERENCES courses(id),
  title TEXT NOT NULL,
  content_type TEXT NOT NULL,  -- 'video', 'text', 'quiz'
  content_url TEXT,
  sort_order INTEGER NOT NULL,
  duration_minutes INTEGER,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- 学習進捗
CREATE TABLE progress (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  lesson_id UUID REFERENCES lessons(id),
  completed BOOLEAN DEFAULT FALSE,
  completed_at TIMESTAMPTZ,
  quiz_score INTEGER,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(user_id, lesson_id)
);

-- 受講登録
CREATE TABLE enrollments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  course_id UUID REFERENCES courses(id),
  enrolled_at TIMESTAMPTZ DEFAULT NOW(),
  completed_at TIMESTAMPTZ,
  UNIQUE(user_id, course_id)
);

設計で特にこだわった点は、progressテーブルのUNIQUE制約です。

UNIQUE(user_id, lesson_id)により、1人のユーザーが同じレッスンに対して複数のレコードを持つことを防いでいます。

これにより、「進捗の重複」という厄介なバグを根本から排除できます。

動画配信の設計

LMSで最も技術的に難しいのが動画配信です。

以下の要件を満たす必要があります。

1. 大容量ファイルの保存: 1本の動画が数百MBになることも 2. ストリーミング配信: ダウンロード完了を待たずに再生開始 3. アクセス制御: 購入したユーザーだけが視聴できる 4. 不正ダウンロードの防止: URLの直リンクによる不正視聴を防ぐ

これらの要件を満たすために、以下の設計にしました。

動画ファイルはSupabase Storageに保存し、署名付きURL(Signed URL)を使ってアクセス制御を行います。

// 署名付きURLの生成(有効期限: 1時間)
const { data, error } = await supabase.storage
  .from('videos')
  .createSignedUrl(`courses/${courseId}/${lessonId}.mp4`, 3600);

署名付きURLは有効期限付きのため、URLを共有されても一定時間後にアクセスできなくなります。

完璧な不正防止策ではありませんが、1人開発の規模感では十分な対策です。

決済(Stripe連携)

有料コースの決済にはStripeを使っています。

詳しくは別の記事で書いていますが、LMS特有のポイントだけ触れておきます。

1. 一括購入 vs サブスクリプション

私のLMSでは、コースごとの一括購入を採用しました。

サブスクリプションモデルも検討しましたが、コンテンツ量が限られている段階では「月額料金を払い続ける価値があるか?」という不安を学習者に与えてしまいます。

一括購入なら、「このコースに○○円を払う」という判断だけで済むため、購入のハードルが低いのです。

2. 返金ポリシー

Stripeでは最大120日間の返金が可能です。

私のLMSでは30日間の返金保証を設けています。

返金保証があることで、購入者の心理的ハードルが下がり、コンバージョン率が約20%向上しました。

実際に返金を請求されたのは、全購入の3%以下です。

返金保証は「損失」ではなく「投資」です。

開発期間と工数

LMSの開発にかかった期間と工数をまとめます。

フェーズ期間主な作業
設計1週間DB設計、UI設計、機能要件定義
コース管理(管理者側)2週間コースCRUD、レッスン管理、並び替え
学習画面(受講者側)2週間動画プレイヤー、進捗管理、クイズ
決済(Stripe連携)1週間購入フロー、Webhook、返金処理
認証・権限管理1週間Supabase Auth、RLS設定
テスト・バグ修正1週間E2Eテスト、エッジケース対応
合計約8週間

8週間、1人で。

既製品を使えば1日でセットアップできることを考えると、客観的に見れば非効率です。

ところが、8週間の投資で得られたものは大きいです。

  • 月額料金ゼロ(年間36万円の節約)
  • 完全なカスタマイズ自由
  • データの完全所有
  • 技術的な学び

5年間の運用を考えれば、既製品の総コスト180万円に対して、自作のコストは開発時間 + サーバー代(年間数万円)

長期的には、自作のほうが圧倒的にコストパフォーマンスが高いのです。

自作して良かったこと、後悔していること

良かったこと

1. ユーザー体験を完全にコントロールできる

既製品では「あとちょっとこうしたい」ができません。

自作なら、ユーザーからのフィードバックを受けて翌日にはUIを改善できます。

このスピード感は、既製品では絶対に得られません。

2. 他のサービスとのシームレスな連携

@SOHOのユーザーデータとLMSのユーザーデータを統合し、@SOHOの登録者にLMSの案内を送る、といった連携が簡単にできます。

異なるプラットフォームのデータを連携させるのは、通常は非常に面倒です。

自作なら、同じデータベース内でJOINするだけです。

後悔していること

1. 動画のトランスコーディング

動画のフォーマット変換(トランスコーディング)を自前で実装しようとして、2週間を無駄にしました。

結局、この部分はCloudflare Stream(月額$5〜)を使うことにしました。

動画のトランスコーディングは、1人で実装するには複雑すぎる領域です。

すべてを自作する必要はない。 苦手な部分は既存のサービスに任せる。

この判断ができるまでに、無駄な2週間を過ごしてしまいました。

読者の皆さんへ

LMSの自作を検討している方に、正直にお伝えします。

ほとんどの場合、既製品を使うべきです。

自作が正当化されるのは、以下の条件をすべて満たす場合だけです。

1. 既製品では実現できない独自の要件がある 2. 長期的(3年以上)に運用する予定がある 3. 技術力があり、1人で開発・保守できる 4. 既製品の月額料金が長期的に見てコスト高になる

これらの条件を満たさないなら、TeachableやThinkificを使ったほうが、はるかに早く、安く、確実です。

「作ること」自体が目的になってはいけません。

「ユーザーに価値を届けること」が目的であり、自作はその手段の一つに過ぎないのです。

それでも自作したいと思ったなら。

その情熱は本物です。

8週間の開発期間を楽しんでください。

この記事が、LMS開発の判断材料になれば幸いです。

シェア
#LMS#教育#SaaS#設計思想#1人開発
平城寿
平城寿
インディーハッカー。2004年に@SOHOを創業し、20年間1人で運営。
フォロー

関連記事