Skip to content
Pepinby SHIN
Shopify2026-05-0610分で読めます
Shopifyアプリ開発アーキテクチャソロプレナー

How My 6 Shopify App Architectures Evolved: From Marutto YOYAKU to Sales Ranking

How My 6 Shopify App Architectures Evolved: From Marutto YOYAKU to Sales Ranking

独立して3ヶ月、自宅のデスクで Shopify アプリばかり書いていたら、まるっとシリーズが6本まで増えていました。1本目の まるっと予約 をリリースしたのが2026年3月17日、6本目の まるっと売上ランキング が2026年5月6日。約50日のあいだに5本を追加した計算になります。

枚数が増えたから偉いという話ではなく、 毎本ごとに「捨てるもの」が増えていった のが、自分にとっては一番大きな変化でした。1本目では基盤コードを律儀に全部自分で書こうとしていたのに、6本目では基盤コードのほとんどを Shopify 側に預けて、勝負所であるドメインロジックと UI にだけ時間を投下する書き方になっていました。

この記事は、まるっとシリーズ6本のアーキテクチャ判断が 本ごとにどう進化したか を時系列で振り返る一次情報コラムです。SHIN(大島慎平)が2026年2〜5月に実装した中での話に限定しています。

この記事はわたし(SHIN)が2026年2〜5月にまるっとシリーズ6本を実装した、アーキテクチャ判断の一次情報です。インストール数や売上などの運用指標はまだ語れる段階にないため記載していません。書いているのは「どの実装を捨て、どこに時間を投下したか」という技術判断と、わたし個人比の工数感覚のみです。

まるっとシリーズ6本のリリース時系列

まずは6本がどんな順番で世に出たかを整理します。だいたい2〜3週間に1本のペースで、後半に行くほど1本あたりの実装期間が短くなっています。

  1. 2026-03-17

    まるっと予約(YOYAKU)

    最初の1本。Rails + React で書き始めて Remix系の公式テンプレに途中で全部移しました。Session Token を自前キャッシュした失敗作でもあります。

  2. 2026-04-15

    まるっと法務作成

    2本目。最初から公式テンプレで書き始めた1本目。基盤の悩みが消えて、書類フォーマットの設計に集中できました。

  3. 2026-04-22

    まるっとフォルダ管理(FileFolders)

    3本目。Bulk Operation を最初から前提にしたアプリ。数万件規模の Files でもスロットリングを踏まずに動きました。

  4. 2026-04-末

    まるっと検索

    4本目。Webhook 同期で自前 DB を持つ設計に切り替え、検索体験を Shopify Admin API のレイテンシから切り離しました。

  5. 2026-05-初旬

    まるっと請求書

    5本目。課金画面を自作する誘惑を断ち、Shopify Billing API に全乗せ。審査通過もスムーズでした。

  6. 2026-05-06

    まるっと売上ランキング

    6本目。バッチ集計ではなく Webhook 即時反映で「いま売れている商品」を出す構成。DB 設計に時間を投下しました。

6本のShopifyアプリを書き続けたデスクのイメージ

1本目から6本目で進化した3つの軸

6本の判断を後ろから振り返ると、進化の軸は次の3つに集約できます。

  • 認証 — Session Token の自前管理を完全にやめ、App Bridge と Token Exchange に丸投げする
  • フレームワーク — 慣れた Rails+React を捨て、 shopify app init の公式テンプレを毎回ベースにする
  • データ取得 — 逐次 GraphQL クエリではなく Bulk Operation と Webhook で「自前 DB に寄せる」設計に変える

3つとも、 公式が用意している道具に乗ったほうが速い という結論で、わたしが新しい発明をしたわけではありません。ただ、1本目を作っているときには、どれも「自前で書いたほうが理解できそう」という気持ちが勝ちました。これから1本目を書く方には、可能な限りその誘惑を捨てて欲しいなと思います。

Token Exchange

Shopify が推奨する Embedded App 向けの認証フロー。クライアントが App Bridge から取得した Session Token をバックエンドに渡すと、必要な Access Token に交換できる仕組み。アプリ開発者がトークンの寿命管理やキャッシュを書く必要がなくなります。

Bulk Operation

Shopify Admin GraphQL の非同期ジョブAPI。1回の mutation で対象クエリを登録すると、バックグラウンドで JSONL ファイルを生成し、完了通知とダウンロードURLを返してくれます。Rate Limit の消費は登録1回分のみで、数万件規模のデータ取得に向いています。

出典:Shopify App Bridge library — Session token / idToken

出典:Shopify GraphQL Bulk Operations

6本それぞれで何を捨て、何に投下したか

ここから本題です。6本ごとに「捨てたもの」と「投下した先」を、時系列で振り返ります。

1本目: まるっと予約(YOYAKU) — 自前認証を捨て、UX に投下

