2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「学習コンテンツ」を Web アプリケーションとして設計する — Next.js × Prisma × Clerk × LLM で、研究知見ベースのコンテンツ配信基盤を作る話

2
Posted at

研修・社内教育・ドキュメント配信・eラーニング — 「人に何かを学んでもらう Web アプリ」 を作るとき、知らずに同じ落とし穴を踏むことが多いです。

  • 内容を画面に直接書くと、改訂のたびにフロントが壊れる
  • 公開タイミングを手で切り替えていると忘れる
  • LLM を組み込んだら「考えなくなる」ユーザーが増える
  • 学習ログを溜めたら、データガバナンスで詰む

この記事では、コンテンツ配信型 Web アプリを作るときに有効な設計パターンを、学習科学の査読論文と紐付けながら Next.js のスタックで整理します。

筆者は医療系の業界で AI 関連の仕事をしているので、医療AI 領域での裏取りも添えました。


0. この記事の主張(先に結論)

3つだけ覚えて帰ってください。

  • コンテンツは「データ」として持つと、保守性・再現性が一気に上がる
  • ユーザー体験(UX)の根拠は、学習科学の査読論文に既に書かれている
  • LLM を組み込むときは「丸投げ防止」をセットで設計しないと、教育効果がむしろ落ちる

各セクション、「研究原則 → 実装パターン」の順で並べます。


1. 技術スタック(参考構成)

レイヤ 採用技術 役割
フロント/サーバ Next.js 16 (App Router) / React 19 UI・API Routes
DB PostgreSQL コンテンツ・ログ
ORM Prisma スキーマ・型安全クエリ
認証/組織 Clerk ロール・組織スコープ
生成AI Google Gemini 2.0 Flash 対話・要約支援
ホスティング Vercel(国内リージョン) ログを国内で処理

設計の起点:ログは国内リージョンで処理する。外部 LLM に渡すのは一般的な知識のみ、と境界を先に引く。守りを固めてから機能を乗せる順序で進めます。


2. パターン①:コンテンツを「データ」として設計する

HTML や JSX に内容を直接書くと、改訂のたびにフロントエンドが壊れる現象がよく起きます。

これを回避するため、コンテンツを型付きデータとして持ち、UI はそれをレンダリングするだけにする

// コンテンツ=データ。種類で表現し、描画側が分岐する
type SectionType =
  | "lecture"      // 一方向の説明
  | "exercise"     // 演習・ハンズオン
  | "discussion"   // ディスカッション
  | "ai-chat"      // LLM 対話
  | "reflection";  // 振り返り

interface ContentSection {
  type: SectionType;
  title: string;
  body: string;          // Markdown
  prompt?: string;       // discussion / ai-chat 用の問い
}

interface ContentUnit {
  no: number;
  title: string;
  objectives: string[];
  sections: ContentSection[];
  quiz: QuizItem[];        // 形成的クイズ(後述)
  aiChatEnabled?: boolean; // ユニットごとに LLM 対話の可否を制御
}

この設計の利点

  • 改訂が差分で済む(文章はデータ、ロジックは1つ)
  • セクション種別ごとに体験を標準化できる
  • 新しいユニットの追加がデータ追加だけで完結
  • レビュー時に差分が見やすい

エンジニアリングのコツ

「変わり続けるもの」と「安定しているもの」を分離する。

  • 変わる:説明文・問い・選択肢・解答 → データ
  • 安定:レイアウト・遷移・状態管理 → ロジック

この境界をどこに引くかが、保守性を左右します。


3. パターン②:時刻ベースの公開制御(自動 × 手動上書き)

「いつから公開するか」を制御する状態機械です。自動公開を基本にしつつ、運用担当者が手動で前倒し / 非公開に上書きできる設計が現実的です。

type VisibilityOverride = "auto" | "force-show" | "force-hide";

function isVisible(
  now: Date,
  releaseAt: Date,
  override: VisibilityOverride
): boolean {
  if (override === "force-show") return true;
  if (override === "force-hide") return false;
  return now >= releaseAt; // auto: 公開時刻を過ぎたら表示
}

