Skip to content

feat(admin,classroom,gui): Admin による課題推薦 — 限定公開→みんなの課題への発展 (#1110)#1114

Merged
smalruby3-editor-bot[bot] merged 5 commits into
topic/classroom-notification-centerfrom
feature/shared-recommendation-1110
Jul 25, 2026
Merged

feat(admin,classroom,gui): Admin による課題推薦 — 限定公開→みんなの課題への発展 (#1110)#1114
smalruby3-editor-bot[bot] merged 5 commits into
topic/classroom-notification-centerfrom
feature/shared-recommendation-1110

Conversation

@smalruby3-editor-bot

Copy link
Copy Markdown

Summary

EPIC #1110 の実装。運営(Admin)が限定公開(合言葉・#1109)の課題を推薦し、みんなの課題(全体公開)へ育てるパイプラインを完成させる。#1111 のお知らせセンターを通知チャネルとして利用する(link.kind='shared-mine' を追加)。

限定公開(合言葉・内輪)→ Admin が把握(限定公開タブ)→ 推薦(+ お知らせ通知)→ 先生が全体公開に広げる

Changes Made

  • infra/smalruby-admin: POST/DELETE /admin/shared-assignments/{id}/recommend(audit 付き・冪等・推薦時のみ著者へ epic(classroom): クラス管理の右上「お知らせ」通知センター #1111 通知)、一覧の visibility フィルタ、admin 投影に visibility/recommended
  • infra/smalruby-classroom: 先生側投影(mapSharedSummary)に recommended(boolean のみ。recommendedBy は非公開)
  • packages/admin: 「限定公開」タブ、限定公開/推薦中バッジ、詳細の「推薦する/取り消す」(二段階確認)
  • packages/scratch-gui:
    • 「自分の投稿」カードに 限定公開/推薦 バッジ、詳細に推薦済み注記
    • みんなの課題に公開する」CTA → 共有フォームを編集モードで再利用(既存メタデータ初期値・CC BY 同意は改めて必須)→ PATCH visibility='public'
    • 推薦通知のジャンプ先 shared-mine(クラス未選択でも先頭クラスを開いて「自分の投稿」表示)
  • docs: assignment-sharing README(推薦セクション + スクショ 2 枚)、architecture、testing(data-testid)、admin README(+ スクショ 1 枚)
  • tools/playwright-verify: verify-shared-recommendation.mjs(スタブ式・stg 不要・12 チェック)

設計判断(各コミットメッセージに詳細)

  • D16 推薦印は「自分の投稿」一覧(共有項目は元 classroomId を持たないためクラスボード行への表示はスコープ外)
  • D17 発展フォームは新規でなく既存共有フォームの編集モード拡張(バリデーション・文言の二重管理回避)
  • D12 推薦対象は published 全般(主対象は限定公開)。unlisted は 404
  • D13 通知は推薦時のみ・冪等(再推薦で再通知しない)。取り消しは audit のみ

Test Coverage

  • admin infra: handler-shared-recommendation.test.ts 5 件(全 49 件パス・tsc クリーン)
  • admin SPA: +2 件(lint + 40 件パス)
  • scratch-gui: catalog +5 / form +1(22 件パス・対象ファイル lint クリーン)
  • headless Playwright(API スタブ): 12/12 — 通知ジャンプ → バッジ → 発展フォーム → PATCH payload 検証

残タスク

Related Issues

Refs #1110(前提: #1109 実装済み、通知基盤: #1111 = PR #1113

🤖 Generated with Claude Code

smalruby3-editor-bot Bot and others added 4 commits July 25, 2026 16:56
admin API に POST/DELETE /admin/shared-assignments/{id}/recommend を追加。
推薦時は recommendedAt/recommendedBy を記録し、著者の先生へお知らせ
センター (#1111) 経由で通知(link.kind='shared-mine')。取り消しは
静かに解除(audit のみ)。一覧に visibility フィルタを追加。
先生側 API (mapSharedSummary) には boolean の recommended だけを投影。

設計上の分岐点 (このコミットに立ち戻ればやり直せる):
- D11 推薦の保存先: SharedAssignments 項目に直接 recommendedAt/By を
  持たせた (admin は既に同テーブルのモデレーション書込 grant を保有)。
  代替案: 別テーブル (結合が増えるだけなので不採用)
- D12 対象: status='published' なら visibility を問わず推薦可 (EPIC の
  主対象は限定公開だが、公開項目の推薦印も後続で意味を持ちうる)。
  unlisted (取り下げ) は 404
- D13 通知: 推薦時のみ・冪等 (既推薦なら no-op で再通知しない)。
  通知の put は best-effort にせず失敗を運営に見せる (通知が主目的)
- D14 露出: 先生側には recommended (boolean) のみ。recommendedBy
  (admin email) は先生に出さない。admin にも passcode は出さない

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
みんなの課題ビューに「限定公開」タブ (visibility フィルタ) を追加し、
一覧行と詳細に 限定公開/推薦中 バッジを表示。詳細に「推薦する/
推薦を取り消す」を非公開化とは独立した二段階確認で追加。

設計上の分岐点:
- D15 推薦候補の見せ方: 専用タブ (限定公開) を追加。すべての投稿に
  フィルタ UI を足す案より、運営の定常動線 (限定公開を巡回→推薦) が
  1 クリックで出るタブを採用
- 推薦の確認文言に「先生にお知らせが届きます」を明記 (通知が飛ぶ
  操作であることを操作時点で意識させる)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
みんなの課題の「自分の投稿」カードに 限定公開/推薦 バッジを表示。
自分の限定公開の詳細に「みんなの課題に公開する」CTA を追加し、
共有フォームを編集モード (initialValues・classroomId なし) で再利用
して PATCH visibility='public' + CC BY 同意で全体公開に広げる。
推薦通知 (link.kind='shared-mine') のジャンプ先として「自分の投稿」
を直接開く handleOpenCatalogMine を追加。

設計上の分岐点 (このコミットに立ち戻ればやり直せる):
- D16 推薦印の場所: 「自分の投稿」一覧のカード (先生の共有課題の
  一覧=ボード) に表示。クラスの課題ボード行への表示は共有項目が
  元 classroomId を持たないため今回のスコープ外 (必要なら共有時に
  sourceClassroomId を保存する追加が要る)
- D17 発展フォーム: 新規フォームを作らず SharedAssignmentForm を
  編集モード対応に拡張して再利用 (バリデーション/文言が公開時と
  完全一致し、二重管理を避ける)。CC BY 同意は編集モードでも必須
- D18 ジャンプの文脈: カタログはボード内サブビューのため、クラス
  未選択時はアクティブな先頭クラスを開いてから表示 (専用フェーズの
  新設はナビ構造の変更が大きく不採用)

検証: jest 22件 + headless Playwright 12/12 (通知ジャンプ→バッジ→
発展フォーム→PATCH payload まで)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- assignment-sharing/README.md: 限定公開と運営の推薦セクション
  (パイプライン図・発展フロー・スクリーンショット 0105/0106)
- classroom/architecture.md: recommendedAt/By と admin ルートの説明
- classroom/testing.md: 新 data-testid 5 件
- admin/README.md: 限定公開タブ + 推薦操作 + スクリーンショット 0107
- tools/playwright-verify/README.md: verify-shared-recommendation.mjs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

レビュー (PR #1114) の指摘への対応:

- [Must] shared-mine 通知ジャンプ: クラス選択済みでも必ず
  handleSelectGroup でボードへ戻してからカタログを開く (課題詳細など
  別フェーズでは無反応になっていた)。クラスが 1 つも無い場合は
  黙殺せずエラー表示 (i18n 追加)
- [Must] broadenTarget/broadenDone をカタログの開閉・タブ切替で必ず
  リセット (古い公開フォーム/完了メッセージが再表示されるリーク)
- [Question] 推薦を limited のみに制限 (公開項目への推薦は通知文が
  意味を成さない)。推薦取り消しは公開に広がった後も可能なまま。
  D12 の決定をレビューを受けて改訂
- [Question+FYI] 通知→印付けの順に変更 + ConditionExpression で冪等を
  原子化 (印付け成功後の通知失敗が回復不能だった / 同時 POST の二重
  通知防止)。最悪ケースは通知の重複 (無害) に倒す
- [FYI] #1109 の潜在バグ修正: 限定公開→全体公開の PATCH で明示的な
  null クリア (コマ数・所属) が既存値へ巻き戻っていた (?? → undefined
  判定に統一)。回帰テスト追加
- [FYI] 境界テスト追加: 先生 PATCH が recommendedAt/By を無視する
  whitelist の pin、投影に recommendedBy が漏れない検証

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@smalruby3-editor-bot

Copy link
Copy Markdown
Author

敵対レビュー結果(自動レビュー + 対応済み)

diff 全体を正確性・セキュリティ・rules 準拠・整合性・テスト妥当性の 5 観点で敵対的に検証(全テストスイート実行 + tsc/eslint/prettier 確認済み)。

指摘と対応(コミット 5f10e06

分類 指摘 対応
[Must] shared-mine 通知ジャンプが課題詳細など board 以外のフェーズでは無反応(phase を戻していない。主動線の欠陥) クラス選択済みでも必ず handleSelectGroup でボードへ戻してから開く。クラス 0 件は黙殺せずエラー表示 ✅
[Must] broadenTarget/broadenDone がカタログ閉じ→再開後も残り、古い公開フォームが再表示 カタログ開閉・タブ切替で必ずリセット ✅
[Question] 印付け成功後に通知が失敗すると、冪等 no-op により再通知が永久に不可能(通知が本体なのに) 通知→印付けの順に変更。リトライで回復可能に(最悪ケース = 通知重複で無害) ✅
[Question] 公開項目にも推薦できるが通知文(全体公開の検討を促す)が意味を成さない 推薦を limited のみに制限(400)。取り消しは公開後も可能 ✅
[FYI] 推薦 Update に ConditionExpression が無く同時 POST で二重通知 attribute_not_exists(recommendedAt) で原子化 ✅
[FYI] #1109 の潜在バグ: 限定→公開 PATCH で null クリア(コマ数・所属)が既存値へ巻き戻る(本 PR で顕在化) ?? → undefined 判定に統一 + 回帰テスト ✅
[FYI] 先生 PATCH が recommended* を書けないことの pin テストなし 境界テスト 4 件追加(whitelist・投影に recommendedBy 非漏出 等) ✅

クリーンと確認された点(抜粋)

  • DynamoDB REMOVE ... SET ... 構文は正当。先生 PATCH の whitelist は構造的に recommended* を通さない
  • CC BY 同意はサーバー側でも強制。admin 応答に authorSub/passcode 非漏出(テスト検証済み)
  • 公開フォームの再マウント挙動は ternary の型切替で担保(key 不要)
  • ja/ja-Hira ペア一致、testid ドキュメント一致、audit 両 mutation、4xx パスへのログ追加なし

判定: 指摘対応後 MERGEABLE(stg デプロイは PR #1113 と同枠のフォローアップ)

@smalruby3-editor-bot
smalruby3-editor-bot Bot merged commit 938188b into topic/classroom-notification-center Jul 25, 2026
21 checks passed
@smalruby3-editor-bot
smalruby3-editor-bot Bot deleted the feature/shared-recommendation-1110 branch July 25, 2026 17:33
@smalruby3-editor-bot

Copy link
Copy Markdown
Author

stg デプロイ・検証完了(2026-07-25)

ClassroomStack-stg / AdminStack-stg をデプロイし、integration テスト(49 件パス・教師フロー含む)+ 実 API のスモークで 3 EPIC の通しを確認:

検証データはクリーンアップ済み(取り下げ + アーカイブ、stg TTL 1 日)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants