セグメンテーション & ロイヤルティサービス
顧客セグメンテーション、会員ランク別キャッシュバック、パートナーリベート設定
プロジェクト背景
各テナントは、入金額などの行動に基づいて顧客を区別して扱いたく、その設定も自分で行いたい。セグメントはユーザー登録の瞬間に割り当て、全テナント・全通貨について定期的に再評価し、監査証跡付きで手動変更できる必要がある。
アーキテクチャ
管理 API(ゲートウェイ)→ セグメンテーション gRPC サービス → MySQL(設定、割り当て、履歴、戦略テーブル)。ID サービスからの登録イベント → Kafka コンシューマー → デフォルト割り当て。スケジュールジョブサービス内の毎日の Temporal ワークフロー → テナント/通貨ごとの子ワークフロー → 分類結果を Kafka に発行 → リトライとデッドレタートピックを備えたコンシューマーが適用。
主な技術ポイント
顧客セグメンテーションをゼロから構築:9テーブル、28の gRPC エンドポイントと16の HTTP エンドポイント、排他的なデフォルトを持つトランザクショナルな設定、スナップショット付きの変更履歴
新規ユーザーには Kafka の登録イベントからデフォルトセグメントを付与。ローリング期間の入金額しきい値に基づくルールベースの自動分類
毎日の Temporal ワークフローが、テナント別の子ワークフローとハートビート・ページング付きのアクティビティで、全テナント・全通貨を再分類
階層数無制限のパートナーネットワーク向けリベート設定:階層ごとの料率、パイプラインによる無効化を伴う Redis キャッシュアサイド、プロダクト有効化時の Kafka 駆動のデフォルト設定
冪等なキャッシュバック記録コンシューマー:一意インデックスで担保された決定的キー
コア実装
イベントによるデフォルト割り当て
Kafka コンシューマーがユーザー登録・ユーザー作成イベントを購読し、テナントのデフォルトセグメントを割り当てる。リトライとデッドレタートピック付き。
Why: 割り当てが登録リクエスト内の2回目の書き込みの成否に依存してはならない。イベント駆動にすることで ID とセグメンテーションを疎結合に保てる。
再開可能な再分類
毎日のワークフローがテナントを列挙し、テナント・通貨ごとに子ワークフローを起動する。各子ワークフローは昇格マップと降格戦略を読み込み、アクティビティのハートビートを送りながらユーザーをページングで処理し、結果を発行する。
Why: 全ユーザーの再評価は長時間ジョブになる。ハートビートとページングにより、Temporal は全体をやり直すことなく子ワークフロー単位でリトライ・再開できる。
パートナーリベート設定
階層数無制限のパートナーネットワーク向けの階層別料率ルール。Redis にキャッシュし、テナント単位で無効化する。参照時にはユーザーのパートナーチェーン全体の料率を並列に解決する。
Why: 精算ジョブは全ユーザーについてチェーン全体を必要とする。キャッシュと並列参照でそのコストを低く抑えられる。
技術的意思決定
| 技術的意思決定 | 選択 | 代替案 | 理由 |
|---|---|---|---|
| 分類をどこで実行するか | 結果を Kafka に発行する Temporal ワークフロー | セグメンテーションサービス内で cron により分類 | テナント単位の長時間処理にはリトライ、可視性、再開性が必要。結果を発行する方式なら、書き込み経路を1つのコンシューマーに集約できる。 |