最初の1本は、ほぼすべての設計判断を間違えました。Rails のバックエンドに React の SPA を載せ、Session Token を Redis にキャッシュし、Webhook の HMAC 検証も自前で書こうとしていました。動くものは動きましたが、書き終わった頃には基盤コードがアプリの中身を超える分量になっていました。

リリース直前の2週間で、公式テンプレ(当時 Remix系、現在は React Router v7 ベース)に全部移しました。基盤コードの大半が消え、残ったのは予約カレンダーと席数管理ロジックという、本来勝負したい部分だけ。1本目から教訓ができました。

Before: 1本目を書き始めた頃のわたし

Rails + React、Session Token を Redis にキャッシュ、Webhook 受信を自作、CSP も自分で設定しようとした

After: リリース直前のまるっと予約

公式テンプレに全部移行、認証は App Bridge 任せ、Webhook は同梱ヘルパーで検証、勝負所は予約カレンダー UX

1本目は「自分のスタックで作りきれる」と思いがちですが、Shopify エコシステムでは公式テンプレに乗ったほうが圧倒的に速いです。慣れたフレームワークを使いたい気持ちは、9割の確率で回収できません。

出典:Shopify CLI — Scaffold an app

2本目: まるっと法務作成 — 自作フォーム検証を捨て、テンプレ充実に投下

2本目は、Shopify ストアで使う特商法・利用規約・プライバシーポリシーなどの 法務書類を自動生成する アプリです。1本目の反省から、最初から公式テンプレで書き始めました。

このアプリで捨てたのは「フォームバリデーションを Zod や React Hook Form でフルに書く」という方針でした。法務書類はフォーム入力よりも テンプレートそのものの充実度 が UX を決めます。バリデーション層は Polaris のフォーム部品が持つ最低限の機構に任せ、空いた時間を書類テンプレートのバリエーション拡充に回しました。

  1. 1

    公式テンプレで雛形を生成

    shopify app init を実行し、推奨テンプレートを選択。1本目と違って即座にローカルで動く状態に。

  2. 2

    Polaris のフォーム部品をそのまま採用

    自前デザインを諦めて Shopify 管理画面のトーンに合わせる。慣れた merchant が違和感なく操作できる。

  3. 3

    勝負所である書類テンプレに時間を投下

    特商法・利用規約・プライバシーポリシー・キャンセルポリシーなど、業種別のテンプレを増やす。

基盤コードを書かないと決めた瞬間、書類テンプレの充実に1日まるごと使えるようになりました。アプリの「中身」は基盤の外にあります。

3本目: まるっとフォルダ管理 — 逐次クエリを捨て、Bulk Operation 一択に

3本目の まるっとフォルダ管理(FileFolders) は、Shopify の Files セクションに「フォルダ」概念を持ち込むアプリです。Files は merchant が画像・動画・PDF などを大量に置く場所で、ストアによっては数万ファイル規模になります。

1本目の反省から、最初から Bulk Operation 前提 で組みました。一覧取得を逐次クエリで書いていたら、Calculated query cost を使い切って THROTTLED の嵐になっていたはずです。Bulk Operation なら登録1回分のポイントで済み、JSONL を読みながらフォルダ構造に再マップできます。

Bulk Operationを最初から選ぶ判断のイメージ
Before: 1本目の癖で逐次クエリを書きそうになった

GraphQL の files query に first: 50 を指定して pageInfo でページング → 数万件で API ポイントを使い切る

After: Bulk Operation 一択

bulkOperationRunQuery で登録 → 完了通知 → JSONL をストリーム読み込み → フォルダ構造を組み直す

Bulk Operation は「初期同期に1回だけ走らせて、以降は Webhook で差分追従」というパターンがソロ開発には最も実装コストが低い構成です。

出典:Shopify API rate limits

4本目: まるっと検索 — Admin API レイテンシを捨て、自前 DB に投下

4本目の まるっと検索 は、商品・コレクション・ブログ記事などストア内コンテンツの横断検索を、merchant 向け管理画面側に提供するアプリです。最初は「検索のたびに Admin API を叩く」設計を考えましたが、レイテンシも Rate Limit も悲鳴をあげるのが目に見えていたので方針転換しました。

捨てたのは「Shopify をマスター DB として毎回問い合わせる」という発想です。投下したのは Webhook 同期 による自前 DB の構築でした。products/update、collections/update、articles/update といった Webhook を購読し、変更を自前 DB に反映。検索クエリは自前 DB に対して走らせ、表示時のみ Shopify から最新の在庫数や価格を引きにいく構成にしました。

Webhook

Shopify が指定 URL にイベント(注文作成、商品更新、在庫変更など)をプッシュ送信する仕組み。アプリ側が自前 DB を持っていれば、API ポーリングなしで Shopify と同期できます。HMAC 署名による検証が必須です。

