Fincs

横断/運用基盤 / 通知基盤

横断/運用基盤 / 通知基盤

本ページは 2 段構成。上段が biz/CS 向け(ユーザー提示可)、下段(## 🔧 実装詳細 以降)が dev 向け。biz/CS がユーザーへ提示・転用してよいのは上段のみ。

概要

fincs サービスのプッシュ通知配信・未読バッジ集計の基盤レイヤ。Web ブラウザ・iOS PWA・Android PWA 上で動作するプッシュ通知の購読管理・配信処理・未読カウント集計をまとめて担当する。

主な構成要素:

  • プッシュ通知購読管理: ユーザーがブラウザ・PWA で通知購読を ON にするとデバイスのトークンを取得・登録
  • 2 経路の通知配信: Web ブラウザ・Android 向けの主経路と、iOS 向けの互換層経路(別アプリ「PushQuay」経由)の併用
  • 通知設定(4 軸): 講座 / トークルーム / DM / メンションの 4 軸でユーザーが個別に通知 ON/OFF を制御可能
  • 未読バッジ集計: 内部キャッシュとサーバーレス処理で未読数を効率的に取得
  • OS バッジ更新: Service Worker が通知受信時に OS のバッジ(アイコンバッジ)を更新

主な利用想定は、新規トーク投稿・記事公開・配信開始・運営告知などの即時通知、未読カウントの集計と表示、iOS PWA での通知運用など。各機能側の通知発火条件(どんなイベントで通知するか)は機能側 PSD(../talk/notification.md 等)を参照。

iOS は PWA 化が前提: iOS Safari ではブラウザ自体に通知機能の標準サポートがないため、ホーム画面追加で PWA として動作させた状態でのみ通知を受け取れる。PWA 化されていない iOS ユーザーには「PushQuay」という互換層アプリを経由して通知を届ける運用を提供。

通知トークンの定期再送: Web Push の通知トークンは内部仕様により 14 日間で無効化される仕様のため、ブラウザ側で 1 時間ごと + 画面表示時に再送して有効性を維持する仕組みを持つ。

通知許可拒否後の復帰について: ユーザーが一度ブラウザで通知許可を拒否すると、サービス側からは再度の許可ダイアログを出せない。ブラウザ設定から手動で許可に戻す必要があるため、CS 案内で手順を提示する運用となる。

通知本文の長さ制限: トーク投稿などで本文が長い場合、通知に表示される本文は内部的に約 2KB で切り詰められる。全文は通知タップ後の本文画面で確認する。

📝 レビュー観点:

  • 目的: プッシュ通知の配信と受信、未読カウントの効率取得
  • 誰が使うか: 全ユーザー(受講者・講師)
  • どこで使うか: ブラウザ・iOS PWA・Android PWA
  • 隣接機能との関係: トーク通知(../talk/notification.md)、メール(./delivery-engine.md)、PWA(./pwa.md
  • CS 問い合わせで頻発する論点: 「通知が来ない」「iOS で通知出せるか(PWA 化必須)」「14 日後に通知が止まる」「未読バッジが古い」
  • [本機能特有] FCM 経路と PushQuay 経路は両方発火: ユーザーがどちらでトークン登録しているかに依存
  • [本機能特有] FCM Web Push トークンは 14 日 TTL: FE が 1 時間ごと + visibilitychange で再送
  • [本機能特有] iOS は PWA 化必須: Notification API は PWA でのみ利用可
  • [本機能特有] Firestore キャッシュ 40MB: 24 時間で再初期化、3MiB 超 localStorage で削除
  • [本機能特有] 未読集計は Firebase Cloud Functions: バックエンド負荷分散

利用シナリオ

シナリオ 1: 新規トーク投稿でプッシュ通知を受け取る

トークルームで他の受講者・講師が新規投稿すると、プッシュ通知が即座にデバイスへ届く。Web ブラウザ・Android PWA は主経路、iOS PWA は同経路または互換層(PushQuay)経由で受信。

シナリオ 2: 通知購読 ON / OFF を切り替える

ユーザーがブラウザの通知許可ダイアログで許可 / 拒否を選択することで、購読を切り替え。許可済みの状態でも、講座 / トークルーム / DM / メンションの 4 軸で個別に通知設定を ON / OFF できる。

シナリオ 3: iOS でホーム画面追加 → PWA 化 → 通知受信

iOS ユーザーがホーム画面追加で PWA 化することで通知機能が利用可能になる。PWA 化していないと iOS では通知が届かない仕様のため、CS で「iOS で通知が来ない」相談時はホーム画面追加を案内する。

シナリオ 4: 未読バッジの表示

未読のトーク・通知がある状態でアプリを閉じると、OS のホーム画面アイコンに未読数のバッジが表示される。ユーザーが未読を確認すると自動的にクリアされる。

よくある失敗ケース

  • 通知許可拒否後の復帰不可: ブラウザ側で一度拒否すると、サービス側からは再許可ダイアログを出せない。ユーザー本人がブラウザ設定から手動許可へ戻す必要がある
  • PWA 化していない iOS で通知が来ない: iOS Safari は標準で通知非対応。ホーム画面追加 + 互換層経由が必要
  • トークン無効化による通知途絶: 14 日経過したまま画面を開かないと、トークンが無効化されて通知が途絶する。画面を開いてトークン再送が走れば復帰
  • OS バッジが古い表示: 内部キャッシュの整合性問題で、実際の未読数とバッジ数値がずれるケース。整合性メンテナンス(../admin/master.md のセレクション既読再同期等)で対応

権限別仕様

権限定義は ../user-roles.md 参照。

通知基盤は基盤機能のため、ユーザー権限軸での直接の操作は無い。機能側の通知設定は ../talk/notification.md を参照。

操作 受講者 講師 運営アドミン
プッシュ通知購読 ON / OFF
通知設定(講座 / トークルーム / DM / メンション)
受信解除(プッシュ)

機能詳細(ふるまい)

プッシュ通知の購読

  • ユーザーが画面を開いた際にバックグラウンドで Service Worker が起動 + 通知トークン取得 → サーバーに登録
  • 主経路(Web Push)と互換層経路(PushQuay)の両方を並行して登録する仕組み
  • ユーザーがどちらの経路でトークン登録しているかに依存して、どの経路から通知が届くかが決まる

iOS の PushQuay 経路

  • iOS Safari は PWA 化しないと通知機能を利用できない
  • PWA 化していない iOS ユーザー向けに、別の互換層アプリ(PushQuay)経由で通知を受け取る経路を提供
  • 互換層アプリ側でトークン登録 / 解除を行う運用

通知設定(4 軸)

ユーザーが 4 軸で個別に通知 ON/OFF を制御可能:

  • 講座単位: 特定講座の通知をまとめて ON/OFF
  • トークルーム単位: 講座内の特定ルームの通知のみ ON/OFF
  • DM 通知: ダイレクトメッセージの通知 ON/OFF
  • メンション通知: 自分が言及された投稿の通知 ON/OFF

これらの設定は通知配信の対象判定と、未読カウントへの反映に使われる。

未読バッジ集計

  • 内部キャッシュ(ブラウザ側 IndexedDB)と、サーバーレス処理(クラウド関数)の組み合わせで未読数を効率的に取得
  • BE への直接負荷を抑えつつ、リアルタイム性を確保する構成
  • 大量のトークルーム・コンテンツに対する一括未読チェックを効率化

Service Worker と OS バッジ更新

  • Service Worker が通知イベントを受信
  • 受信時に通知を表示し、内部の未読カウントを更新
  • OS のホーム画面アイコンバッジ(数字バッジ)を更新

通知配信の本文長制限

  • 通知本文の長さは内部仕様により約 2KB で切り詰め
  • 通知タップ後の本文画面では全文を表示

📝 レビュー観点:

  • 入力 → 処理 → 出力: 投稿・配信トリガー → BE が FCM/PushQuay へ送信 → デバイス受信 → SW が表示
  • エッジケース: Notification permission denied から復帰、14 日 TTL でトークン無効化、トークン重複(複数端末同期)
  • エラー表示: 通知失敗時はエラーログ + AWS ログ基盤に記録、UNREGISTERED トークンは自動削除
  • [本機能特有] 通知許可拒否後の復帰不可: requestPermission で再度許可を求めても denied が変わらない

admin 操作

該当なし / 実装されていない

  • 手動配信の運営アドミン UI: 専用画面は無し
  • 配信ログの運営閲覧 UI: 未実装(AWS ログ基盤側で確認)

📝 レビュー観点:

  • 運営アドミン側からの介入経路の必要性

品質 / 約束事項

  • 応答性: 投稿から数秒以内に通知配信
  • 信頼性: 500 件単位 partition + @Async 並列送信、20 秒超で内部監視通知。UNREGISTERED トークンは自動削除
  • 制限値:
    • トーク本文 truncate: 2048 byte(FCM 制限)
    • 同時送信パーティション: 500 件
    • Firestore キャッシュ: 40MB IndexedDB
    • localStorage 閾値: 3MiB 超で firestore_* キー削除
    • トークン TTL: FCM Web Push 14 日(FE 側で 1 時間ごと再送)
  • データ保持: トークン・通知設定は内部的に保持、配信ログは AWS ログ基盤

📝 レビュー観点:

  • [本機能特有] iOS の Web Push 16.4+ 対応の最新検証状況

変更履歴(リリースノート候補)

v2.29.2: 2026-05-04(PSD 初版)

  • [PSD 追加] 本ドキュメント初版作成。v2.29.2 時点の実装を起こし。機能追加・変更は含まない

📝 レビュー観点:

  • 過去の主要変更(PushQuay 互換層導入 / Firestore キャッシュ導入 / Cloud Functions 経路導入 等)

関連ドキュメント


このページの内容を AI に質問しますか?
関連 spec を自動抽出して ChatGPT / Claude などに渡せます。
AI Prompt で開く →