Просмотр исходного кода

docs(spec): add admin UI opt-out flag to news-inappnotification spec

Replace the env-driven `NEWS_FEED_URL` skip path (Requirement 1.6) with
the DB-managed `news:isDeliveryEnabled` flag, and add Requirement 9
covering the new admin UI toggle. Also document the related design
components: News Delivery Config (configManager registration) and
the App Settings UI extension.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Ryotaro Nagahara 2 недель назад
Родитель
Сommit
ac9f28e02f

+ 48 - 1
.kiro/specs/news-inappnotification/design.md

@@ -94,6 +94,7 @@ sequenceDiagram
   participant DB as MongoDB
   participant DB as MongoDB
 
 
   Cron->>Cron: getCronSchedule() = '0 0 * * *'(midnight 起動)
   Cron->>Cron: getCronSchedule() = '0 0 * * *'(midnight 起動)
+  Cron->>Cron: configManager.getConfig('news:isDeliveryEnabled') が false? → スキップ
   Cron->>Cron: NEWS_FEED_URL 未設定? → スキップ
   Cron->>Cron: NEWS_FEED_URL 未設定? → スキップ
   Cron->>Cron: randomSleep(0–5 時間)でリクエスト時刻を分散
   Cron->>Cron: randomSleep(0–5 時間)でリクエスト時刻を分散
   Cron->>Feed: HTTP GET feed.json
   Cron->>Feed: HTTP GET feed.json
@@ -170,11 +171,13 @@ sequenceDiagram
 
 
 | コンポーネント | 層 | Intent | 要件 | 主要依存 |
 | コンポーネント | 層 | Intent | 要件 | 主要依存 |
 |---|---|---|---|---|
 |---|---|---|---|---|
-| NewsCronService | Server / Cron | フィード定期取得・DB 同期 | 1.1–1.7 | CronService (P0), NewsService (P0) |
+| NewsCronService | Server / Cron | フィード定期取得・DB 同期 | 1.1–1.7, 9.5, 9.6 | CronService (P0), NewsService (P0), configManager (P0) |
 | NewsItem Model | Server / Data | ニュースアイテムの永続化 | 2.1–2.4 | MongoDB (P0) |
 | NewsItem Model | Server / Data | ニュースアイテムの永続化 | 2.1–2.4 | MongoDB (P0) |
 | NewsReadStatus Model | Server / Data | ユーザー既読状態の永続化 | 3.1–3.3 | MongoDB (P0) |
 | NewsReadStatus Model | Server / Data | ユーザー既読状態の永続化 | 3.1–3.3 | MongoDB (P0) |
 | NewsService | Server / Domain | ニュース一覧・既読管理のビジネスロジック | 3.4–3.5, 4.1–4.2 | NewsItem Model (P0), NewsReadStatus Model (P0) |
 | NewsService | Server / Domain | ニュース一覧・既読管理のビジネスロジック | 3.4–3.5, 4.1–4.2 | NewsItem Model (P0), NewsReadStatus Model (P0) |
 | News API | Server / API | HTTP エンドポイント提供 | 3.1–3.5, 4.1–4.2 | NewsService (P0) |
 | News API | Server / API | HTTP エンドポイント提供 | 3.1–3.5, 4.1–4.2 | NewsService (P0) |
+| News Delivery Config | Server / Config | 配信フラグ `news:isDeliveryEnabled` の登録(DB 主体、defaultValue: true) | 9.1, 9.2 | configManager (P0) |
+| App Settings UI(拡張) | Client / Admin | `/admin/app` UI から配信フラグを切り替える | 9.3, 9.4 | News Delivery Config (P0), 既存 `app-settings` API (P0) |
 
 
 ---
 ---
 
 
@@ -187,6 +190,7 @@ sequenceDiagram
 
 
 **Responsibilities & Constraints**
 **Responsibilities & Constraints**
 - 毎日 0 時に発火し、ランダムスリープで実取得時刻を 0–5 時に分散させる(cron 起動 `'0 0 * * *'` + `randomSleep(0–5h)`)
 - 毎日 0 時に発火し、ランダムスリープで実取得時刻を 0–5 時に分散させる(cron 起動 `'0 0 * * *'` + `randomSleep(0–5h)`)
