第七章:PostgreSQL 極小データベース設計 - 権限と注文のコアハブ

開発初期のシステムアーキテクチャ設計において、多くの新人エンジニア(そして時には経験のあるバックエンドエンジニアでさえ)がECサイトやコースデータベースを設計する際、「過剰設計 (Over-engineering)」の罠に陥りがちです。

彼らはリレーショナル図ソフトを開き、複雑に入り組んだアーキテクチャを描きます: Usersテーブルを作成し、Coursesテーブルを作成し、何を購入したかを記録するためにOrdersテーブルを作成し、さらに明細を記録するためにOrder_Itemsテーブルが必要で、最後に金流を確認するためのTransactionsテーブルを追加します... 複雑な外部キー(Foreign Keys)とJOINクエリの山ができあがります。

しかし、「純粋な知識販売、仮想商品、在庫問題なし、物流配送なし」のSaaSプラットフォームにとって、このような巨大な従来型EC設計は開発が非常に苦痛で、将来のメンテナンスコストが極めて高く、99%のシナリオで完全に不要です。

Vibe Tutorのシステムアーキテクチャでは、私たちは「Minimal Viable Product (MVP、最小限の実行可能製品)」の精神を堅持しています。コアとなるビジネス権限ロジック全体を極限まで圧縮し、最終的にたった1つのテーブルだけで済ませました。


🧊 The One Table 哲学:vt_purchases

SupabaseのPostgreSQLデータベースでは、vt_purchases(購入記録)という名前のテーブルを作成しました。 このテーブルのフィールドは非常に簡潔ですが、サイト全体の「権限解除判断」と「バックエンド販売統計」を完璧にサポートしています。

フィールド設計の詳細分析

| フィールド名 | データ型 | 説明とビジネス価値 | | :--- | :--- | :--- | | id | uuid (Primary Key) | 各購入記録の一意の識別子、絶対に重複しないことを保証。 | | created_at | timestamp with time zone | 購入完了時のタイムスタンプ、デフォルトはnow()。月次収益トレンドグラフの作成に使用。 | | user_id | uuid (Foreign Key) | 購入者のID。このフィールドはSupabase組み込みの高セキュリティauth.users認証テーブルに安全に関連付けられます。 | | item_id | text | (コアの魂) 購入した商品コード、例: "coding-101"。プログラムはこの文字列でどの権限を付与するかを決定します。 | | item_type | text | 商品のタイプ。例: course(単一コース)、bundle(バンドル)。将来の物理商品販売拡張に備えて。 | | price | integer | 実際の取引金額。これは重要で、一部の顧客が早期割引価格で購入している可能性があるため、財務調整のために実際の支払い金額を記録する必要があります。 |


💡 コアの魂:item_id 権限判断の技術

すべての「権限ロックロジック」をitem_idというプレーンテキスト文字列に圧縮しました。これにより、巨大な「コーステーブル」と「注文明細テーブル」の関連付けを作成する手間を省きました。 チェックアウト時にitem_idをどのように設定したか振り返りましょう:

  • 99円入門コース購入: item_id = "coding-101"と記録。このユーザーがこのコースのテキストコンテンツをアンロックしたことを意味します。
  • 1999円上級地図コース購入: item_id = "car-camping-map"と記録。同様にこのコースのテキストコンテンツをアンロック。
  • 3999円ソースコード付きプラン購入: item_id = "car-camping-map-source"と記録。フロントエンドコードでは、-sourceで終わるIDを持つ場合、テキストをアンロックし、プロジェクトのZIPダウンロードボタンを表示します。
  • 9999円究極VIPパス購入: item_id = "vip-all-access"と記録。プログラムがこのIDを見ると、古代の「免死金牌」を見たかのように、直接return trueし、サイト内のすべてのコースとダウンロードエリアに無条件でアクセス許可!

このフラットな設計により、データベースのクエリ速度は電光石火のように速く、コードも極めてクリーンです:

