requirements.md 13 KB

Requirements Document

Introduction

GROWI の InAppNotification にニュース配信・表示機能を追加する。外部の静的 JSON フィード(GitHub Pages)を GROWI 本体が cron で定期取得し、ローカル MongoDB にキャッシュした上で、InAppNotificationパネルおよび通知一覧ページにニュースとして表示する。

ニュースは既存の InAppNotification とは別モデル(NewsItem)として管理する。InAppNotification はユーザーアクション起因で関係者のみに配信されるのに対し、ニュースは全ユーザー(またはロール単位)に配信されるため、1件のニュースを全ユーザーで共有する設計が SaaS 規模で効率的である。UI ではクライアント側で両データを時系列マージして統合表示する。

Requirements

Requirement 1: ニュースフィードの定期取得

Objective: As a GROWI 運営者, I want GROWI が外部フィードからニュースを自動取得する, so that 各 GROWI インスタンスに最新のニュースが配信される

Acceptance Criteria

  1. When cron スケジュールの実行時刻に達した場合, the News Cron Service shall コードに内蔵された配信元 URL から JSON フィードを HTTP GET で取得する
  2. When フィードの取得に成功した場合, the News Cron Service shall 取得したニュースアイテムをローカル MongoDB に upsert(externalId で重複排除)する
  3. When フィードに含まれなくなったニュースアイテムがある場合, the News Cron Service shall 該当アイテムをローカル DB から削除する
  4. When 複数の GROWI インスタンスが同時に取得を試みる場合, the News Cron Service shall ランダムスリープにより配信元へのリクエストを時間分散する
  5. If フィードの取得に失敗した場合, then the News Cron Service shall エラーをログに記録し、既存のキャッシュデータを維持する
  6. Where ニュース配信が無効化されている場合(news:isDeliveryEnabledfalse の場合), the News Cron Service shall フィード取得をスキップしエラーなく動作する
  7. When ニュースアイテムに growiVersionRegExps 条件が設定されている場合, the News Cron Service shall 現在の GROWI バージョンと照合し、一致しないアイテムを除外する

Requirement 2: ニュースアイテムのローカルキャッシュ

Objective: As a GROWI システム, I want 取得したニュースをローカル DB にキャッシュする, so that フィード配信元に障害が起きてもニュースを表示できる

Note: NewsItem を既存の InAppNotification モデルで代替できない理由:①外部フィード由来コンテンツの重複排除に必要な externalId(ユニークインデックス)が InAppNotification に存在しない。②InAppNotification は per-user ドキュメント設計のため、ニュースに適用すると配信時点で全ユーザー分のドキュメントを強制生成する必要がある(例: 1000ユーザー × 10件 = 10,000件、さらに snapshot にニュース本文がユーザー数分コピーされる)。NewsItem は全ユーザーで1件を共有するため、SaaS規模で効率的である。③TTL管理(90日)はニュース固有の要件。

Acceptance Criteria

  1. The NewsItem モデル shall externalId にユニークインデックスを持ち、重複登録を防止する
  2. The NewsItem モデル shall publishedAt にインデックスを持ち、公開日時順のソートを効率的に行う
  3. The NewsItem モデル shall fetchedAt に TTL インデックス(90日)を持ち、古いニュースを自動削除する
  4. The NewsItem モデル shall 多言語対応のタイトル・本文(ja_JP, en_US)を格納できる

Requirement 3: 既読/未読管理

Objective: As a GROWI ユーザー, I want ニュースの既読/未読状態を管理したい, so that 新しいニュースを見逃さない

Note: NewsReadStatus を既存の InAppNotification モデルで代替できない理由:InAppNotification の status フィールドは per-user ドキュメントに依存しており、ニュースの既読状態を管理するには配信時に全ユーザー分のドキュメントを作成しなければならない(1000ユーザー × 10件 = 配信時点で強制的に 10,000件)。NewsReadStatus はユーザーが実際に既読アクションを起こした時のみ作成される(未読はレコードなし)。全員が全件読まない限り実際のレコード数は常に 10,000件を下回り、SaaS規模でのストレージ効率が高い。

Acceptance Criteria

  1. When ユーザーがニュースアイテムをクリックした場合, the News API shall 該当ユーザーとニュースアイテムの組み合わせで NewsReadStatus レコードを作成する
  2. While NewsReadStatus レコードが存在しない場合, the News API shall 該当ニュースを未読として扱う
  3. The NewsReadStatus モデル shall userId + newsItemId の複合ユニークインデックスにより重複登録を防止する
  4. When ニュース一覧を取得する場合, the News API shall 各ニュースアイテムに isRead: true/false を付与して返却する
  5. The News API shall ログインユーザーの未読ニュース数を返却するエンドポイントを提供する

Requirement 4: ロール別表示制御

Objective: As a GROWI 運営者, I want ニュースの表示対象をロールで制御したい, so that 管理者向け情報を一般ユーザーに見せない

Note: 表示制御はニュース配信側(GROWI運営)がフィードJSON内の conditions.targetRoles で指定する。インスタンス側(GROWI管理者)による制御は設けない。

Acceptance Criteria

  1. When ニュースアイテムに conditions.targetRoles が設定されている場合, the News API shall ユーザーのロール(admin/general)に基づいてフィルタリングする
  2. When ニュースアイテムに conditions.targetRoles が未設定の場合, the News API shall 全ユーザーにニュースを表示する

Requirement 5: InAppNotification UI 統合表示

Objective: As a GROWI ユーザー, I want 既存の InAppNotification UI でニュースを確認したい, so that 通知と同じ導線でニュースにアクセスできる