+- **配信フラグ判定**:cron 発火ごとに `configManager.getConfig('news:isDeliveryEnabled')` を読み、`false` ならフィード取得をスキップ(再起動不要、次回 tick から即時反映)
 - `NEWS_FEED_URL` 未設定時はスキップ(エラーなし)
 - `NEWS_FEED_URL` 未設定時はスキップ(エラーなし)
 - 取得失敗時は既存 DB データを維持
 - 取得失敗時は既存 DB データを維持
 - `growiVersionRegExps` の照合はここで実施(DB には合致アイテムのみ保存)
 - `growiVersionRegExps` の照合はここで実施(DB には合致アイテムのみ保存)
@@ -391,6 +395,49 @@ GROWI の scope 階層は以下の意味論で運用する:
 
 
 ---
 ---
 
 
+#### News Delivery Config
+
+| Field | Detail |
+|---|---|
+| Intent | `news:isDeliveryEnabled` を configManager に登録し、cron/API/UI から共通で参照できるようにする |
+| Requirements | 9.1, 9.2 |
+
+**Responsibilities & Constraints**
+- `apps/app/src/server/service/config-manager/config-definition.ts` に CONFIG_KEYS と `defineConfig` の 2 箇所を追加
+- 既存先例 `OPENTELEMETRY_ENABLED`(`otel:enabled`)と完全に同形:`envVarName: 'NEWS_DELIVERY_ENABLED'` + `defaultValue: true`
+- `defaultValue: true` をコードに内蔵 → DB に値が無い状態で全顧客が ON
+- 値の優先順は configManager の既存仕様(DB > env > defaultValue)に従う
+
+**Dependencies**
+- Inbound: NewsCronService, App Settings UI
+- Outbound: configManager(既存)
+
+**Implementation Notes**
+- 通常運用では env を設定しないため `/admin` 環境変数一覧に現れない(DB 主体運用)
+- 開発時の override 用途で `.env.development.local` 等に `NEWS_DELIVERY_ENABLED` を書いた場合のみ env 値が効く
+- 設定変更時は configManager の `updateConfigs` がメモリキャッシュ更新と pubsub 通知(multi-pod 反映)を行う
+
+---
+
+#### App Settings UI(拡張)
+
+| Field | Detail |
+|---|---|
+| Intent | `/admin/app` 画面に「ニュース配信」ON/OFF トグルを追加する |
+| Requirements | 9.3, 9.4 |
+
+**Responsibilities & Constraints**
+- 既存 `app-settings` 画面・API(`PUT /apiv3/app-setting`)に項目を追加するパターンを踏襲
+- 認可:`accessTokenParser([SCOPE.WRITE.ADMIN.APP])` + `adminRequired` で admin のみに制限
+- トグル値の永続化先:`configManager.updateConfigs({ 'news:isDeliveryEnabled': boolean })`
+- UI 文言は i18n 対応(`ja_JP`, `en_US`, `zh_CN`, `ko_KR`, `fr_FR`)
+
+**Dependencies**
+- Inbound: 管理画面(admin user)
+- Outbound: News Delivery Config(configManager 経由)
+
+---
+
 ### クライアントサイド
 ### クライアントサイド
 
 
 | コンポーネント | 層 | Intent | 要件 | 主要依存 |
 | コンポーネント | 層 | Intent | 要件 | 主要依存 |

+ 17 - 1
.kiro/specs/news-inappnotification/requirements.md

@@ -19,7 +19,7 @@ GROWI の InAppNotification にニュース配信・表示機能を追加する
 3. When フィードに含まれなくなったニュースアイテムがある場合, the News Cron Service shall 該当アイテムをローカル DB から削除する
 3. When フィードに含まれなくなったニュースアイテムがある場合, the News Cron Service shall 該当アイテムをローカル DB から削除する
 4. When 複数の GROWI インスタンスが同時に取得を試みる場合, the News Cron Service shall ランダムスリープにより配信元へのリクエストを時間分散する
 4. When 複数の GROWI インスタンスが同時に取得を試みる場合, the News Cron Service shall ランダムスリープにより配信元へのリクエストを時間分散する
 5. If フィードの取得に失敗した場合, then the News Cron Service shall エラーをログに記録し、既存のキャッシュデータを維持する
 5. If フィードの取得に失敗した場合, then the News Cron Service shall エラーをログに記録し、既存のキャッシュデータを維持する
