はじめに
この記事は、Merpay Advent Calendar 2022 の7日目の記事 メルカードの舞台裏編です。
こんにちは。 株式会社メルペイ Growth Platform Teamのバックエンドエンジニアの@keiitajです。Growth Platform Teamはキャンペーンやクーポンを通してお客さまにメルペイをより使っていただけるようなプロダクトの基盤開発を行うチームです。
先日、弊社ではメルカードというクレジットカードをリリースしました。 メルカリ・メルペイをおトクに使っていただけるように、メルカードの常時ポイント還元と、メルカードを持つお客さまへの限定キャンペーンを開発しています。
今回は、メルカードの常時ポイント還元の仕組みと、開発で工夫・苦労したところをお話したいと思います。
メルカード常時ポイント還元の仕組み
ポイント付与の役割を担うマイクロサービスはSantaサービスです。 基本的に、ポイント付与はPubSubを使った非同期処理によってSubscriberの処理で行っています。今回、メルカードの常時ポイント還元においてもSantaサービスのSubscriberの新規実装を行いました。 以下のシステム構成となっています。
メルカードのお支払いは、メルペイスマート払いの仕組みが使われており、翌月に請求が発行されます。 メルカードの常時ポイント還元は、そのメルペイスマート払い請求の支払い完了をトリガーに、ポイント付与を実行しています。 流れはこのようになります。
- メルペイスマート払い請求の支払いが完了すると、Credit Designチームが管理するメルペイスマート払いサービスは、PubSubのTopicに請求情報をPublishします。
- Santaサービスは、Pull型のSubscriptionを通じて、請求情報をSubscribeします。
- Santaサービスは、請求情報から支払い完了済みのメルペイスマート払いの債権を取り出して、各債権がポイント還元対象かどうかのフィルタリングをかけます。(フィルタリングの機能についてはこちらの記事を御覧ください。)
- メルカードの初期設定が完了し、有効化されているかどうか
- ポイント還元対象加盟店で決済した債権かどうか
- フィルタリングを通して、還元対象となった債権は、その金額と還元率に応じて、ポイント付与額を計算し、還元のリワードデータを生成します。ポイント還元率は他のマイクロサービスである還元率管理のマイクロサービスからお客さま還元率を判定して決定されます。(メルカードの還元率管理については、こちらの記事を御覧ください。)
- 債権ごとにリワードデータが生成された後、複数のリワードデータからポイントを集計して、Paymentサービスを通じてポイント付与が実行されます。
以上が、メルカードの常時ポイント還元の処理の流れで、PubSubのSubscriberとして実装されます。
Santaサービスのデータ設計
メルカードの常時ポイント還元におけるデータは、Campaigns、Rewardsのテーブルに分けており、下記がその関係図になります。 Campaignsが事前に登録しておくキャンペーン用のテーブルで、Rewardsが上記のSubscriberによるポイント付与処理によって生成されるリワードを登録するテーブルです。
Campaignsがキャンペーン用のデータを管理するテーブルです。常時ポイント還元は、メルカリ・メルカリ以外のお店でのお買い物によって、それぞれキャンペーン名称や還元率、還元条件(フィルタ設定)が異なるため、それぞれレコードを作成しています。
- メルカリ
- メルカリ以外のお店
請求のお支払い完了日時がキャンペーン期間内(start_atからend_atの期間範囲内)であるキャンペーンが適用されるようになっていますが、常時ポイント還元は定常施策であるため、start_atとend_atは幅広い範囲を持たせることで、全ての定常施策(この場合、メルカリとメルカリ以外お店でのお買い物による常時ポイント還元)のCampaignsが適用されるようになっています。
定常施策以外のキャンペーンに関してはアドオン施策として具体的にキャンペーン期間(start_atとend_at)を指定します。アドオン施策に関しては後述します。
では、請求情報の中の1つのメルペイスマート払い債権に対して、メルカリ・メルカリ以外のお店での双方の還元が適用されるでしょうか? こちらは実際には発生しないようになっており、payment_filters(債権単位のフィルタ設定)によって、それぞれフィルタリングが実施され、1つの債権に対して両方で還元されないように運用しています。
payment_filtersはそれぞれ次のような設定になっています。(フィルタリングの機能についてはこちらの記事を御覧ください。)
- メルカリ
- メルカリで決済した債権かどうかのフィルタリング。メルカリで決済した債権である場合、還元対象となる。
- メルカリ以外のお店
- メルカリ以外のお店で決済した債権かどうか、かつ、ポイント還元対象加盟店で決済した債権かどうかのフィルタリング。 メルカリ以外のお店で決済し、かつ、ポイント還元対象加盟店で決済した場合、還元対象となる。
customer_filters(お客さま単位のフィルタ)は、お客さまが還元条件を満たしているか判定するために使用しています。常時ポイント還元の場合、アクティベート済みのメルカードを保有しているかどうかのフィルタリングが設定されます。
Rewardsがキャンペーンのリワードを管理するテーブルです。ポイント付与処理の中で、債権単位でリワードを生成しています。
メルカードの常時ポイント還元実装で工夫・苦労した点
冪等性
PubSubは、Subscriberの処理中のエラーによる再配信(リトライ)や、予期せぬ複数回の配信が発生することがあるため、Subscriberは冪等である必要があります。この時、冪等性を担保するために、campaign_idとinvoice_id(請求書のID)を使用しています。
既に該当のキャンペーンでinvoice_idに関連付いたリワードデータが登録されている場合は、Subscriberはリワードデータの作成を行わないようにします。
ただし、同一の請求の中に、複数の債権が含まれているため、payment_id(債権のID)に紐づく複数のリワードは、請求単位で、同一のトランザクション内でまとめて登録と更新を実行しなければなりません。
アドオン施策
メルカードの常時ポイント還元は定常施策ですが、アドオン施策として、特定の期間だけポイント還元率をアップできるような機能をもたせることができます。例えば、メルカードの新規入会&利用で最大10,000ポイントをプレゼントするキャンペーンです。(キャンペーンの内容に関してはこちらを御覧ください。) このうち、最大4,000ポイントの還元は、このアドオン施策の仕組みを利用しています。
還元対象が、メルカード申込日の翌々月末(支払いはその1ヶ月後まで)という要件があるため、Campaignsテーブルに11月メルカード申込みしたお客さま用のキャンペーンデータを一つ追加し、フィルタには以下が設定されます。
customer_filters(お客さま単位のフィルタ)
- メルカードの初期設定が完了し、有効化されているかどうかのフィルタリング
- 11/1 – 11/30の期間内にメルカードに初回申込みしたかどうかのフィルタリング
payment_filters(債権単位のフィルタ)
- 債権の決済日時が11/1 – 1/31の期間内かどうかのフィルタリング
- ポイント還元対象加盟店で決済した債権かどうかのフィルタリング
メルカリとメルカリ以外のお店での決済の特定
メルカリでの購入と、メルカリ以外のお店でのお買いもので、それぞれポイント還元率が異なるため、正しく判定する必要があります。
その判定に際し、注意するべきところは幾つかあるのですが、そのうちの一つがメルカリの購入で使用できるオンライン型のApple Payです。
オンライン型のApple PayはiD決済であり、システム上は厳密にはメルカリ以外のお店での決済とみなされます。 またiD加盟店のアクワイアラはメルペイではないため、メルカリの決済かどうかを判定するためのiDの端末識別番号などの情報を、iD加盟店のアクワイアラから連携いただき、メルカリで決済したかどうかを特定する必要があります。
さいごに
最後まで読んでいただきありがとうございます。
メルカードの常時ポイント還元の機能は非同期のポイント付与処理を実装するだけでなく、メルカリの購入画面や決済完了通知に表示するポイント還元予定額表示のためのAPIも新規実装し、各マイクロサービスに提供しています。 APIの処理は同期的に行っているため、想定RPS(Request Per Second)に応じたレイテンシやDBの負荷軽減のために工夫した点は色々あるのですが、こちらはまた別の機会にお話できればと考えています。
また、メルカードを持つお客さまへの限定キャンペーンは、仕組みが常時ポイント還元とは異なり、オペレーション上の問題に直面しています。 現在は、オペレーションの改善に向けた取り組みを進めているので、そちらについても別の機会にお話できればと考えています。
明日の記事は krisさん , mikaelさん, anzaiさん , shinmyさんです。引き続きお楽しみください。