アーキテクチャと送信の仕組み
todoke は Cloudflare のプラットフォームのみで構成された Web Push 通知 SaaS です。このページでは、通知が API 呼び出しからブラウザに届くまでの内部の流れと、送信を安定させるための仕組みを解説します。
todoke は次の Cloudflare コンポーネントで構成されています。
| コンポーネント | 役割 |
|---|---|
| Cloudflare Workers | REST API・Queue Consumer の実行環境 |
| Cloudflare D1 | アプリ・購読者・API キー・送信ログなどの永続化(SQLite) |
| Cloudflare KV | セッション・OAuth ステートの一時保存 |
| Cloudflare Queues | 通知送信のバッファリングと非同期配信 |
| Cloudflare Pages | ダッシュボード(SPA)のホスティング |
外部の Web Push サービス(Google FCM、Mozilla autopush、Apple の Web Push 用 APNs など)へは、購読者のブラウザ・OS に応じて自動的に振り分けられます。これはブラウザ側の Push Subscription の endpoint に含まれる情報であり、todoke 側で明示的に選択するものではありません。
通知が届くまで
Section titled “通知が届くまで”通知の送信は次の経路をたどります。
REST API → Cloudflare Queues → Queue Consumer Worker → Push サービス(FCM 等)→ ブラウザ- クライアント(SDK・CLI・curl など)が
POST /api/v1/notifyを呼び出す - API はペイロードサイズやプラン上限などを検証したうえで、通知を Cloudflare Queues に enqueue する
- API は enqueue が完了した時点で
202 Acceptedを返す - Queue Consumer Worker が非同期にメッセージを取り出し、購読者ごとに Push サービスへ配信する
この非同期化により、購読者数が多いアプリでも API リクエストがタイムアウトすることなく、常に高速なレスポンスを返せます。
リトライと DLQ(Dead Letter Queue)
Section titled “リトライと DLQ(Dead Letter Queue)”Queue Consumer Worker での処理が失敗した場合、そのメッセージは自動的にリトライされます。
- リトライ回数: メッセージ単位で最大 3 回
- リトライを使い切った場合: メッセージは DLQ(Dead Letter Queue) に送られます
- DLQ に到達したメッセージ: 内容を記録したうえで破棄されます。つまり、その通知は再送されず失われます
購読の自動無効化
Section titled “購読の自動無効化”ブラウザの購読は、ユーザーが通知を許可しなくなった場合やブラウザ側で購読期限が切れた場合などに失効します。todoke では、Push サービスへの配信時に HTTP 410(Gone)または 404(Not Found) が返された購読を、その時点で自動的に非アクティブ化します。
非アクティブ化された購読には次のとおり適用されます。
- 以降の通知送信の対象から除外される
- 購読者数(プラン上限のカウント対象)には含まれない
これにより、失効した購読への配信を無駄にリトライすることなく、購読者一覧を実態に近い状態に保っています。
Web Push / VAPID の基礎
Section titled “Web Push / VAPID の基礎”ブラウザへの Push 配信は Web Push プロトコル(RFC 8291 暗号化、RFC 8188 メッセージエンコーディング、RFC 8292 VAPID)に基づいています。todoke ではこれらを自前実装しており、一般的な Node.js 向け web-push ライブラリには依存していません(Cloudflare Workers ランタイムの Web Crypto API と互換性を持たせるためです)。
利用者として意識する必要があるのは、主に次の2つの概念です。
購読(Push Subscription)
Section titled “購読(Push Subscription)”ブラウザの Push API から取得できる購読情報で、次の3つの値からなります。
| フィールド | 説明 |
|---|---|
endpoint | 配信先の Push サービス URL(ブラウザ・ベンダーごとに異なる) |
p256dh | ペイロード暗号化に使う公開鍵 |
auth | ペイロード暗号化に使う認証シークレット |
この3つをセットで API に登録することで、todoke はそのブラウザ宛に暗号化された通知を送れるようになります。
VAPID 鍵ペア
Section titled “VAPID 鍵ペア”VAPID(Voluntary Application Server Identification)は、Push サービスに対して「どのアプリケーションからの送信か」を証明する仕組みです。todoke はアプリ作成時にアプリごとの VAPID 鍵ペア(公開鍵・秘密鍵)を発行し、秘密鍵は暗号化して保存します。送信時にはこの鍵ペアで署名した JWT を各リクエストに付与し、Push サービスに送信元を証明します。
公開鍵はブラウザ側で購読を作成する際に必要になるため、GET /api/v1/vapid-public-key から取得できます。
プラン制限の適用点
Section titled “プラン制限の適用点”Free プランには、購読者数と月間送信数に上限があります。これらは異なるタイミングでチェックされます。
| 制限 | チェックのタイミング | 上限(Free) |
|---|---|---|
| 月間送信数 | 通知の送信時(Queue への投入前) | 30,000 通 |
| 購読者数 | 購読の登録時 | 1,000 人 |
つまり、月間送信上限は POST /api/v1/notify のリクエストごとに、購読者数上限は新規購読を登録する POST /api/v1/apps/:appId/subscriptions のリクエスト時に、それぞれ独立してチェックされます。どちらを超過した場合もリクエストは拒否され、レスポンスにアップグレード導線(upgrade_url)が含まれます。詳細はエラーコード・制限値を参照してください。