-6. Where `NEWS_FEED_URL` が未設定または空の場合, the News Cron Service shall フィード取得をスキップしエラーなく動作する
+6. Where ニュース配信が無効化されている場合(`news:isDeliveryEnabled` が `false` の場合), the News Cron Service shall フィード取得をスキップしエラーなく動作する
 7. When ニュースアイテムに `growiVersionRegExps` 条件が設定されている場合, the News Cron Service shall 現在の GROWI バージョンと照合し、一致しないアイテムを除外する
 7. When ニュースアイテムに `growiVersionRegExps` 条件が設定されている場合, the News Cron Service shall 現在の GROWI バージョンと照合し、一致しないアイテムを除外する
 
 
 ### Requirement 2: ニュースアイテムのローカルキャッシュ
 ### Requirement 2: ニュースアイテムのローカルキャッシュ
@@ -106,3 +106,19 @@ GROWI の InAppNotification にニュース配信・表示機能を追加する
 2. If ブラウザの言語に対応するテキストが存在しない場合, then the NewsItem コンポーネント shall `ja_JP` → `en_US` の順にフォールバックする
 2. If ブラウザの言語に対応するテキストが存在しない場合, then the NewsItem コンポーネント shall `ja_JP` → `en_US` の順にフォールバックする
 3. The UI ラベル(「ニュース」「ニュースはありません。」等)shall `ja_JP`, `en_US`, `zh_CN`, `ko_KR`, `fr_FR` の i18n ロケールファイルで提供する
 3. The UI ラベル(「ニュース」「ニュースはありません。」等)shall `ja_JP`, `en_US`, `zh_CN`, `ko_KR`, `fr_FR` の i18n ロケールファイルで提供する
 4. The フィルタボタン用ラベル(「通知」「お知らせ」)shall 全対応言語のロケールファイルに追加する
 4. The フィルタボタン用ラベル(「通知」「お知らせ」)shall 全対応言語のロケールファイルに追加する
+
+### Requirement 9: ニュース配信のオンオフ切替
+
+**Objective:** As a GROWI 管理者, I want ニュース配信のオンオフを管理画面から切り替えたい, so that 環境変数の編集や再起動なしにインスタンス単位で配信を停止/再開できる
+
+**Note:** 配信フラグは DB(`Config` コレクション)で管理し、admin が `/admin/app` UI から操作する。`OPENTELEMETRY_ENABLED` などの既存パターン(configManager + `defineConfig` + `envVarName` + `defaultValue`)を踏襲する。`defaultValue: true` をコードに内蔵することで、新規・既存インスタンスとも DB に値が無い状態で**デフォルト ON**が成立する。env レイヤーは開発時の override(例:`.env.development.local`)にのみ用い、本番運用での設定変更は UI 経由で行う。pod 再起動は不要。
+
+#### Acceptance Criteria
+
+1. The configuration `news:isDeliveryEnabled` shall `defaultValue: true` を持ち、DB/env のいずれにも値が無い場合は ON として扱われる
+2. The 設定値 shall configManager 経由で読み出され、優先順位は **DB > env > defaultValue**(既存仕様)に従う
+3. When 管理者が `/admin/app` の UI からトグルを切り替えた場合, the GROWI shall `Config` コレクションの該当キーを更新し、再起動なしで設定値を反映する
+4. The 切替操作 shall admin 権限を持つユーザーのみに許可される
+5. When `news:isDeliveryEnabled` が `false` の場合, the News Cron Service shall 次回 cron 発火時にフィード取得をスキップする(既に取得済みの DB キャッシュは維持する)
+6. When `news:isDeliveryEnabled` が `true` に戻された場合, the News Cron Service shall 次回 cron 発火時に通常どおりフィード取得を再開する
+7. The 設定値 shall env 変数(`NEWS_DELIVERY_ENABLED`)が明示的に設定されていない通常運用では `/admin` トップの「サーバー側で設定されている環境変数一覧」に現れない(DB 主体運用のため、env を設定する必要がない)