Google Apps Script (GAS) + Vue.js 3 で構築するマルチテナント型学習支援Webアプリ。
Firestoreをデータベースとして使用し、教育委員会 → 学校 → 教員/生徒 の階層構造で管理する。
| レイヤー | 技術 | 備考 |
|---|---|---|
| バックエンド | Google Apps Script | doGet + google.script.run |
| フロントエンド | Vue.js 3 (CDN) | SFC不使用、Options/Composition API混在 |
| DB | Firestore (REST API) | ScriptApp.getOAuthToken()で認証 |
| AI | Claude API | Sonnet 4 / Vision対応 |
| ホスティング | GAS Webアプリ | doGet でHTML配信 |
index.html 生徒向け画面dashboard.html 教員ダッシュボードstudent_chat.html AIチャットteacher_assist.html AI教材生成grading.html AI答案採点02_Router.gs doGet + アクションルーター01_Auth.gs 4段階ロール認証03_StudentHandler.gs 生徒向け処理04_TeacherHandler.gs 教員向け処理05-09 AI連携・匿名化・採点10_Firestore.gs REST APIクライアント06_ClaudeAI.gs API基盤07_StudentChat.gs ヒント段階制御08_TeacherAssist.gs 教材/テスト/指導案生成09_Grading.gs Vision採点| action パラメータ | 返すHTML | 用途 |
|---|---|---|
index (デフォルト) | index.html | 生徒向け画面 |
dashboard | dashboard.html | 教員ダッシュボード |
studentChat | student_chat.html | AIチャット |
teacherAssist | teacher_assist.html | AI教材生成 |
grading | grading.html | AI答案採点 |
| 関数名 | 引数 | 戻り値 |
|---|---|---|
getBoards() | - | [{ id, name }] |
getSchools(boardId) | boardId | [{ id, name }] |
loginStudent(boardId, schoolId, studentId) | 3引数 | { ok, role, boardId, schoolId, studentId, subjects } |
loginTeacher(boardId, schoolId, teacherId, pw) | 4引数 | { ok, role, boardId, schoolId, teacherId, subjects } |
loginBoardAdmin(boardId, pw) | 2引数 | { ok, role, boardId, schools } |
{ action, boardId, schoolId, studentId }| action | 追加パラメータ | 処理関数 | 説明 |
|---|---|---|---|
getMaterials | subject?, grade?, unit? | getStudentMaterials | 教材一覧(公開+履修教科のみ) |
getQuiz | quizId | getStudentQuiz | 小テスト取得(正解なし) |
submitQuizAnswer | quizId, answers[] | submitQuizAnswer | テスト回答提出(正解付きで返す) |
submitReflection | materialId, subject, answers{} | submitReflection | 振り返り提出 |
getMyKartes | - | getStudentKartes | 自分のAIカルテ一覧 |
studentChat | subject, unit, messages[], hintLevel | handleStudentChat | AIチャット |
{ action, boardId, schoolId, teacherId, teacherPassword }| action | 権限 | 処理関数 | 説明 |
|---|---|---|---|
getMaterials | teacher+ | getTeacherMaterials | 教材一覧(非公開含む) |
getReflections | teacher+ | getTeacherReflections | 振り返り一覧 |
getStudentDetail | teacher+ | getTeacherStudentDetail | 生徒詳細 |
getStudentIds | teacher+ | getTeacherStudentIds | 管理番号一覧 |
exportForAI | teacher+ | exportAnonymized | AI匿名化エクスポート |
saveMaterial | teacher+ | saveMaterial | 教材保存 |
saveQuiz | teacher+ | saveQuiz | テスト保存 |
togglePublish | teacher+ | togglePublish | 公開切替 |
importAIKarte | teacher+ | importAIKarte | カルテインポート |
saveSettings | teacher+ | saveSettings | 教科マスター保存 |
registerStudents | schoolAdmin+ | registerStudents | 生徒一括登録 |
registerTeacher | schoolAdmin+ | registerTeacher | 教員登録 |
getTeachers | schoolAdmin+ | getTeacherList | 教員一覧 |
generateMaterial | teacher+ | handleGenerateMaterial | AI教材生成 |
generateQuiz | teacher+ | handleGenerateQuiz | AIテスト生成 |
generateLesson | teacher+ | handleGenerateLesson | AI指導案生成 |
gradeAnswer | teacher+ | handleGradeAnswer | AI答案採点 |
{ action, boardId, boardPassword }| action | 処理関数 | 説明 |
|---|---|---|
getSchools | getSchools | 学校一覧 |
addSchool | addSchool | 学校追加 |
getReflections | getBoardReflections | 全学校の振り返り |
getSchoolSummary | getSchoolSummary | 学校サマリー |
| 定数 | 値 | パスヘルパー |
|---|---|---|
CONFIG.COL.BOARDS | 'boards' | - |
CONFIG.COL.SCHOOLS | 'schools' | schoolPath(boardId, schoolId) |
CONFIG.COL.STUDENTS | 'students' | schoolCol(boardId, schoolId, 'students') |
CONFIG.COL.TEACHERS | 'teachers' | 同上 |
CONFIG.COL.MATERIALS | 'materials' | 同上 |
CONFIG.COL.QUIZZES | 'quizzes' | 同上 |
CONFIG.COL.QUIZ_ANS | 'quizAnswers' | 同上 |
CONFIG.COL.REFLECTIONS | 'reflections' | 同上 |
CONFIG.COL.KARTES | 'kartes' | 同上 |
CONFIG.COL.DUMMY_MAP | 'dummyMap' | 同上 |
CONFIG.COL.GRADING | 'gradingResults' | 同上 |
| 関数 | 用途 | 例 |
|---|---|---|
fsGet(path) | 1ドキュメント取得 | fsGet('boards/b1/schools/s1/students/S001') |
fsSet(colPath, docId, data) | ID指定で作成/上書き | fsSet('boards/b1/schools/s1/students', 'S001', {...}) |
fsAdd(colPath, data) | ID自動生成で作成 | fsAdd('boards/b1/schools/s1/reflections', {...}) |
fsUpdate(path, data) | 部分更新 | fsUpdate('boards/b1/.../materials/m1', { published: true }) |
fsDelete(path) | 削除 | fsDelete('boards/b1/.../students/S001') |
fsList(colPath) | 全ドキュメント取得 | fsList('boards/b1/schools/s1/students') |
fsQuery(colPath, where, orderBy, dir, limit) | 条件付き検索 | fsQuery(col, [{field:'subject', op:'EQUAL', value:'数学'}]) |
| ロール | 定数 | 認証方法 | 権限範囲 |
|---|---|---|---|
| 生徒 | student |
管理番号の存在チェック | 自分の履修教科の教材・テスト・振り返り |
| 教科担当 | teacher |
教員ID + パスワード | 担当教科のみ(教材CRUD、振り返り閲覧、AI連携) |
| 学校管理者 | schoolAdmin |
教員ID + パスワード (role: schoolAdmin) | 全教科 + 教員管理 + 生徒管理 |
| 教育委員会 | boardAdmin |
教育委員会ID + パスワード | 学校横断閲覧 + 学校追加 |
| 関数 | チェック内容 |
|---|---|
canAccessSubject(auth, subject) | 教科担当は自教科のみ、schoolAdmin/boardAdminは全教科OK |
isTeacherOrAbove(auth) | teacher, schoolAdmin, boardAdmin のいずれか |
isSchoolAdminOrAbove(auth) | schoolAdmin, boardAdmin のいずれか |
| ファイル | 種別 | 責務 | 依存先 |
|---|---|---|---|
00_Config.gs | GS | Firebase設定・コレクションパス・ロール定数 | - |
01_Auth.gs | GS | 4段階ロール認証 + アクセスログ | 10_Firestore |
02_Router.gs | GS | doGet + handleStudentAction / handleTeacherAction / handleBoardAction | 01_Auth, 03-09 |
03_StudentHandler.gs | GS | 教材取得・テスト受験・振り返り提出・カルテ閲覧 | 10_Firestore |
04_TeacherHandler.gs | GS | 教材CRUD・振り返り閲覧・生徒詳細・教員管理・設定 | 10_Firestore, 01_Auth |
05_AnonymizeAI.gs | GS | 振り返りのダミーID匿名化エクスポート | 10_Firestore, 01_Auth |
06_ClaudeAI.gs | GS | Claude API呼び出し基盤(テキスト/Vision) | - |
07_StudentChat.gs | GS | ヒント段階制御AIチャット | 06_ClaudeAI |
08_TeacherAssist.gs | GS | AI教材/テスト/指導案生成 | 06_ClaudeAI |
09_Grading.gs | GS | AI答案採点 + 採点結果保存 | 06_ClaudeAI, 10_Firestore |
10_Firestore.gs | GS | Firestore REST APIクライアント(CRUD + Query) | 00_Config |
index.html | HTML | 生徒向け画面(ログイン・教材・テスト・振り返り) | 02_Router |
dashboard.html | HTML | 教員ダッシュボード(管理・AI連携) | 02_Router |
student_chat.html | HTML | 生徒AIチャット画面 | 02_Router |
teacher_assist.html | HTML | 教員AI生成画面(教材/テスト/指導案) | 02_Router |
grading.html | HTML | AI答案採点画面 | 02_Router |
00_Config.gs の FIREBASE_PROJECT_ID を設定| パラメータ | 用途 | 使用ページ |
|---|---|---|
action | doGetルーティング | 全ページ |
boardId | 教育委員会ID | student_chat, teacher_assist, grading |
schoolId | 学校ID | 同上 |
studentId | 管理番号 | student_chat |
teacherId | 教員ID | teacher_assist, grading |
tp | 教員パスワード | teacher_assist, grading |
google.script.run でCSVデータを送信しない。canAccessSubject() で制御。| 項目 | 規約 |
|---|---|
| GAS関数名 | camelCase: getStudentMaterials, handleTeacherAction |
| プライベート関数 | _プレフィックス: _fsHeaders(), _writeLog() |
| Firestore操作 | 必ず 10_Firestore.gs のヘルパーを使う(直接REST呼び出し禁止) |
| 認証チェック | Router内で authenticate* を呼ぶ。Handler側では呼ばない。 |
| パスヘルパー | schoolPath(), schoolCol() を使う(パス文字列を直書きしない) |
| フロントエンド → GAS | gas(fnName, ...args) ヘルパー経由。直接 google.script.run を使わない。 |
| エラーハンドリング | GAS側は throw new Error()、フロント側は try/catch + showToast |
?tp=... で開かれる。
GAS WebアプリはHTTPS + Google認証基盤上で動作するため許容しているが、将来的にはセッショントークン方式への移行を検討。
優先度順に並んでいます。担当者は自由にアサインしてください。
| # | タスク | 詳細 | 難易度 | 担当 |
|---|---|---|---|---|
| 1 | イラスト画像生成・表示 |
AI生成画像を教材に埋め込む。 方針案: ・Gemini gemini-2.5-flash-image モデルで画像生成・生成画像をBase64またはCloud Storageに保存 ・教材本文に  形式で埋め込み・フロントで <img> タグに変換して表示課題: ・GASのレスポンスサイズ制限(Base64画像は大きい) ・Cloud Storage連携が必要になる可能性 ・画像生成の品質・適切さのチェック |
中〜高 | 未定 |
| 2 | 動画コンテンツ対応 |
教材内に動画を表示する。 方針案(段階的): Phase 1: YouTube埋め込み ・教員がYouTube URLを教材本文に貼付 ・フロントで自動的にiframeプレイヤーに変換 ・AIが単元に関連するYouTube動画を推薦 Phase 2: 動画生成(将来) ・Google Vids API / Synthesia 等で解説動画を自動生成 ・Mermaidアニメーション → GIF/MP4変換 課題: ・YouTube埋め込みはGASのiframe制限に注意 ・動画生成AIは現状高コスト ・学校ネットワークのYouTubeフィルタリング対応 |
高 | 未定 |
| # | タスク | 詳細 | 難易度 | 担当 |
|---|---|---|---|---|
| 3 | 採点サマリーUI |
grading.html にクラス全体の採点サマリー表示を追加。 バックエンド handleGetGradingSummary は実装済み。問題ごとの正答率グラフ、平均点、得点分布を表示。 |
低 | 未定 |
| 4 | Firestoreセキュリティルール |
クライアントからの直接アクセスを拒否するルールを設定。 現在はテストモードのため全アクセス許可になっている。 allow read, write: if false; で全拒否(GASはサーバーサイドなので影響なし)
|
低 | 未定 |
| 5 | 教材Markdownレンダリング強化 |
教材本文のMarkdown(見出し・太字・リスト・表)をHTMLに変換。 現在はMermaid/KaTeX/改行のみ対応。 marked.js等のライブラリ導入を検討。 |
低 | 未定 |
| 6 | パスワードハッシュ化 |
現在教員パスワードを平文でFirestoreに保存している。 SHA-256等でハッシュ化して保存するよう変更。 Utilities.computeDigest() を使用。
|
低 | 未定 |
| # | タスク | 詳細 | 難易度 | 担当 |
|---|---|---|---|---|
| 7 | E2Eテスト | 主要フローの自動テスト。GAS環境でのテストは難しいため、APIレベルのテスト関数を作成。 | 中 | 未定 |
| 8 | セッショントークン方式 | 現在URLパラメータで教員パスワードを渡している。JWT等のトークン方式に移行。 | 中 | 未定 |
| 9 | PWA対応 | Service Worker + マニフェストでオフライン対応・ホーム画面追加。 | 中 | 未定 |
| 10 | 学習分析ダッシュボード | テスト成績の推移グラフ、教科別の強み/弱み分析、クラス全体のヒートマップ。Chart.js導入。 | 中 | 未定 |