ECサイトを作る場合: 決済・在庫管理・検索・SEOの技術選定
はじめに
ECサイト(Electronic Commerce)の構築は、決済処理、在庫管理、商品検索、SEO対策など、多くの技術的課題を同時に解決する必要があります。本記事では「Shopifyを使うか、自作するか」という根本的な判断から、自作する場合の具体的な技術構成まで解説します。
身近な例えで理解するECサイトの技術課題
ECサイトは「デパート」の運営に似ています。
- 決済システム = レジ。お金を正確に、安全に処理する(最も重要で失敗が許されない)
- 在庫管理 = 倉庫管理。「残り1個」を2人が同時に買おうとしたらどうする?
- 商品検索 = フロアガイド。お客様が欲しい商品を素早く見つけられるように
- SEO = 広告とのれん。Google検索で見つけてもらえるように
- カート = ショッピングカート。途中で離脱しても中身を覚えておく
Shopify vs 自作: 判断フロー
[ECサイト構築の判断]
|
v
[独自の業務ロジックが必要?]
|
+-- いいえ --> [月商1,000万円以上になる見込み?]
| |
| +-- いいえ --> Shopify(最も手軽)
| |
| +-- はい --> Shopify Plus or 自作
|
+-- はい
|
v
[どの程度のカスタマイズが必要?]
|
+-- デザインのみ --> Shopify + テーマカスタマイズ
|
+-- 機能追加が必要 --> Shopify + アプリ/Hydrogen
|
+-- 完全なカスタム --> 自作
(独自の決済フロー、複雑な在庫管理、
既存システムとの深い統合が必要な場合)
Shopify vs 自作の比較
| 項目 | Shopify | 自作(Next.js + Stripe) |
|---|
| 初期構築期間 | 数日〜数週間 | 3〜6ヶ月 |
| 初期費用 | $0〜 | 数百万円〜 |
| 月額費用 | $39〜$399 + 手数料 | サーバー費 + 保守費 |
| 決済手数料 | 3.4%〜 | Stripe: 3.6% |
| カスタマイズ性 | 中(テーマ + アプリ) | 最高 |
| SEO | 良好 | 自由自在 |
| スケーラビリティ | Shopifyが管理 | 自分で管理 |
| 保守運用 | Shopifyが管理 | 自分で管理 |
| PCI DSS準拠 | Shopifyが対応 | Stripe利用で大幅に軽減 |
自作する場合の全体アーキテクチャ
推奨構成: Next.js + Stripe + PostgreSQL
+-------------------+
| CloudFront |
| (CDN + WAF) |
+--------+----------+
|
+--------v----------+
| Next.js |
| (SSR/SSG) |
| on Vercel |
+--------+----------+
|
+--------v----------+
| ALB |
+--------+----------+
|
+--------------+--------------+
| | |
+-------v------+ +----v-------+ +----v--------+
|API Server | |Payment | |Search |
|NestJS | |Service | |Service |
|(商品/注文/ | |(Stripe | |(OpenSearch) |
| ユーザー) | | Webhook) | | |
+-------+------+ +----+-------+ +----+--------+
| | |
+------v------+ +---v---+ +-----v-----+
|PostgreSQL | |Stripe | |OpenSearch |
|(Aurora) | |API | |Cluster |
+------+------+ +-------+ +-----------+
|
+------v------+
|Redis |
|(ElastiCache) |
|セッション/ |
|カート/在庫 |
+-------------+
+-------------------------------------------+
| バックグラウンド処理 |
| - SQS: 注文処理キュー |
| - Lambda: メール送信、画像処理 |
| - EventBridge: 在庫アラート |
| - S3: 商品画像保存 |
+-------------------------------------------+
技術選定の詳細
フロントエンド: Next.js
| 要件 | Next.jsでの対応方法 |
|---|
| SEO | SSR/SSGで事前レンダリング。構造化データ(JSON-LD)対応 |
| 商品ページ | ISR(増分静的再生成)で高速表示 + 最新データ |
| カート | Client-sideのState管理(Zustand等) |
| 決済ページ | Stripe Elementsの埋め込み |
| レスポンシブ | Tailwind CSSでモバイル対応 |
バックエンド: NestJS (Node.js)
NestJSを選ぶ理由:
- TypeScriptネイティブ
- モジュール構造でドメイン分離が容易
- デコレーターベースのAPI定義
- Swagger自動生成
- テストが書きやすい
決済: Stripe
| 決済サービス | 手数料 | 特徴 |
|---|
| Stripe | 3.6% | 開発者体験最高、API充実 |
| PayPay | 1.98%〜 | 日本のモバイル決済 |
| GMO PaymentGateway | 3.2%〜 | 日本の主要決済代行 |
| Square | 3.25% | 対面/オンライン両対応 |
Stripeを選ぶ理由:
- APIファーストの設計で開発が容易
- Webhookで決済イベントを確実に受信
- Stripe Checkoutで安全な決済フォームを簡単に実装
- サブスクリプション、分割払い、クーポンなど豊富な機能
- PCI DSS準拠の負担を大幅に軽減
データベース: PostgreSQL (Aurora)
[テーブル設計の概要]
users -- ユーザー情報
products -- 商品マスタ
product_variants -- 商品バリエーション(サイズ、色等)
inventory -- 在庫管理
orders -- 注文ヘッダー
order_items -- 注文明細
payments -- 決済情報
addresses -- 配送先
categories -- カテゴリ
reviews -- レビュー
在庫管理の設計
在庫管理で最も重要な課題: 在庫の競合
2人のユーザーが同時に「残り1個」の商品を購入しようとした場合の対処。
方式の比較
| 方式 | 仕組み | メリット | デメリット |
|---|
| 悲観的ロック | DB行ロック(SELECT FOR UPDATE) | 確実 | パフォーマンス低下 |
| 楽観的ロック | バージョン番号チェック | 高パフォーマンス | リトライが必要 |
| Redis在庫カウンター | Redisでアトミックにデクリメント | 超高速 | Redis障害時の整合性 |
推奨: Redis在庫カウンター + DBの楽観的ロック
[在庫確保の流れ]
1. カートに追加時
Redis: DECR inventory:product_123
→ 0以上なら「仮確保」成功
→ 0未満なら「在庫切れ」、INCR で戻す
2. 決済完了時
DB: UPDATE inventory SET quantity = quantity - 1
WHERE product_id = 123 AND quantity > 0
→ 成功: 注文確定
→ 失敗: Redisの在庫を戻す
3. カート放棄時(30分後)
Redis: INCR inventory:product_123
→ 仮確保を解放
検索機能
検索要件
| 要件 | 説明 |
|---|
| キーワード検索 | 商品名、説明文からの全文検索 |
| ファセット検索 | カテゴリ、価格帯、ブランド等でのフィルタリング |
| サジェスト | 入力途中での候補表示 |
| 類似検索 | 「赤いTシャツ」→「レッドのTシャツ」もヒット |
| ソート | 価格順、新着順、人気順 |
OpenSearchの構成
[商品データ(PostgreSQL)]
|
v
[DMS / Lambda(同期ジョブ)]
|
v
[OpenSearch Index]
|-- 商品名(日本語形態素解析: kuromoji)
|-- 説明文
|-- カテゴリ(ファセット用)
|-- 価格(範囲検索用)
|-- タグ
|
v
[検索API] --> [フロントエンドの検索結果]
SEO対策
ECサイトのSEO要件
| 対策 | 実装方法 |
|---|
| 構造化データ | JSON-LD(Product、BreadcrumbList、Review等) |
| メタタグ | 商品ごとにtitle、description、OGP画像を動的生成 |
| サイトマップ | Next.jsのnext-sitemapで自動生成 |
| パンくずリスト | カテゴリ階層を反映 |
| ページ速度 | ISR + 画像最適化 + CDN |
| モバイル対応 | レスポンシブデザイン |
| canonical URL | 重複コンテンツの防止 |
| robots.txt | クロール制御 |
ISR(増分静的再生成)の活用
[商品ページの配信戦略]
1. 初回アクセス
→ SSGでビルド済みのHTMLを返す(高速)
2. revalidate期間経過後
→ バックグラウンドで再生成
→ 次のアクセスから新しいHTMLを返す
3. 新商品追加
→ On-demand ISRで即座に生成
→ APIからrevalidateをトリガー
チーム規模と開発スケジュール
MVP(3ヶ月)
| 役割 | 人数 | 担当範囲 |
|---|
| フロントエンド | 2人 | 商品一覧/詳細、カート、決済ページ |
| バックエンド | 2人 | API、決済連携、在庫管理 |
| インフラ | 1人 | AWS構築、CI/CD |
| デザイン | 1人 | UI/UXデザイン |
| PM | 1人 | 進捗管理、要件定義 |
| 合計 | 7人 | 3ヶ月 |
MVPの機能:
- 商品一覧/詳細/検索
- カート
- 会員登録/ログイン
- Stripe決済
- 注文履歴
- 管理画面(商品/注文管理)
本格展開(6ヶ月追加)
| 追加機能 | 必要人数 | 期間 |
|---|
| レコメンデーション | 1人 | 2ヶ月 |
| レビュー/評価システム | 1人 | 1ヶ月 |
| ポイント/クーポン | 1人 | 2ヶ月 |
| メール配信(カート放棄等) | 1人 | 1ヶ月 |
| 分析ダッシュボード | 1人 | 2ヶ月 |
コスト見積り
MVPフェーズ(〜月商100万円)
| サービス | 構成 | 月額 |
|---|
| Vercel | Proプラン | $20 |
| ECS/Fargate | 2タスク | $40 |
| Aurora PostgreSQL | db.t3.medium | $130 |
| ElastiCache Redis | cache.t3.micro | $25 |
| S3 + CloudFront | 50GB + 50GB転送 | $10 |
| OpenSearch | t3.small.search | $35 |
| Stripe手数料 | 月商100万円の3.6% | $260 (36,000円) |
| 合計(Stripe手数料除く) | | 約$260/月 |
成長フェーズ(〜月商1,000万円)
| サービス | 構成 | 月額 |
|---|
| Vercel | Teamプラン | $100 |
| ECS/Fargate | 4タスク x 1vCPU | $200 |
| Aurora PostgreSQL | db.r6g.large + Replica | $600 |
| ElastiCache Redis | cache.r6g.large | $200 |
| S3 + CloudFront | 500GB + 500GB転送 | $80 |
| OpenSearch | 3ノード | $200 |
| SES | メール送信 | $10 |
| Stripe手数料 | 月商1,000万円の3.6% | $2,600 (360,000円) |
| 合計(Stripe手数料除く) | | 約$1,390/月 |
Shopifyを選ぶ場合のアーキテクチャ
Shopify + カスタムフロントエンド(Hydrogen/Next.js)
[ユーザー]
|
v
[Next.js (カスタムフロント)]
|
v
[Shopify Storefront API (GraphQL)]
|
+-- 商品データ取得
+-- カート管理
+-- 決済(Shopify Checkout)
+-- 注文管理
|
[Shopify Admin API]
|
+-- 在庫管理
+-- 注文処理
+-- 顧客管理
Shopify + ヘッドレスのメリット:
- バックエンド(決済、在庫、注文)はShopifyが管理
- フロントエンドは完全にカスタマイズ可能
- SEOも自由にコントロール
デメリット:
- Shopifyの月額費用 + 決済手数料が発生
- Shopify APIの制約を受ける
- 複雑な在庫ロジックは実装しにくい
決済のセキュリティ
PCI DSS準拠
クレジットカード情報を扱うシステムは、PCI DSS(Payment Card Industry Data Security Standard)に準拠する必要がある。
| 方式 | PCI DSS負担 | 説明 |
|---|
| Stripe Elements | 最小(SAQ A) | カード情報はStripeのiframeで処理。自社サーバーにカード情報が一切流れない |
| Stripe Checkout | 最小(SAQ A) | Stripeの決済ページにリダイレクト |
| 自社で直接処理 | 最大(SAQ D) | カード情報を自社サーバーで処理。年間数千万円のコスト |
推奨: Stripe Elementsを使い、自社サーバーにクレジットカード情報を一切保存しない設計にする。
まとめ
判断の要約
| 状況 | 推奨 |
|---|
| 小規模EC、早く始めたい | Shopify |
| デザインを自由にしたい | Shopify + ヘッドレス(Next.js) |
| 複雑な業務ロジックがある | 自作(Next.js + NestJS + Stripe) |
| 超大規模、完全な制御 | 自作(フルカスタム) |
推奨技術スタック(自作の場合)
| レイヤー | 技術 | 理由 |
|---|
| フロントエンド | Next.js | SSR/ISR、SEO最適化 |
| バックエンド | NestJS | TypeScript、モジュール構造 |
| データベース | PostgreSQL (Aurora) | 信頼性、トランザクション |
| キャッシュ | Redis | セッション、在庫カウンター |
| 決済 | Stripe | 開発者体験、PCI DSS軽減 |
| 検索 | OpenSearch | 全文検索、ファセット |
| 画像 | S3 + CloudFront | スケーラブル、CDN配信 |
ECサイトは「お金を扱う」という特性上、セキュリティと信頼性が最も重要。Stripeのような信頼できる決済プロバイダーを活用し、自社はビジネスロジックに集中するのが最善の戦略である。
参考リンク