クックパッドマートでの店舗の認証方法移行の取り組み

クックパッドマートの開発に携わっているソフトウェアエンジニアの塩出(@solt9029)です。「クックパッドマートを支えるアカウントたち」連載シリーズの5本目の記事です。本記事では、クックパッドマートでの店舗の認証方法移行の取り組みについて紹介します。

美味しい生鮮食品をユーザーにお届けするサービスであるクックパッドマートでは、日々街の販売店や地域の生産者が商品登録や出荷作業を行っており、それらの操作を行う際に、専用の管理画面を利用しています。

今までは、店舗向け管理画面の認証のために、ユーザー登録の仕組みを設けていませんでした。専用のチャットアプリ上で管理画面のログインURLを都度発行する方式を取っていました。このログイン方式では、「店舗のスタッフごとの権限管理や操作ログの監査ができない」という明確な課題や、「店舗とクックパッドのユーザーは分離された概念となり、クックパッドにおけるサービス共有資産が活用できない」という中長期的な課題がありました。

そこで店舗の認証方法を、クックパッドのユーザーを利用したOAuth認証に移行しました。認証方法の移行の際、多くの困難な課題を解決する必要がありました。本記事では、店舗の認証方法の移行の背景や経緯、実現のために求められた要件や解決した課題について紹介します。

認証方法の移行前と移行後の比較

背景・目的

クックパッドマートは、弊社が力を入れて取り組んでいる新規事業の1つです。生鮮食品を中心として扱っているECプラットフォームで、街の販売店や地域の生産者がクックパッドマートに参加しています。コンビニエンスストア・ドラッグストア・駅・マンションなどの様々な場所に、ユーザーの受け取り場所として専用の冷蔵庫が設置されています。ユーザーはアプリから注文を行い、冷蔵庫から生鮮食品を受け取ることができます。

クックパッドマートでは、店舗が商品の登録や営業日の管理、日々の出荷作業などを行うための機能を提供する、店舗向け管理画面を開発しています。

店舗向け管理画面

クックパッド運営は、店舗の問い合わせサポートをするために、専用のチャットアプリを利用してやり取りしています。店舗向け管理画面では、今までユーザー登録の仕組みを設けておらず、チャットアプリ上での発言に応じて、ボットが管理画面のログインURLを都度発行する方式を取っていました。

チャットアプリ上でログインURLを都度発行する様子

店舗向け管理画面が誕生した当時、ミニマムの機能でなるべく多くの店舗にスムーズに使ってもらえるような形で検証を行いたく、ログインの手間を最小限に抑えた作りとしていました*1。実際にしばらく運用したところで、店舗向け管理画面はクックパッドマートを回すために必要不可欠な存在にまで成長しました。しかし、ログインURLを都度発行する方式では、以下のような課題が存在していました。

  • 1店舗の中でも複数のスタッフが商品登録や出荷作業を行っているケースがある一方で、どの操作をどのスタッフが行ったかを、ログから特定することが難しい。
  • クックパッドマートの注文ユーザー向けECアプリでは、レシピサービスであるクックパッドのユーザー基盤を用いて認証を行っている一方で、店舗の認証はクックパッドのユーザーから切り離されており、クックパッドにおけるサービス共有資産が一切活用できない。つまり、例えばクックパッドマートのECアプリ上では、店舗として活動できない状態であり、「クックパッドマートのECアプリ上で店舗として登録されたユーザー限定機能を提供する」といった施策は実現できない。

本来であれば、検証段階に作ったプロダクトをそのまま成長させるのではなく、認証方法を含めて一度あるべき姿で作り直すべきでした。しかし、時間を巻き戻すことはできないため、改めて認証方法の移行に踏み切ることにしました。上記に掲げた前者の課題から、何かしらのアカウントを利用した認証の仕組みが必要となり、後者の課題から、その「アカウント」はクックパッドのユーザーであるべきだと整理しました。そこで店舗の認証方法を、クックパッドのユーザーを利用したOAuth認証に移行することにしました。

設計・実装

店舗の認証方法の移行にあたって、機能として必要となった要件や設計、実装を紹介します。

認証方法移行に伴うデータ設計

今まで店舗ごとに、チャットアプリ上からログインURLを都度発行する方式をとっていたため、「店舗としての操作」という扱いになっていました。

実際には、背景・目的の章で述べたとおり、1店舗の中でも複数のスタッフが商品登録や出荷作業を行っているケースがあるため、1店舗に対して複数のユーザーを登録できる状態を実現する必要がありました。

また、1事業者が複数の店舗を運営しているケースもあります。例えば、「〇〇マート株式会社」という事業者が、「〇〇マート横浜店」と「〇〇マート川崎店」といった店舗を運営している場合です。この場合、例えば事業者の代表者が複数の店舗の売上情報を閲覧したいといった要望がありえるため、1ユーザーが複数の店舗に登録できる状態も実現する必要がありました。以上から、店舗とユーザーの関係は多対多として実現する必要がありました。