設計のポイント

  • タイムゾーン(JST)を明示
  • 自動を基本にしつつ、運用担当者に最終決定権を残す
  • 「うっかり非公開」「うっかり前倒し」のミスを DB の状態で吸収

運用の現実(リスケ・前倒し・障害対応)に耐える設計です。


4. パターン③:匿名化された協働ボード

各ユニットにディスカッション・ボードを持たせるケースがあります。ポイントは匿名性の設計です。

なぜ匿名重視か

  • 間違いや疑問を出しやすい場ほど、学習が駆動する
  • 大事なデータはそもそも表に出さない設計にする
  • もし含まれていても、安全側で扱うを徹底
interface DiscussionPost {
  id: string;
  unitNo: number;
  displayName: string;     // ニックネーム or "匿名"
  body: string;
  createdAt: Date;
  // 個人特定可能な情報は表示用 DTO に含めない
}

実装上の注意

  • タイムラインは個人を特定しない形で表示
  • フィルタ/検索は、集団の傾向を見るためのもの
  • ロールベース(admin/operator/user)で閲覧範囲を絞る

5. パターン④:LLM を組み込むときの「丸投げ防止」設計

ここが、最近のコンテンツ配信型アプリで一番悩むところです。

5.1 なぜ「丸投げ防止」が必要か

LLM の能力が上がりすぎて、ユーザーが考える前に LLM に投げる現象("シャドーAI 学習")が、教育文脈では実害として観察されています。

医療 AI 領域での裏取りを1本入れておきます。

LLM は臨床推論タスクで医師ベースラインを上回り、過去の AI 臨床判断支援システムから継続的な改善を示した、と Brodeur らの研究(2026年、PubMed 掲載・Science)が報告しています。論文では「LLM が臨床推論ベンチマークの大半を超えた今、急ぐべきは前向き臨床試験」と結論されています。

出典:Brodeur PG, et al. (2026). Performance of a large language model on the reasoning tasks of a physician. Science, 392(6797), 524-527. DOI: 10.1126/science.adz4433

医療プロフェッショナル相当のタスクで LLM が高性能を出せる時代、学習者が「考える前に投げる」誘惑は強くなる一方です。

5.2 ガードレールの実装方針

// ユニットごとに LLM 対話を ON/OFF
interface ContentUnit {
  // ...
  aiChatEnabled?: boolean;
}

// 「考える前に投げる」を防ぐ足場かけ
interface AiChatPolicy {
  requirePreHypothesis: boolean;  // LLM に聞く前に仮説を書かせる
  showLimitations: boolean;       // 出力に「限界」を併記
  logToReviewQueue: boolean;      // 運用担当者がレビュー
}

5.3 設計の原則

🟢 OK な使い方

  • ユーザーが自分の仮説を書いた後で LLM に聞く
  • LLM の出力に根拠と限界を必ず添える
  • ユニットによっては LLM を意図的に切る

🔴 避けるべき使い方

  • 起動直後から無制限の LLM チャット
  • LLM 出力を唯一の正解として扱う UI
  • 出力ログを保存せず、品質チェックができない設計

6. パターン⑤:形成的クイズ(= 検索練習)の組み込み

6.1 「能動的学習」「検索練習」の根拠

聞くだけより、手を動かす・思い出す・議論するほうが学習成果が上がる、というのは学習科学の古典的知見です。

STEM 分野の大規模統合分析(メタ分析)として、Freeman らの 2014 年の PNAS 論文が広く引用されます。

Freeman, S., et al. (2014). Active learning increases student performance in science, engineering, and mathematics. PNAS, 111(23), 8410–8415.
https://www.pnas.org/doi/10.1073/pnas.1319030111

また、「思い出す行為そのものが記憶を強くする」(検索練習効果)も、教育心理学で確立した知見です。

Roediger, H. L., & Karpicke, J. D. (2006). Test-Enhanced Learning. Psychological Science, 17(3), 249–255.

PubMed 掲載の医学教育研究でも、これは再確認されています。