// 🚀 ユーザーが所有するものを一度に検出、複雑なテーブルをJOINする必要なし!
const { data: purchases } = await supabase
  .from("vt_purchases")
  .select("item_id")
  .eq("user_id", user.id);

// 文字列配列に抽出:['coding-101', 'car-camping-map']
const purchasedItemIds = purchases.map(p => p.item_id);

// 特定のコースにアクセス可能か判断
const canAccess = purchasedItemIds.includes(currentCourseId) || purchasedItemIds.includes("vip-all-access");

🛡️ RLS (Row Level Security) 行レベルセキュリティ防御

SupabaseのようなBackend-as-a-Service (BaaS)を使用すると開発が非常に速くなりますが、初心者が犯しがちな致命的なセキュリティ問題が発生します: 「SupabaseのAPI Keyがフロントエンドで公開されている場合、プログラミングを知っているハッカーはブラウザのConsoleでAPIを叩いてデータベースに書き込み、自分に何百もの無料コースを追加できるのでは?」

この恐ろしい問題を解決するために、PostgreSQLには業界最強のRLS (Row Level Security)メカニズムが組み込まれています。 vt_purchasesという会社の収益に関わる重要なテーブルに対して、私たちは非常に厳格なRLSポリシーを設定しました:

  1. Select (読み取り) ポリシー

    -- SQLポリシールール
    (auth.uid() = user_id)
    

    ビジネス保護の意味: 誰もが自分のログインUIDと等しいuser_idのデータのみを読み取ることができます。他人の購入記録を絶対に見ることはできず、競合他社が顧客リストと販売量をスクレイピングするのを防ぎ、厳格な個人情報保護法規制に準拠します。

  2. Insert/Update/Delete (書き込みと���更) ポリシーすべて閉鎖(禁止)! これは、フロントエンドのJavaScriptコードが、ハッカーがどのように改ざんしようとも、このテーブルに書き込みや変更を行う権限が「まったくない」ことを意味します。

❓ では通常の注文はどのように書き込むのか?

フロントエンドがデータを書き込めない場合、ユーザーが支払いを完了した後、どのように記録をデータベースに保存するのでしょうか? 答えはバックエンドサーバーの Service Role Key (無敵のスーパーキー) を通じてです。

サーバーサイド(Next.jsの/api Route Handlers内)では、最高のシステム権限を持つSupabase Clientを使用し、.envに保存されているSERVICE_ROLE_KEYを携帯しています。このキーはすべてのRLSポリシーを無視し、データベースに直接強力に書き込むことができます。

緑界科技(ECPay)のサーバーが私たちのバックグラウンドWebhook(支払い成功通知)を呼び出すとき、これは「サーバー間」の安全なチャネルで行われます。私たちのバックエンドAPIが検証に成功すると、このスーパーキーを使用してデータを安全にvt_purchasesテーブルに書き込みます。

この「フロントエンドは自分のデータのみを照会でき、バックエンドのみがコアデータを書き込める」という設計が、知識販売プラットフォームの堅牢な最後の防衛線を構成しています!

✅ 本章のまとめ

最高のアーキテクチャは、往々にして最もシンプルなアーキテクチャです。One Table哲学と強力なRLS防御を通じて、私たちは拡張性が高く、セキュリティが強固で���メンテナンスコストがゼロのデータベース層を構築しました。 大ボスに立ち向かう準備はできていますか?次の章では、台湾のECで最も困難で、最もお金を稼げる難関に挑戦します:緑界科技ECPay金流APIの接続と検証!

章のまとめ

  • コアコンセプトと原理を理解
  • 実装方法とテクニックを習得
  • 一般的な問題と解決策に精通
  • 実際のプロジェクトに適用可能

さらに読む

  • 公式ドキュメントとAPIリファレンス
  • GitHubのオープンソース例
  • 技術書とオンラインコース
  • コミュニティディスカッションと技術ブログ

完全なチュートリアルをロック解除

このチャプターは有料コンテンツです。プロジェクトに参加して、10以上の神レベルのPromptや実際のソースコード例を含む、5000字以上の深い分析をロック解除してください!