GROWI の InAppNotification にニュース配信・表示機能を追加する。外部の静的 JSON フィード(GitHub Pages)を GROWI 本体が cron で定期取得し、ローカル MongoDB にキャッシュした上で、InAppNotificationパネルおよび通知一覧ページにニュースとして表示する。
ニュースは既存の InAppNotification とは別モデル(NewsItem)として管理する。InAppNotification はユーザーアクション起因で関係者のみに配信されるのに対し、ニュースは全ユーザー(またはロール単位)に配信されるため、1件のニュースを全ユーザーで共有する設計が SaaS 規模で効率的である。UI ではクライアント側で両データを時系列マージして統合表示する。
Objective: As a GROWI 運営者, I want GROWI が外部フィードからニュースを自動取得する, so that 各 GROWI インスタンスに最新のニュースが配信される
externalId で重複排除)するnews:isDeliveryEnabled が false の場合), the News Cron Service shall フィード取得をスキップしエラーなく動作するgrowiVersionRegExps 条件が設定されている場合, the News Cron Service shall 現在の GROWI バージョンと照合し、一致しないアイテムを除外する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日)はニュース固有の要件。
externalId にユニークインデックスを持ち、重複登録を防止するpublishedAt にインデックスを持ち、公開日時順のソートを効率的に行うfetchedAt に TTL インデックス(90日)を持ち、古いニュースを自動削除するja_JP, en_US)を格納できるObjective: As a GROWI ユーザー, I want ニュースの既読/未読状態を管理したい, so that 新しいニュースを見逃さない
Note: NewsReadStatus を既存の InAppNotification モデルで代替できない理由:InAppNotification の status フィールドは per-user ドキュメントに依存しており、ニュースの既読状態を管理するには配信時に全ユーザー分のドキュメントを作成しなければならない(1000ユーザー × 10件 = 配信時点で強制的に 10,000件)。NewsReadStatus はユーザーが実際に既読アクションを起こした時のみ作成される(未読はレコードなし)。全員が全件読まない限り実際のレコード数は常に 10,000件を下回り、SaaS規模でのストレージ効率が高い。
NewsReadStatus レコードを作成するNewsReadStatus レコードが存在しない場合, the News API shall 該当ニュースを未読として扱うuserId + newsItemId の複合ユニークインデックスにより重複登録を防止するisRead: true/false を付与して返却するObjective: As a GROWI 運営者, I want ニュースの表示対象をロールで制御したい, so that 管理者向け情報を一般ユーザーに見せない
Note: 表示制御はニュース配信側(GROWI運営)がフィードJSON内の conditions.targetRoles で指定する。インスタンス側(GROWI管理者)による制御は設けない。
conditions.targetRoles が設定されている場合, the News API shall ユーザーのロール(admin/general)に基づいてフィルタリングするconditions.targetRoles が未設定の場合, the News API shall 全ユーザーにニュースを表示するObjective: As a GROWI ユーザー, I want 既存の InAppNotification UI でニュースを確認したい, so that 通知と同じ導線でニュースにアクセスできる
Note: NewsItem と InAppNotification は別モデルとして維持する。UI のみクライアント側で両データを時系列マージして表示する。
60vh)を設定した内部スクロールコンテナを使用し、dock/drawer モード(全面サイドバー)では外側の SimpleBar コンテナにスクロールを委ねることで二重スクロールコンテナを回避するemoji フィールドをタイトル前に表示する。emoji 未設定の場合は 📢 をフォールバックとして使用するObjective: As a GROWI ユーザー, I want 未読のニュース・通知を視覚的に区別したい, so that 未確認の項目をすぐに見分けられる
fw-bold)で表示するbg-primary)を表示するfw-normal)で表示するObjective: As a GROWI ユーザー, I want 未読ニュースの存在をバッジで把握したい, so that 新しいニュースがあることに気づける
Objective: As a GROWI ユーザー, I want ニュースを自分の言語で読みたい, so that 内容を正しく理解できる
ja_JP → en_US の順にフォールバックするja_JP, en_US, zh_CN, ko_KR, fr_FR の i18n ロケールファイルで提供する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 再起動は不要。
news:isDeliveryEnabled shall defaultValue: true を持ち、DB に値が無い場合は ON として扱われるenvVarName を設定しない)ため、優先順位は DB > defaultValue のみとなる/admin/app の UI からトグルを切り替えた場合, the GROWI shall Config コレクションの該当キーを更新し、再起動なしで設定値を反映するnews:isDeliveryEnabled が false の場合, the News Cron Service shall 次回 cron 発火時にフィード取得をスキップする(既に取得済みの DB キャッシュは維持する)news:isDeliveryEnabled が true に戻された場合, the News Cron Service shall 次回 cron 発火時に通常どおりフィード取得を再開する/admin トップの「サーバー側で設定されている環境変数一覧」には決して現れない