分散学習(distributed practice)と練習テスト(practice testing)は、学部学生にとって最も効果的な学習技法と評価されている。一方、読み直し・下線引き・要約は、最もよく知られているが効果が低い、と Urrizola らの研究(2022年)が報告しています。

出典:Urrizola A, et al. (2022). Learning techniques that medical students use for long-term retention. Medical Teacher, 45(4), 412-418. DOI: 10.1080/0142159X.2022.2137016

つまり、「クイズで思い出させる」を UI に組み込むこと自体が、エビデンスベースの設計なんです。

6.2 実装

interface QuizItem {
  question: string;
  choices: string[];
  answerIndex: number;
  explanation: string;   // 解答直後にフィードバック
}

// ユニット末に配置
interface ContentUnit {
  // ...
  quiz: QuizItem[];
}

6.3 「分散学習」も組み込む

ユニットをまたいだ前回の振り返りを、新しいユニットの先頭に置く設計です。

Cepeda, N. J., Pashler, H., Vul, E., Wixted, J. T., & Rohrer, D. (2006). Distributed practice in verbal recall tasks. Psychological Bulletin, 132(3), 354–380.

「次のユニットを始める前に、前回の重要ポイントを思い出してもらう」だけで、長期保持が改善する、という主張です。


7. パターン⑥:匿名集計による可視化(Learning Analytics)

提出物や傾向を匿名で集計し、「全体の関心・つまずき」を可視化します。

設計の原則

  • 個人を名指ししない
  • 集団の像として運用担当者にフィードバックする
  • 表示する単位は、グループサイズが閾値以上のときだけ
// 集計時のアクセス制御の例
function getClassMetrics(groupId: string, requesterRole: Role) {
  if (requesterRole !== "operator") throw new Error("forbidden");
  return prisma.userResponse.groupBy({
    by: ["unitNo", "isCorrect"],
    where: { groupId },
    _count: true,
    having: {
      // グループサイズが小さいと個人特定リスクがあるため閾値を設定
      groupId: { _count: { gte: 5 } },
    },
  });
}

Learning Analytics(学習分析)は強力ですが、個人特定をしないことが信頼の前提です。集計は匿名・表示は集団、という線を最初から引きます。


8. データの守り(最初から固める)

ロールベースアクセス制御

// Clerk の roles と組み合わせて、API Route 層で検証
export async function GET(req: Request) {
  const { userId, sessionClaims } = await auth();
  const role = sessionClaims?.role as Role;

  if (role !== "operator") {
    return new Response("Forbidden", { status: 403 });
  }

  // 自組織スコープに厳格化
  const orgId = sessionClaims?.orgId as string;
  return await getMetricsForOrg(orgId);
}

データ境界の allowlist 発想

外部 LLM に渡すデータは、一般教材・知識のみに限定。

// 外部 LLM に投げる前の sanitizer の例
function sanitizeForExternalLLM(input: string): string {
  // 個人情報・組織内秘密情報のパターンを検知して除去
  // allowlist:一般的な教材・知識のみ通す
  return input
    .replace(EMAIL_PATTERN, "[EMAIL_REMOVED]")
    .replace(PHONE_PATTERN, "[PHONE_REMOVED]")
    .replace(INTERNAL_ID_PATTERN, "[ID_REMOVED]");
}

リージョンの選択

  • 学習ログは国内リージョンで処理
  • 大事なデータはそもそも外に出さない設定
  • もし外に出るものがあっても、契約で「保存しない」を担保

医療情報を扱う場合は、3省2ガイドラインや個人情報保護法の論点が別途あるので、必ず顧問弁護士・情報セキュリティ部門と相談してください(後述)。


9. コスト設計

  • 生成 LLM は Gemini 2.0 Flash に統一して運用コストを最適化
  • コンテンツ(Markdown / データ)のみの変更は ビルドをスキップ(Ignored Build Step)
  • 検証はローカル、本番反映は最小回数に
  • LLM 呼び出しは キャッシュ可能なものはキャッシュ

ビルドスキップの例(Vercel)

# vercel.json または環境設定で
# git ログを見て docs/ 配下しか変更がなければビルドをスキップ
git diff HEAD^ HEAD --quiet -- ':(exclude)docs/*' ':(exclude)content/*'