また法務や権限管理の観点から、1事業者は管理者としてのユーザーを1つのみ登録する必要がありました。そのため、「事業者」を表す概念もデータ設計時に組み込む必要がありました。これまでの内容を図解すると、以下のようになります。

移行前と移行後の認証の単位の比較

もともとは shops テーブルで完結していたものが、認証方法の移行にあたって以下のようなデータ設計になりました。大した複雑性ではありませんが、移行前と比較すればそれなりに登場人物の増えた状態になりました。

データ設計の変更

認証方法移行に伴うログイン体験の変化

今までは都度発行されるログインURLと店舗が1対1の関係であったのに対して、認証方法を移行した後は、前章の通り1ユーザーが複数店舗を保持できるようになります。そのため、クックパッドのユーザーを利用して店舗向け管理画面にログインしたとしても、「どの店舗の操作をしたいか」は確定しません。

実現方法は主に2つ考えられました。1つ目は、リソースを扱うようにパスなどで指定したIDに応じて操作対象の店舗を指定する方法です。ECサイトの管理画面などでたくさんの商品マスター情報を操作する考え方に近いです。2つ目は、セッションなどで操作対象の店舗のIDを指定・保持する方法です。厳密には根底の概念から違いますが、TwitterやFacebookなどのSNSに見られる「アカウント切り替え」の見せ方に近いです。

認証方法の移行にあたっては、2つ目の「アカウント切り替え」のような見せ方を採用しました。以前の店舗向け管理画面では、都度発行されるログインURLと店舗が1対1の関係であったことから、「店舗」主体での操作しかありえなかったため、管理画面の操作体験の変化を最小限に留めることや、移行のための実装の容易性を意識したことが主な理由です。

「アカウント切り替え」のような見せ方

複数の認証方法の並存

認証方法の移行にあたって、ログインURLを都度発行する方式からいきなり全てをクックパッドのユーザーを用いたOAuth認証に切り替えることは当然できません。認証方法の移行に関する告知を出した後、一定期間どちらの認証方法も受け入れられる状態を用意する必要があります。認証方法の移行が完了した店舗から随時、旧認証方法(都度発行されるログインURLの認証)が無効になる形にしました。

また、どちらか片方の方法で認証された状態だけでなく、両方の認証方法が同時に適用された状態が必要になる場面も存在するため、それを考慮した実装を行う必要がありました。具体的には、店舗の認証方法の移行手順を実施するタイミングです。

両方の認証方法が同時に適用された状態が必要になる場面

