Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3b1ead7
feat(classroom): お知らせテーブルと先生向け通知APIを追加 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
ab982df
feat(admin): お知らせ送信API (classroomId 指定・audit付き) を追加 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
688ac72
feat(admin): クラス詳細に先生へのお知らせ送信フォームを追加 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
ed6e376
feat(gui): クラス管理右上にお知らせセンターを追加 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
6e33f70
docs(classroom,admin): お知らせセンターのドキュメントと検証スクリプトを追加 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
56c226c
fix(classroom,admin,gui): お知らせセンターの敵対レビュー指摘対応 (#1111)
smalruby3-editor-bot[bot] Jul 25, 2026
5faa7ff
Merge pull request #1113 from smalruby/feature/notification-center-1111
smalruby3-editor-bot[bot] Jul 25, 2026
33eaf0b
feat(admin,classroom): 共有課題の Admin 推薦APIと先生向け recommended 投影 (#1110)
smalruby3-editor-bot[bot] Jul 25, 2026
fa7587d
feat(admin): 限定公開タブと推薦する/取り消す操作を追加 (#1110)
smalruby3-editor-bot[bot] Jul 25, 2026
7665198
feat(gui): 推薦バッジと限定公開→全体公開への発展導線 (#1110)
smalruby3-editor-bot[bot] Jul 25, 2026
da111ff
docs(assignment-sharing,admin,classroom): 推薦機能のドキュメントとスクリーンショット (#1110)
smalruby3-editor-bot[bot] Jul 25, 2026
5f10e06
fix(admin,classroom,gui): 課題推薦の敵対レビュー指摘対応 (#1110)
smalruby3-editor-bot[bot] Jul 25, 2026
938188b
Merge pull request #1114 from smalruby/feature/shared-recommendation-…
smalruby3-editor-bot[bot] Jul 25, 2026
0e4846c
feat(admin,classroom): 課題の共有推奨フラグAPIと有益候補バグ修正 (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
f909c12
feat(admin): クラス詳細に共有推奨アクション・俯瞰候補に推奨済みバッジ (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
ea3f01f
feat(gui): 課題詳細に共有促しバナー・ボード行に共有おすすめマーク (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
399cdde
docs(classroom,admin): 共有推奨のドキュメントとスクリーンショット (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
4d9ec65
fix(admin,gui): 共有推奨の敵対レビュー指摘対応 (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
600aa6f
test(admin): overview テストのフィクスチャを実フィールド名 assignment に修正 (#1106)
smalruby3-editor-bot[bot] Jul 25, 2026
329be50
Merge pull request #1115 from smalruby/feature/share-suggestion-1106
smalruby3-editor-bot[bot] Jul 25, 2026
81bde27
fix(admin): 詳細画面の「一覧に戻る」ボタンのスタイルを他ボタンに揃える (#1106 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
d314a7e
fix(admin): 戻るボタンのサイズ一致 + 限定公開の未入力属性を「未指定」表示 (#1106 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
ce3cd19
docs(classroom-notification-center): トピック集約の紹介ページとスクリーンショット
smalruby3-editor-bot[bot] Jul 26, 2026
5344302
Merge pull request #1116 from smalruby/fix/admin-back-button-style
smalruby3-editor-bot[bot] Jul 26, 2026
eb245a8
Merge pull request #1117 from smalruby/docs/topic-classroom-notificat…
smalruby3-editor-bot[bot] Jul 26, 2026
225d850
feat(gui,admin): 通知の日次取得・アバターメニュー・白ベル・全件ページ (#1111 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
24e184b
docs: 集約プレゼンのスクショ 10 枚を現行 UI で撮り直し (#1111 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
0d0d9af
fix: 通知UX 敵対レビュー指摘対応 (#1111)
smalruby3-editor-bot[bot] Jul 26, 2026
dd61119
Merge pull request #1118 from smalruby/feature/notification-ux-cost
smalruby3-editor-bot[bot] Jul 26, 2026
9bff6e5
feat(gui): お知らせパネルに ⋯ メニュー + 一覧ページのパンくず/戻る (#1111 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
e10be71
fix(gui): お知らせフックの docstring 修正 + パネル ⋯ ポップアップのクリップ回避 (#1111 レビュー)
smalruby3-editor-bot[bot] Jul 26, 2026
2d99863
Merge pull request #1119 from smalruby/feature/notification-menu-1111
smalruby3-editor-bot[bot] Jul 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .claude/rules/infra/smalruby-classroom.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ CDK project for the Classroom service (API Gateway + Lambda + DynamoDB + S3).
`X-Google-Access-Token` を含む)。stage スロットリングに加え、`/classrooms/join` と
`/classrooms/lookup` はルート個別に厳しめのスロットリングを設定
- **Lambda (Node.js 22)**: 単一ハンドラー (`lambda/handler.ts`) に全ビジネスロジック
- **DynamoDB (4 テーブル)**:
- **DynamoDB (8 テーブル)**:
- `Classrooms{suffix}` — GSI `joinCode-index` / `teacherSub-index`
- `ClassroomMemberships{suffix}` — GSI `sessionToken-index`
- `ClassroomSubmissions{suffix}` — GSI `classroomId-memberId-index`
- `ClassroomKickRequests{suffix}` — GSI `classroomId-seatNumber-index`(退室依頼 #692)
- すべて TTL `ttl`・**RemovalPolicy: DESTROY**
- `ClassroomGroups{suffix}` — GSI `teacherSub-index`(クラス=学級、長期 TTL 400日)
- `SharedAssignments{suffix}` — GSI `status-createdAt-index` / `authorSub-createdAt-index` / `passcode-index`(みんなの課題 #1066。**TTL なし・prod RETAIN + PITR**)
- `SharedAssignmentReports{suffix}` — 通報(TTL 90日)
- `ClassroomNotifications{suffix}` — お知らせ #1111(PK teacherSub / SK notificationId。**書き手は admin スタックのみ**・この Lambda は Query/UpdateItem だけ grant)
- 上記注記のないものは TTL `ttl`・**RemovalPolicy: DESTROY**
- **S3** `smalruby-classroom-submissions{suffix}`: 提出ファイル (project.sb3, thumbnail.png,
screenshots)。lifecycle 期限 = `CLASSROOM_TTL_DAYS`
- **認証**: Google / Microsoft ID Token(`iss` 自動判別 + JWKS 検証。bug-report と同型)。
Expand Down
7 changes: 5 additions & 2 deletions docs/admin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

### セクション(3 ドメイン)

1. **みんなの課題**(S3 #1083): 通報キュー(多い順)/ 全投稿一覧 / 詳細(ページ・画像・クレジット)/ 非公開⇄再公開(2 段階確認・audit)
2. **クラス・課題**(S4 #1084 + 俯瞰ダッシュボード): 3 タブ構成 — ①**俯瞰ダッシュボード**(作成の推移・内容の充実度・テーマ傾向 + みんなの課題の**有益候補**を見える化。有益候補を先生に促す仕組みは別 EPIC #1106)②**クラス検索**(参加コード完全一致・名前部分一致 / 詳細 / アーカイブ切替)③**期限切れ復元**(ddb-archive スナップショットを削除時期・先生でファセット絞り込み → dry-run → 実行。EPIC #1049 の CLI の UI 後継)
1. **みんなの課題**(S3 #1083): 通報キュー(多い順)/ 全投稿一覧 / **限定公開タブ**(推薦候補の母集団・#1110)/ 詳細(ページ・画像・クレジット)/ 非公開⇄再公開(2 段階確認・audit)/ **推薦する・推薦を取り消す**(#1110。2 段階確認・audit。推薦すると作成した先生のお知らせセンター #1111 に通知が届き、限定公開を全体公開に広げる動線につながる。取り消しは通知なし
2. **クラス・課題**(S4 #1084 + 俯瞰ダッシュボード): 3 タブ構成 — ①**俯瞰ダッシュボード**(作成の推移・内容の充実度・テーマ傾向 + みんなの課題の**有益候補**を見える化。候補行には**推奨済みバッジ**)②**クラス検索**(参加コード完全一致・名前部分一致 / 詳細 / アーカイブ切替)③**期限切れ復元**(ddb-archive スナップショットを削除時期・先生でファセット絞り込み → dry-run → 実行。EPIC #1049 の CLI の UI 後継)。クラス詳細には**先生へのお知らせ送信**(EPIC #1111)があり、タイトル + 本文を二段階確認で `POST /admin/notifications` へ送ると、その課題を作成した先生のクラス管理画面右上「お知らせ」🔔 に届く(宛先 teacherSub はサーバー側で classroomId から解決し SPA には出さない。書き込み先 `ClassroomNotifications` テーブルは名前規約 import + write-only grant で、この面が単一の書き手)。さらに**みんなの課題への共有推奨**(EPIC #1106)があり、二段階確認で `POST /admin/classrooms/{id}/recommend-sharing` を実行すると先生へお知らせ(`share_suggestion`)が届き、先生の課題詳細に「この課題、みんなの課題に共有しませんか?」バナーが出る(公開は CC BY 同意を伴う先生本人の共有フローのみ — 代理公開はしない。取り消しは通知なし・audit のみ
3. **バグ報告**(S5 #1085 + 対応機能追加): 既存バグ報告の一覧・状態フィルタ・詳細・添付 presigned DL に加え、**状態の変更と進捗コメント(開発者からの返信)**を既存 bug-report admin API の PATCH で行える(2 段階確認・終端ステータスは自動削除 TTL の警告つき。返信は報告者の「私の不具合報告」に表示され、非表示にしていた報告も再表示される — サーバー側の既存挙動)。詳細には**状態に応じた Claude 連携プロンプト**(`/bug-report` スキル向け・受付→Issue 化 / 改修 / 解決返信 / 再開)が表示され、ワンクリックでコピーして Claude Code に貼り付けられる

## 認証・認可モデル(要点)
Expand Down Expand Up @@ -90,3 +90,6 @@ cd tools/playwright-verify && node verify-admin.mjs
| `screenshots/0103-classrooms.png` | クラス・課題: 検索一覧 |
| `screenshots/0104-restore-plan.png` | 期限切れ復元: dry-run プラン |
| `screenshots/0105-bug-reports.png` | バグ報告: 閲覧一覧 |
| `screenshots/0106-classroom-notify.png` | クラス詳細: 先生へのお知らせ送信(EPIC #1111) |
| `screenshots/0107-shared-recommend.png` | みんなの課題: 限定公開の詳細と推薦の確認(EPIC #1110) |
| `screenshots/0108-recommend-sharing.png` | クラス詳細: 共有推奨の確認(EPIC #1106) |
Binary file added docs/admin/screenshots/0106-classroom-notify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/admin/screenshots/0108-recommend-sharing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions docs/assignment-sharing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@

![取り込み完了](screenshots/0104-imported.png)

## 限定公開と運営の推薦(#1109 / #1110)

共有時に**公開範囲**を選べる: `public`(みんなの課題カタログ)/ `limited`(**合言葉限定公開** — 参加コード同型の合言葉を知っている人だけが取り込める内輪公開。CC BY 同意・属性・著者名は任意)。

```text
限定公開(合言葉・内輪)→ Admin が把握(限定公開タブ)→ 推薦 → 先生が全体公開に広げる
```

- **推薦(Admin)**: 運営が Admin SPA から「推薦する」と、`recommendedAt`/`recommendedBy` が付き、**作成した先生へお知らせセンター(#1111・`link.kind='shared-mine'`)で通知**が届く。取り消しは通知なし(audit のみ)
- **推薦印(先生)**: 「自分の投稿」のカードに「推薦」バッジ(限定公開バッジと並ぶ)。詳細には推薦済みの注記
- **全体公開への発展(先生)**: 自分の限定公開の詳細に「**みんなの課題に公開する**」。共有フォームが**編集モード**(既存メタデータが初期値)で開き、全体公開に必要な属性・著者名・**CC BY 4.0 同意(改めて必須)**を揃えて送信すると `PATCH visibility: 'public'` でカタログに載る
- 推薦通知をクリックすると「自分の投稿」へ直接ジャンプする(クラス未選択ならアクティブな先頭クラスを開いてから表示)

### 自分の投稿の推薦バッジ

![自分の投稿と推薦バッジ](screenshots/0105-mine-recommended.png)

### 全体公開フォーム(編集モード)

![全体公開フォーム](screenshots/0106-broaden-form.png)

## 主要ファイル

### バックエンド(infra/smalruby-classroom)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions docs/classroom-notification-center/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# クラス管理 お知らせ通知センター & 課題共有パイプライン(トピック集約)

> **🆕 Smalruby 独自** — topic ブランチ `topic/classroom-notification-center` で実装した 3 つの EPIC を横断的にまとめた紹介ページ。各機能の一次ドキュメントは下記のとおり別にあり、ここは**全体像とスクリーンショットの集約**です。

運営(Admin)が良い課題を見つけ → 作成した先生に届け → 先生が「みんなの課題」へ公開する、という一連の流れを支える 3 機能:

| EPIC | 機能 | 一次ドキュメント |
|------|------|-----------------|
| #1111 | お知らせ通知センター(通知の共通土台) | [`docs/classroom/`](../classroom/ui-ux.md) ・ [`docs/admin/`](../admin/README.md) |
| #1110 | Admin による課題推薦(限定公開 → みんなの課題への発展) | [`docs/assignment-sharing/`](../assignment-sharing/README.md) ・ [`docs/admin/`](../admin/README.md) |
| #1106 | 有益な課題を先生に「みんなの課題へ共有」促す | [`docs/classroom/`](../classroom/ui-ux.md) ・ [`docs/admin/`](../admin/README.md) |

## パイプライン

```
限定公開(合言葉・内輪/先生)
→ 運営が把握(限定公開タブ #1110 / 有益候補ダッシュボード #1106)
→ 推薦・推奨(お知らせ #1111 が先生に届く)
→ 全体公開(CC BY 4.0 同意して先生本人が公開)
```

- 公開は著作権(CC BY 4.0)の都合で**必ず先生本人**が行う(運営は代理公開しない)
- 2 つの「気づき」経路(#1110 の推薦 / #1106 の共有推奨)は、どちらも #1111 のお知らせ🔔 に集約され、クリックで該当画面へジャンプする

## スクリーンショット

| ファイル | 内容 |
|---------|------|
| `screenshots/0101-notification-bell.png` | #1111 タイトルバーの 🔔 + 未読バッジ |
| `screenshots/0102-notification-panel.png` | #1111 お知らせ一覧パネル |
| `screenshots/0103-admin-notify-form.png` | #1111 管理 SPA の先生へのお知らせ送信フォーム |
| `screenshots/0201-mine-recommended-badges.png` | #1110 先生「自分の投稿」の 限定公開 / 推薦 バッジ |
| `screenshots/0202-broaden-form.png` | #1110 全体公開フォーム(編集モード) |
| `screenshots/0203-admin-shared-recommend.png` | #1110 管理 SPA 限定公開タブ + 推薦の確認 |
| `screenshots/0301-share-suggestion-banner.png` | #1106 課題詳細の共有促しバナー |
| `screenshots/0302-board-share-suggested.png` | #1106 課題一覧(ボード)の「共有おすすめ」マーク |
| `screenshots/0303-admin-recommend-sharing.png` | #1106 管理 SPA クラス詳細の共有推奨の確認 |
| `screenshots/0304-admin-overview-candidates.png` | #1106 俯瞰ダッシュボードの有益候補 |

## 機能紹介プレゼン(HTML)

人間が機能を把握するための HTML スライドは **git 管理外の `notes/topic-classroom-notification-center/index.html`** にあります(上記スクリーンショットを相対パスで参照。ブラウザで直接開けます)。
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/classroom/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ sequenceDiagram
| **DynamoDB** | `ClassroomGroups-{stage}` | クラス(学級)情報(Streams: OLD_IMAGE) |
| **DynamoDB** | `SharedAssignments-{stage}` | みんなの課題(TTL なし・prod RETAIN + PITR) |
| **DynamoDB** | `SharedAssignmentReports-{stage}` | みんなの課題の通報(TTL 90日) |
| **DynamoDB** | `ClassroomNotifications-{stage}` | お知らせ(EPIC #1111。TTL は書き手の admin スタックが付与・既定 180 日) |
| **S3** | `smalruby-shared-assignments-{stage}` | 共有課題のスナップショット(lifecycle なし = 永続・prod RETAIN) |
| **S3** | `smalruby-classroom-submissions-{stage}` | 提出ファイル (.sb3, サムネイル, スクリーンショット) + `ddb-archive/` スナップショット。lifecycle = `ARCHIVE_RETENTION_DAYS`(既定 365 日) |
| **Route53** | A レコード | カスタムドメイン |
Expand Down Expand Up @@ -187,6 +188,8 @@ sequenceDiagram
| `PATCH` | `/classroom-groups/{groupId}/topics` | トピックの add / remove / rename(rename・remove は課題へ一括追従) |
| `POST` | `/classrooms/{id}/duplicate` | クラス(授業)の複製。課題コンテンツの S3 オブジェクトもコピー。`groupId` / `className` / `assignmentName` を上書き可。メンバー・提出は複製しない |
| `POST` | `/classrooms/{id}/evaluate` | AI 評価支援。静的解析結果(シグナル + 擬似コード)を Anthropic API にリレーし、`mode: grade` は S/A/B/C 案 + 根拠 + needsReview、`mode: comment` は生徒向けポジティブコメント下書きを返す。1リクエスト最大10提出(API GW の30秒制限対策、クライアントがチャンク分割)。先生ごとにレート制限(既定 60回/時) |
| `GET` | `/notifications` | お知らせ一覧(EPIC #1111)。自分宛て(teacherSub)の直近 50 件 + `unreadCount` を返す。書き込みは admin スタックのみ(単一ライター) |
| `POST` | `/notifications/mark-read` | お知らせ既読化。`{notificationIds?}` — 省略時は一覧窓(直近 50 件)の未読を全既読化(パネルを開いたらバッジが消える UX) |

### みんなの課題 (共有課題ライブラリ・先生 ID Token 認証)

Expand All @@ -205,6 +208,7 @@ sequenceDiagram
| `POST` | `/shared-assignments/{id}/report` | 通報(理由必須・20件/日制限。reporterSub は内部保持のみ) |

- **公開範囲(#1109)**: 項目は `visibility`(`public`/`limited`)を持つ。#1109 以前の項目は属性を持たず `public` とみなす(後方互換)。`limited` は `passcode`(合言葉)を持ち、公開カタログには出ない。「限定公開(合言葉・内輪)→ Admin が把握 → 推薦 → 全体公開」パイプラインの土台
- **Admin 推薦(#1110)**: 項目は `recommendedAt` / `recommendedBy`(admin email)を持ちうる。書き込みは admin API(`POST/DELETE /admin/shared-assignments/{id}/recommend`)のみ。先生側 API には boolean の `recommended` だけを投影(`recommendedBy` は内部情報)。推薦時は著者へお知らせ(#1111・type `shared_recommended`・`link.kind='shared-mine'`)が飛ぶ
- データ: `SharedAssignments{suffix}`(**TTL なし・prod は RETAIN + PITR**。GSI: `status-createdAt-index` / `authorSub-createdAt-index` / `passcode-index`(合言葉ルックアップ・#1109))、`SharedAssignmentReports{suffix}`(TTL 90日)
- ファイル: 専用バケット `smalruby-shared-assignments{suffix}`(**lifecycle なし = 永続**、`shared/{sharedId}/` プレフィックス)。クラス側の保存期限と完全に分離
- 共有/取り込みの実体は既存 duplicate と同じ S3 サーバー側コピー(クロスバケット)
Expand Down Expand Up @@ -244,6 +248,8 @@ erDiagram
string googleClassroomCourseId "任意"
list coTeacherEmails "共同管理者の email 配列 (任意, 最大10)"
map assignment "課題コンテンツ (任意): {pages: [{text, imageKey?}], starterKey?, updatedAt}"
string recommendedForSharingAt "共有推奨 (#1106, 任意)。書き込みは admin API のみ。先生側 API には boolean recommendedForSharing を投影"
string recommendedForSharingBy "推奨した admin の email (内部用・先生側 API では返さない)"
string groupId "所属する組 (任意)"
string status "active / archived"
string createdAt "ISO8601"
Expand Down Expand Up @@ -313,6 +319,31 @@ erDiagram
- `listMembers` / `lookup takenSeats` は `FilterExpression: attribute_not_exists(kicked) OR kicked <> :true` で tombstone を除外
- `joinClassroom` の `ConditionExpression: attribute_not_exists(memberId) OR kicked = :true` で新生徒が kicked 行を上書き可能 (tombstone はその時点で消滅)

### ClassroomNotifications テーブル(お知らせ・EPIC #1111)

```mermaid
erDiagram
ClassroomNotifications {
string teacherSub PK "宛先の先生 (Google/Microsoft sub)"
string notificationId SK "createdAt ISO + '#' + UUID (時系列ソート)"
string type "admin_message など (リンク種別の意味付け)"
string title "最大100文字"
string body "最大1000文字"
map link "任意: {kind: 'classroom', classroomId} — クリック時のジャンプ先"
string readAt "既読日時 (未読は属性なし)"
string createdBy "送信した admin の email (内部用・API では返さない)"
string createdAt "ISO8601"
number ttl "Unix timestamp (既定180日)"
}
```

**GSI なし** — 宛先 (PK) への Query だけで受信箱になる。

- **単一ライター**: 書き込みは admin スタック(`POST /admin/notifications`、名前規約 import + write-only grant)のみ。classroom API は一覧と既読化だけを提供するので、エディタ側からお知らせを偽造できない
- 宛先の `teacherSub` は admin SPA に出さず、admin API が classroomId から解決する
- `link.kind` は whitelist(現在 `classroom` のみ)。エディタは未知の kind を無視する(前方互換)
- GUI は先生モーダルのタイトルバー 🔔 から一覧を開く。パネルを開いた時点で mark-read(全件)が走りバッジが消える。60 秒間隔でポーリング

### ClassroomSubmissions テーブル

```mermaid
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions docs/classroom/source-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ smalruby3-editor/
│ │ ├── containers/
│ │ │ ├── classroom-modal.jsx ← コンテナ(生徒/先生モードの振り分け)
│ │ │ ├── use-teacher-classroom.js ← 先生用フック統合(他フックを束ねる)
│ │ │ ├── use-teacher-notifications.js ← お知らせセンター (EPIC #1111)
│ │ │ ├── use-teacher-auth.js ← 認証フック(Google/Microsoft 共通)
│ │ │ ├── use-teacher-classrooms.js ← クラス CRUD + 自動リフレッシュ
│ │ │ ├── use-teacher-submissions.js ← 提出管理・一括ダウンロード
Expand Down Expand Up @@ -109,6 +110,8 @@ CDK スタック定義。以下のリソースを作成:
| `handleUpdateSubmission()` | 提出更新 (返却・コメント) |
| `handleSetAssignment()` | 課題コンテンツ設定 (ページ + スターター、Presigned URL 生成) |
| `handleGetAssignment()` | 課題コンテンツ取得 (生徒 Session Token / 先生 ID Token 両対応) |
| `handleListNotifications()` | お知らせ一覧 + 未読数 (EPIC #1111) |
| `handleMarkNotificationsRead()` | お知らせ既読化 (ids 省略で全既読) |
| `handleCreateGroup()` / `handleListGroups()` / `handleUpdateGroup()` | 組(グループ)の作成・一覧・更新/アーカイブ |
| `handleDuplicateClassroom()` | クラス複製(課題の S3 オブジェクトコピー含む) |
| `handleListGoogleCourses()` | Google Classroom コース一覧 |
Expand Down Expand Up @@ -180,6 +183,7 @@ GOOGLE_ID_TOKEN=eyJ... docker compose run --rm -w /app/infra/smalruby-classroom
| `teacher-login-phase.jsx` | ログイン画面(Google / Microsoft ボタン + カルーセル) |
| `teacher-sidebar.jsx` | サイドバー(クラス一覧ナビゲーション) |
| `teacher-google-courses-phase.jsx` | Google Classroom コースインポート画面 |
| `teacher-notifications.jsx` | お知らせセンター(🔔 + 未読バッジ + 一覧パネル、EPIC #1111) |

### `packages/scratch-gui/src/lib/classroom-api.js`

Expand Down
Loading
Loading