コンテンツが増えても課金が線形に増えない、という構造を最初に作っておくと、長期運用で効きます。


10. まとめ:研究原則 → 実装パターンの対応表

学習科学・教育の原則 一次情報 実装した機能
能動的学習が成績を上げる Freeman et al. 2014 [1] 演習・ディスカッション・LLM 対話を標準セクション化
検索練習(テストが記憶を強化) Roediger & Karpicke 2006 [2] 各ユニット末の形成的クイズ+即時フィードバック
分散学習 Cepeda et al. 2006 [3] ユニットをまたぐ振り返り・自動公開
LLM の高性能と限界 Brodeur et al. 2026 [4] ユニットごと LLM 対話 ON/OFF+丸投げ防止
効果的な学習技法 Urrizola et al. 2022 [5] クイズの即時フィードバックを標準化

要は、「学習科学の知見」を仕様に、「現代的な Web/AI スタック」を実装に置いただけです。

派手な新規性ではなく、既知の研究知見を、現場で動く Web アプリに翻訳する——そこに価値を置いています。


11. 医療・教育領域での運用時の注意点

⚠️ 本記事は筆者の現時点での個人的見解です。法的助言ではありません。

医療系・教育系で運用する場合、以下の論点が別途残ります。

🟢 そのまま使ってOK

  • 一般的な技術知識・公開済みの教材
  • 個人特定情報を含まない集計データ
  • オープンソースのドキュメント

🟡 注意が必要

  • 個人特定可能な学習ログ → 個人情報保護法の論点
  • 組織内秘密情報を含むコンテンツ → 契約上の論点
  • 外部 LLM への入力 → 各サービスのデータ保持ポリシーを確認

🔴 そのまま使うのは NG

  • 患者情報・要配慮個人情報を含むデータの外部 LLM 処理
  • 医療判断に直結する用途(薬機法 SaMD 該当性の検討が必要)
  • 個人特定可能なデータの第三者提供

医療系・教育系での導入は、必ず顧問弁護士・情報セキュリティ部門・関連法令の所管行政機関と相談のうえ判断してください。


まとめ

全部いきなり作らなくて大丈夫です。

まずは「コンテンツを"データ"として書き出す」 — その1点から始めるだけで、改訂も再利用もぐっと楽になります。

そこから、

  1. 公開制御の状態機械
  2. LLM のガードレール
  3. 検索練習を組み込んだクイズ
  4. 匿名化された集計

の順で乗せていけば、研究知見に裏付けられたコンテンツ配信基盤ができていきます。


一次情報(参考文献)

学習科学・教育

医学教育(PubMed 掲載・査読論文)

  • [4] Brodeur, P. G., et al. (2026). Performance of a large language model on the reasoning tasks of a physician. Science, 392(6797), 524-527.
    DOI: 10.1126/science.adz4433

  • [5] Urrizola, A., et al. (2022). Learning techniques that medical students use for long-term retention. Medical Teacher, 45(4), 412-418.
    DOI: 10.1080/0142159X.2022.2137016

情報技術


⚠️ 免責

本記事は筆者の現時点での個人的見解です。法的助言ではありません。

医療系・教育系のプロダクトに本記事のパターンを応用する場合は、必ず顧問弁護士・情報セキュリティ部門・所属組織の責任者と相談のうえ判断してください。

筆者は本記事の内容を実際の業務で使われたことに起因するいかなる損害についても責任を負いません。


著者プロフィール

臨床工学技士 × AIエンジニア / 11年間、病院の医療機器の現場に立ち続けてきました。
いまは AI エンジニアとしても活動しながら、酪農学園大学の研究生として論文博士の取得を目指しています。
研究テーマの主軸は遺伝子医療の未来。そのうえで、医療現場と地続きにある病院の IT・サイバーセキュリティ・医療 AI 導入についても、現場で起きている課題と一次情報を突き合わせながら調べ続けています。
臨床工学技士の教育関係の仕事にも携わっています。

質問・誤りの指摘・「うちの組織ではこうしている」という事例の共有、いつでも歓迎します。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?