メリット

自前 DB なので、インデックス設計次第でミリ秒オーダーのレスポンスを返せる

merchant が連打しても Shopify 側の API ポイントを消費しないため、UX が安定する

デメリット

HMAC 検証、リトライ、デッドレターキュー的な仕組みを用意しないと、稀な失敗時にデータがズレる

Webhook はインストール後の更新分しか飛ばないため、過去データは Bulk Operation で取り込む二段構え

出典:Shopify Webhooks

5本目: まるっと請求書 — 自作課金画面を捨て、Shopify Billing API に全乗せ

5本目の まるっと請求書 は、Shopify ストアで発行する適格請求書(インボイス)を自動生成するアプリです。サブスクリプション課金を載せるとき、最初は「自前で Stripe を組み込んで決済画面を作ろう」という気持ちが頭をよぎりました。

ここでブレーキを踏めたのは、4本目までの経験のおかげです。Shopify アプリでサブスクリプション課金を載せる場合、 Shopify Billing API を使うのが推奨であり、独自決済を挟むと審査で跳ねられる可能性が高い。merchant 側の体験としても、Shopify 管理画面の中で完結したほうが自然です。

課金フローはShopify Billing APIに寄せる判断
  1. 1

    appSubscriptionCreate で課金プラン作成

    GraphQL Admin API の appSubscriptionCreate で月額プランを定義。確認画面の URL が返ってくる。

  2. 2

    merchant を確認画面にリダイレクト

    Shopify 管理画面側で課金確認 → 承諾 → callback で承認結果を受け取る。決済 UI を自作しない。

  3. 3

    Webhook で状態同期

    app_subscriptions/update を購読し、課金状態を自前 DB に保存。プラン変更や解約も同じフローで扱う。

独自決済を Shopify アプリに組み込むと、審査で「Shopify Billing API を使ってください」と差し戻される可能性が高いです。請求書アプリのテーマと審査差し戻しが二重で重なると、致命的に時間を失います。

出典:Shopify Billing API

6本目: まるっと売上ランキング — バッチ集計を捨て、Webhook 即時反映に投下

そして6本目、 まるっと売上ランキング は注文データから「いま売れている商品」を即時にランキング表示するアプリです。最初に思い浮かぶのは「夜中に1回バッチを走らせて集計」ですが、それだと「いま売れている」感が出せません。

捨てたのは 「日次バッチで集計する」 という発想で、投下したのは orders/create と orders/updated を Webhook で受け取り、 届いた瞬間に集計テーブルを更新する 設計です。直近24時間・7日間・30日間のランキングを別テーブルで持ち、注文が来るたびに増減を反映します。これにより、merchant が管理画面を開いた瞬間に最新の売れ筋が見えるようになりました。

即時反映ランキングの集計フロー
6
リリース済みアプリ本数(2026-05-06時点)
50
1本目から6本目までの日数(個人比)
14
1本目で公式テンプレに移行し直した日数
0
3〜6本目でやり直しに使った日数

数字はわたし個人比の実測値で、他のアプリやチーム規模で同じ結果が出る保証はありません。 進化の傾向を示す目安 として読んでください。

1本目 vs 6本目 — アーキテクチャ Before/After

6本を通して、土台に何を採用しているかを整理すると、1本目と6本目はほぼ別物のスタックになりました。

Before: 1本目(まるっと予約)の初期実装

Rails + React SPA、Session Token を自前で Redis にキャッシュ、Webhook 検証を自前実装、Admin API は逐次クエリ、課金は未実装で後回し、CSP も手動設定

After: 6本目(まるっと売上ランキング)

React Router v7 公式テンプレ、App Bridge + Token Exchange、Webhook はテンプレ同梱ヘルパー、初期取り込みは Bulk Operation、以降は Webhook で自前 DB 同期、課金は Shopify Billing API

書き出してみると当たり前のことばかりですが、1本目では「自前で書いたほうが理解できる」と思っていました。6本目では「Shopify が用意してくれている層は、できるだけ薄くてもいいから乗る」という判断に変わっています。

公式が用意した抽象に乗ることは「楽をする」ことではなく、未来の自分に「ここは Shopify 側のメンテに任せる」と委譲する設計判断です。委譲できる領域を増やすほど、勝負所に時間が回ります。

6本目をリリースしたあとの自分

個人比で見た「捨てたもの」の体感

数字はあくまでわたしの実装での個人比ですが、6本を通じて「書かなくて済んだコード」の体感を並べておきます。

100行
1本目で削った Session Token 自前キャッシュのコード(個人比)
2週間
1本目で公式テンプレに移行し直した実工数(個人比)
0回
3本目以降で踏んだ THROTTLED エラー(個人比)
1本
6本中、独自決済を組み込みかけて踏みとどまった本数