複数の認証方法があるだけでなく、その複数の認証方法を同時に扱わなければならない場面があったため、想定されるケース数も多く、実装も複雑になり、認証方法の移行にあたっての1つの大きな鬼門になりました。実装の詳細については軽く紹介するにとどめますが、大きく3つのメソッドが重要になりました。

  • 新旧の認証方法に関わらず、現在選択中(ログイン中)の店舗を返却するメソッド(current_shop
  • 旧認証方法によってログインしている店舗を返却するメソッド(current_shop_by_old_auth
  • ログイン中のクックパッドのユーザーを返却するメソッド(current_user
# 新旧の認証方法に関わらず、現在選択中(ログイン中)の店舗を返却するメソッド
def current_shop
  if logged_in_with_cookpad?
    # ユーザーに登録された店舗が1つのみの場合、操作対象の店舗をわざわざ選択しなくとも、店舗は一意に定まる
    if session[:current_shop_id].nil? && current_user.authorized_shops.size == 1
      session[:current_shop_id] = current_user.authorized_shops.first.id
    end

    current_user.authorized_shops.find_by(id: session[:current_shop_id])
  else
    current_shop_by_old_auth # 都度発行されるログインURLで認証を受けている場合、その店舗を返却するメソッド
  end
end

運営スタッフによる問い合わせサポートの考慮

今までは、店舗ごとにチャットアプリ上からログインURLを都度発行する方式をとっていました。店舗からの問い合わせサポートを行う際、クックパッドの運営スタッフは実際にログインURLを通じて、その店舗として店舗向け管理画面にログインして、画面状況を確認することが時折ありました。

認証方法の移行によって、クックパッドのユーザーによるOAuth認証が必要になりますが、当然セキュリティ上、クックパッドの運営スタッフはその店舗スタッフとして登録されたユーザーのIDやパスワードを把握できません。しかし、認証方法の移行後も引き続き、問い合わせサポートや緊急対応の目的で、クックパッドの運営スタッフが店舗向け管理画面を閲覧できる状態を維持したいと考えました。社内の管理画面でもほとんどの必要な操作はできますが、なるべく店舗スタッフが実際に日々利用している画面を、クックパッドの運営スタッフも閲覧できる状態とすることで、店舗スタッフの抱える課題を、より現場目線で把握しやすい状態にできると考えたからです。

そのため、運営スタッフが店舗向け管理画面を任意の店舗として閲覧できる仕組みを別途設けました。限られたクックパッドの運営スタッフは、あらかじめクックパッドのユーザーを社内の管理画面上で登録することによって、特別な権限を付与し、そのユーザーを利用すれば任意の店舗として店舗向け管理画面を閲覧できる仕組みにしています。

しかし、例えばそのクックパッドの運営スタッフが退職をした際に、退職後もその登録したクックパッドのユーザーを利用して任意の店舗としてログインできる状態となってしまっては、セキュリティ上の問題があるため、クックパッド社員退職後の自動処理の中で、その権限を無効化する機能を作りました。社員退職後の自動処理について、詳細は「退職処理を可能な限り自動化する」の記事にまとまっています。

ユーザー登録の解除の考慮

クックパッドのユーザー登録は解除することができます。しかし、一定の条件において、このユーザー登録の解除はブロックされています。例えば、クックパッドマートでの注文した商品の受け取りが完了していないケースでは、ユーザー登録を解除してしまうと受け取り不可能な状態となってしまうため、受け取りが完了するまでの間、解除がブロックされています。

同様に、例えばクックパッドマートで注文が入っているにも関わらず、未出荷の状態の店舗のスタッフが全員ユーザー登録を解除してしまうと、店舗向け管理画面に一切アクセスできない状態となってしまいます。そこで、クックパッドマートから退店をしない限り、かならず店舗のスタッフとして登録されたユーザーが存在するように、クックパッドのユーザー登録の解除についてブロック処理を設けました。

リリース・運用にあたって

これまで、実装や設計について紹介しました。実際にリリースや運用をするにあたっては、開発以外にも考慮すべき点が多数あります。本章では、その中でも特に注力したものを軽く紹介します。

法務の観点

クックパッドのユーザーは、基本的には個人が営利を目的とせずに利用することが想定されています。しかし、認証方法の移行によって、クックパッドマートに出店している営利目的の店舗(法人含む)がクックパッドのユーザーを利用することになります。法務チームと仕様の認識合わせを行いながら、最終的には営利活動における特約を定めることとしました。また、認証方法の移行にあたって一定期間の告知を設ける必要があるなど、その他にも多くの項目について連携を取りながら開発を進めました。

運用の観点

認証方法の移行にあたって、期限にある程度の余裕を持たせていましたが、なるべく早く、より多くの店舗が認証方法を移行した状態になることが望ましいと考えていました。そこで、社内の管理画面上で認証方法の移行の進捗状況がすぐに確認できる機能を作成し、認証方法の移行完了を目指して、運用チームがアクションのとりやすい状態をつくりました。また、店舗と直接コミュニケーションをとる機会の多い営業チームとも連携し、スピーディーな移行に努めました。

また、認証方法の移行時のトラブルも細かく考慮しながら進めました。認証方法の移行時のトラブルの一例として、1店舗において複数のスタッフが出荷作業を行っている場合に、誤ってあるスタッフが店舗内で何も周知せずに認証方法の移行を行ってしまった結果、旧認証方法(都度発行されるログインURLの認証)が無効になってしまい、他のスタッフが店舗向け管理画面にアクセスできなくなってしまうケースが想定されました。

認証方法の移行の際に想定されたトラブルの一例

店舗向け管理画面の中には、注文商品の出荷作業のような、数時間以内に行う必要のある緊急を要する作業を行うための機能も含まれており、認証方法の移行時に何かトラブルがあると、この出荷作業に影響が出てしまい、最悪の場合ユーザーに注文商品をお届けできなくなる恐れがあります。そのため、ドキュメント整備による認証方法の移行時のトラブル発生の未然防止や、すぐにトラブル対応できるようなサポート体制を整えることはもちろん、問い合わせベースで認証方法を一時的に元に戻せる仕組み作りなども行いました。

最後に

クックパッドマートでの店舗の認証方法の移行の取り組みについて紹介しました。認証方法の移行にあたって、一時的に複数の認証方法が並列して存在したり、店舗とユーザーの多対多の関係にする必要があったり、様々な困難がありました。リリース後の問い合わせは週数件のペースでありましたが、量も内容も想定していた範囲内に留まっており、大きなトラブルもなくスムーズに進めることができました。

本プロジェクトを通じて、「認証方法の移行」は避けられるのであればなるべく避けたいものだとも痛感しました。今まで紹介したように、認証方法の移行には開発はもちろん、多方面で非常に多くのコストがかかるからです。本記事で紹介したケースでは、検証用のミニマムの機能として開発したものをそのまま開発継続して広く普及させず、価値に確信できたタイミングで、早々に認証方法の移行や、新しく別のアプリケーションとして作り直すべきだったと感じました。

一方で、どうしても後から認証方法の移行をしなければならない場面も現実世界では多々あると思います。そんな場面に遭遇してしまった方に、本記事で紹介した実装時の考慮項目や運用が一例として参考になれば幸いです。

最後になりますが、クックパッドマートでは事業成長のためにスピードを高めて開発に取り組んでおり、様々な技術に触れる機会も多くとても楽しい環境です。弊社では絶賛エンジニア募集中なので、興味を持って頂けた方はぜひ採用情報をご覧ください。

info.cookpad.com

アカウント連載シリーズの記事一覧

*1:詳しくは過去の記事「街のお店や生産者が使ってくれる仕組みのつくりかた」をご覧ください。