Note: NewsItem と InAppNotification は別モデルとして維持する。UI のみクライアント側で両データを時系列マージして表示する。

Acceptance Criteria

  1. The InAppNotificationパネル shall 通知とニュースを公開日時/作成日時の降順で混合した1つのリストとして表示する
  2. The InAppNotificationパネル shall 上部にフィルタボタン(「すべて」「通知」「お知らせ」)を配置し、デフォルトは「すべて」とする。「お知らせ」選択時はニュースのみ、「通知」選択時はニュース以外のすべての通知を表示する
  3. The InAppNotificationパネル shall 既存の「未読のみ」トグルスイッチを維持し、種別フィルタと組み合わせた2重フィルタリングを提供する。種別フィルタ(すべて/通知/お知らせ)で表示対象を絞り込んだ上で、トグルON時は未読アイテムのみをさらに絞り込む
  4. The InAppNotificationパネル shall リスト領域のスクロールを提供し、末端に達した場合は次のページを自動で読み込む無限スクロールとする。スクロールの実現方法はサイドバーモードに依存する:collapsed モード(ホバーパネル)では最大高さ(60vh)を設定した内部スクロールコンテナを使用し、dock/drawer モード(全面サイドバー)では外側の SimpleBar コンテナにスクロールを委ねることで二重スクロールコンテナを回避する
  5. The InAppNotificationパネル shall ニュースアイテムの emoji フィールドをタイトル前に表示する。emoji 未設定の場合は 📢 をフォールバックとして使用する
  6. When ユーザーがニュースアイテムをクリックした場合, the InAppNotification UI shall ニュースの詳細 URL を新しいタブで開く
  7. When ユーザーがニュースアイテムをクリックした場合, the InAppNotification UI shall 該当ニュースを既読としてマークし、未読インジケータを更新する

Requirement 6: 既読/未読の視覚表示

Objective: As a GROWI ユーザー, I want 未読のニュース・通知を視覚的に区別したい, so that 未確認の項目をすぐに見分けられる

Acceptance Criteria

  1. The 未読アイテム shall タイトルを太字(fw-bold)で表示する
  2. The 未読アイテム shall 左端に青色の丸ドット(8px, bg-primary)を表示する
  3. The 既読アイテム shall タイトルを通常ウェイト(fw-normal)で表示する
  4. The 既読アイテム shall ドットと同じ幅の透明スペーサーを配置し、インデントを統一する

Requirement 7: 未読バッジ表示

Objective: As a GROWI ユーザー, I want 未読ニュースの存在をバッジで把握したい, so that 新しいニュースがあることに気づける

Acceptance Criteria

  1. The サイドバー通知アイコン shall 通知の未読数とニュースの未読数を合算してバッジに表示する
  2. When 全てのニュースが既読の場合, the バッジ shall ニュース分のカウントを含めない

Requirement 8: 多言語対応

Objective: As a GROWI ユーザー, I want ニュースを自分の言語で読みたい, so that 内容を正しく理解できる

Acceptance Criteria

  1. When ニュースアイテムに複数言語のテキストが含まれる場合, the NewsItem コンポーネント shall ブラウザの言語設定に応じたテキストを表示する
  2. If ブラウザの言語に対応するテキストが存在しない場合, then the NewsItem コンポーネント shall ja_JPen_US の順にフォールバックする
  3. The UI ラベル(「ニュース」「ニュースはありません。」等)shall ja_JP, en_US, zh_CN, ko_KR, fr_FR の i18n ロケールファイルで提供する
  4. The フィルタボタン用ラベル(「通知」「お知らせ」)shall 全対応言語のロケールファイルに追加する

Requirement 9: ニュース配信のオンオフ切替

Objective: As a GROWI 管理者, I want ニュース配信のオンオフを管理画面から切り替えたい, so that 環境変数の編集や再起動なしにインスタンス単位で配信を停止/再開できる

Note: 配信フラグは DB(Config コレクション)で管理し、admin が /admin/app UI から操作する。configManager + defineConfig + defaultValue の既存パターンを踏襲するが、env からの上書き経路は意図的に持たないenvVarName を設定しない)。これにより「インフラ側の env 注入」を不要にし、ニュース配信の意思は DB のみで表現される。defaultValue: true をコードに内蔵することで、新規・既存インスタンスとも DB に値が無い状態でデフォルト ONが成立する。配信元 URL もコードにハードコードされており、ユーザー(admin 含む)・運用者ともに変更できない。pod 再起動は不要。

Acceptance Criteria

  1. The configuration news:isDeliveryEnabled shall defaultValue: true を持ち、DB に値が無い場合は ON として扱われる
  2. The 設定値 shall configManager 経由で読み出される。env からの上書きは意図的にサポートしない(envVarName を設定しない)ため、優先順位は DB > defaultValue のみとなる
  3. When 管理者が /admin/app の UI からトグルを切り替えた場合, the GROWI shall Config コレクションの該当キーを更新し、再起動なしで設定値を反映する
  4. The 切替操作 shall admin 権限を持つユーザーのみに許可される
  5. When news:isDeliveryEnabledfalse の場合, the News Cron Service shall 次回 cron 発火時にフィード取得をスキップする(既に取得済みの DB キャッシュは維持する)
  6. When news:isDeliveryEnabledtrue に戻された場合, the News Cron Service shall 次回 cron 発火時に通常どおりフィード取得を再開する
  7. The 設定値 shall 環境変数として暴露されないため、/admin トップの「サーバー側で設定されている環境変数一覧」には決して現れない