これらの数字はすべて「わたし個人の実装での実測値」です。アプリの規模、扱うデータ量、merchant の使い方で、結果は大きく変わります。傾向の参考としてだけ受け取ってください。

これから1本目を作る人に渡したい順番

6本書いたあとで、もし「これから1本目を書きます」と相談されたら、わたしはこの順番を勧めます。1本目から無駄を踏まないための、ささやかな道しるべです。

  1. 1

    1. 公式 CLI でスカフォールドを作る

    shopify app init で雛形を生成し、推奨テンプレートを選ぶ。慣れたフレームワークを持ち込まない。

  2. 2

    2. 認証は App Bridge と Token Exchange に任せる

    Session Token の保管・キャッシュは絶対に書かない。テンプレ同梱の authenticate.admin 相当のヘルパーをそのまま使う。

  3. 3

    3. データ取得の設計を最初に決める

    扱うデータ量が多いか/更新追従が必要か。多いなら Bulk Operation、追従が必要なら Webhook で自前 DB に同期。

  4. 4

    4. 課金は Shopify Billing API 一択

    独自決済は審査で跳ねられる前提。 appSubscriptionCreate のフローに乗る。

  5. 5

    5. Webhook の HMAC 検証は必ずテンプレに任せる

    ここで自作するメリットがゼロに近いので、テンプレのヘルパーを読んで「何をやっているか」だけ理解する。

  6. 6

    6. 自分の勝負所はドメインロジックと UI

    基盤を組まなくて済む時間を、すべて「このアプリでなければできないこと」に投下する。

6本のまるっとシリーズが並ぶイメージ

よくある質問

自分用の追加レイヤーは育ちます(Prisma スキーマの共通化、Webhook 受信の共通ハンドラなど)。ただ Shopify 側の進化も速いため、 基盤コードは Shopify に寄せて毎本最新を取り直す 方が結果的に楽でした。横展開のコピペで済ませると、1年後に置いていかれます。

間違いなく2本目を書く前に体力が尽きていました。Webhook の HMAC 検証 / CSP / App Bridge 初期化 / セッション検証を全部自分でメンテし続けるのは、ソロ開発では現実的ではありません。1本目の14日間の遠回りは、結果的に2〜6本目の速度を全部底上げしてくれました。

わたしの基準は「画面表示やバッチ処理で50件を超えそうなら検討、数百件を超えるなら確定」です。フォルダ管理(3本目)も検索(4本目)も、最初から Bulk Operation 前提で組んだので一度もスロットリングを踏みませんでした。

Shopify が提供していない決済手段(特殊な BNPL、特定国のローカル決済など)を merchant に提供する目的で、 アプリ機能の対価ではない 形なら可能性があります。アプリのサブスクリプション課金そのものを独自決済で取るのは、ほぼ確実に Shopify Billing API への寄せ替えを求められます。

まとめ

1本目から6本目までで進化したのは、突き詰めると 「Shopify 側の抽象に何を委譲するか」 の判断ひとつでした。

  • 認証は App Bridge と Token Exchange に委譲する(自前キャッシュは書かない)
  • フレームワークは公式テンプレに委譲する(慣れた道具を持ち込まない)
  • データ取得は Bulk Operation と Webhook に委譲する(逐次クエリで Rate Limit を踏まない)
  • 課金は Shopify Billing API に委譲する(独自決済は審査で跳ねられる前提)
  • Webhook 検証はテンプレ同梱ヘルパーに委譲する(HMAC を自作しない)

委譲できる領域を増やすほど、自分の手元には「このアプリでなければできないこと」だけが残ります。まるっと予約の予約カレンダー、まるっとフォルダ管理のフォルダ操作 UI、まるっと売上ランキングの即時集計設計、こうした 勝負所に時間を投下する ためにこそ、基盤判断を毎本見直してきた、というのが正直な実感です。

これから1本目を作る方は、ぜひ6本目のわたしと同じ順番でスタートしてください。1本目から「捨てる勇気」を持って書き始められると、あなたの2本目以降は、わたしのそれよりずっと速くなるはずです。

6本書いてもなお、毎本ごとに「もっと委譲できる領域はないか」を探しています。アプリ開発は土台の進化が速いので、 半年前のベストプラクティスは半年後の負債になりうる という前提で書き続けたいなと思います。

→ まるっとシリーズを見る

この記事はShopify予約アプリ「まるっと予約」の開発元であるPepinが執筆しています。

Share
SHIN

この記事の執筆者

SHIN

Pepin代表、Webエンジニアとして10年以上の経歴を持ち、
Shopifyアプリ・ストア開発 / webサービス開発 / メディア運営などマルチに活動。

Shopify無料体験を始める

Let's Build Together