前回(第3回)は、今後の拡張性をガチで考えたデータベースのスキーマ(設計図)を組み立てました。D1データベーススキーマの設計:リレーショナルデータベースとは? 【CFW P2P心理戦ゲーム開発記】 #3
今回(第4回)からは、いよいよこの設計図を現実のコードに落とし込んでいきます。まずは、すべての土台となる「ユーザー基本情報(users)」と「マルチ認証(user_auths)」のテーブル作成、そして実際のサインイン時にバックエンドがどう動くのか、実装のコア部分を構築していきます。

1. テーブル作成SQL(DDL)を記述する
まずは、前回設計したスキーマをデータベース(Cloudflare D1 / SQLite)に認識させるためのSQL(マイグレーションファイル)を作成します。
-- 1. users テーブル(ユーザー基本プロファイル)
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY, -- UUIDなどを想定
display_name TEXT NOT NULL, -- 表示名
created_at TEXT DEFAULT (datetime('now', 'localtime')) -- 作成日時
);
-- 2. user_auths テーブル(マルチ認証・ログイン方法管理)
CREATE TABLE IF NOT EXISTS user_auths (
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 通し番号
user_id TEXT NOT NULL, -- users.id への紐付け
provider TEXT NOT NULL, -- 'google', 'github', 'email', 'sms' など
provider_user_id TEXT NOT NULL, -- 各外部サービス側のユーザーID
secret_hash TEXT, -- メール/SMSの検証用ハッシュ(OAuth時はNULL)
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE (provider, provider_user_id)
);実装のポイント
FOREIGN KEY ... ON DELETE CASCADEusersからユーザーが削除されたとき、その人に紐づくuser_auths(認証情報)も自動で一緒に消えるようにしています。データのゴミを残さないための重要な設定です。UNIQUE (provider, provider_user_id)前回の設計通り、データベースのレイヤーで「同じGoogleアカウントを持つ別ユーザー」が生まれるバグを物理的にシャットアウトしています。
2. 新規ユーザーの同時作成(トランザクション)
新規登録の場合、users(本体)と user_auths(認証方法)の2つのテーブルに同時にデータをインサートする必要があります。
片方だけ成功して片方が失敗するとデータが壊れてしまうため、ここは必ず「一連の処理がすべて成功するか、すべて失敗するか」を保証するトランザクション(Transaction)を使って実装します。
-- 1. usersテーブルに新しいユーザーを作成
INSERT INTO users (id, display_name)
VALUES ('generated-uuid-1234', '新規プレイヤー');
-- 2. user_authsテーブルに認証情報を紐付け
INSERT INTO user_auths (user_id, provider, provider_user_id)
VALUES ('generated-uuid-1234', 'google', 'GOOGLE_USER_ID_XXXX');これが無事に成功すれば、無事に「マルチ認証に対応した新しいユーザー」の誕生です!
3. メールリンク・SMS認証のための拡張(予備知識)
今回は初期実装として Google や GitHub の OAuth を想定していますが、構想にある「メールリンク」や「ショートメール(SMS)のワンタイムパスワード」を行う場合は、secret_hash を活用します。
- ユーザーがメールアドレスを入力
- ランダムな文字列(トークン)を生成し、ハッシュ化して
secret_hashに保存(同時に有効期限もメモリやキャッシュ等に保持) - ユーザーがURLを踏む、あるいはコードを入力した際に、送信されてきた値のハッシュが
secret_hashと一致すれば認証成功!
このように、あらかじめ secret_hash を仕込んでおくことで、大掛かりなシステム改修をせずともスムーズに認証方法を増やすことができます。
登録後の確認
登録の確認として、以下のような命令で登録されている’table’一覧を出してみました。
npx wrangler d1 execute DB --local --command "SELECT name FROM sqlite_master WHERE type='table';"
usersとuser_authsが登録されていることを確認しました。
4.新規ユーザ追加チェック

ターミナルからjsonリクエストを送り、疑似データでユーザ登録してみました。
winのcurlは疑似curl
データベースやAPIの実装が終わったら、まずはローカル環境でサクッと疎通確認(テスト)をしたいと思いますよね。 MacやLinuxの感覚で、ネットの記事を参考にしながら以下のようなコマンドをターミナルに貼り付けた経験はありませんか?
# 今回の構成で新規ユーザ登録をターミナルから疑似的に行うPOST
curl -X POST http://localhost:8787/api/auth/google `
-H "Content-Type: application/json" `
-d '{"googleUserId": "test_12345", "displayName": "LumenHero"}'よし、これをPowerShellで実行だ!……とエンターキーを押した瞬間、画面は無情にも真っ赤なエラーメッセージで埋め尽くされます。
なぜこんなことが起きるのか。結論から言うと、PowerShellにおける curl は本物のcurlではなく、Windowsが用意した別コマンド(Invoke-WebRequest)の単なる「偽名(エイリアス)」だからです。
PowerShellの親切心(お節介とも言う)によって、「Linuxユーザーも馴染みやすいように、curl って打ったら自動的にWindows用のWebリクエストコマンドに変えておくね!」という処理が裏で走ってしまっているのです。
しかし、本物の curl と Invoke-WebRequest では、引数の受け取り方が全く異なります。
- 本物のcurl:
-Hに"Content-Type: application/json"という「ただの文字列」を渡せばOK。 - 疑似版(Invoke-WebRequest):
-H(内部的には-Headers)には、「連想配列(ハッシュテーブル)」という特別なデータ型を渡さなければならない。
文字列を渡された偽物curlは「そんな型じゃ受け取れない!」とパニックを起こし、先ほどの爆死エラーを吐き出していたわけです。
解決策としては、
アプローチ①:本物の curl.exe を強制指名する(手軽さ★★☆)
アプローチ②:PowerShellのネイティブコマンドを使う(手軽さ★★★)
アプローチ③:VS Codeの「REST Client」に頼る(圧倒的おすすめ★★★★★)
が使えます。今回は簡易テストとして動かしたいだけなので、アプローチ②をとりました。
Invoke-RestMethod -Uri "http://127.0.0.1:8787/api/auth/google" `
>> -Method Post `
>> -ContentType "application/json; charset=utf-8" `
>> -Body '{"googleUserId": "test_google_id_12345", "displayName": "LumenHero"}'まとめと次回予告
今回は前回作った設計図を元に、ユーザーと認証周りの具体的なSQL定義と、バックエンド側でのログイン・新規登録の処理フローを実装に落とし込みました。
データベースの制約(FOREIGN KEYやUNIQUE)を正しく使うことで、プログラム側のコードをゴリゴリ書かなくても、安全なシステムが構築できるのがRDBの強みです。
具体的なログイン実装
GOOGLE #10 : 関連記事は、2026年6月19日に公開予定 (あと6日)
関連記事
CloudFlare Workersセットアップ
Cloudflare Workersの始め方:Wranglerによるローカル環境構築と世界公開の手順
【第2回】データベースを作る
D1データベース作成とテスト環境構築の手順 【CFW P2P心理戦ゲーム開発記】 #2
【第3回】データベーススキーマ設計
D1データベーススキーマの設計:リレーショナルデータベースとは? 【CFW P2P心理戦ゲーム開発記】 #3
もう一つの選択肢:VPSで自由なゲームサーバー構築
本連載ではCloudflare Workersを活用したP2P実装を進めていますが、もし環境の制約がなく、
「もっと使い慣れた言語で自由にゲームサーバーを立てたい」
「WebSocketなどの常駐プロセスをガッツリ回したい」
という場合は、VPS上に独自のシグナリングサーバーを構築するのも強力な正攻法です。
「テキストを読んで知識として知っていること」と、「実際に手元でLinuxサーバー(Ubuntuなど)を叩いて構築した経験」とでは、バックエンドへの理解の深さに大きな差が生まれます。
最近の海外サービスは「最初は無料・格安で普及させ、定着したタイミングで一気に値上げや制限強化に踏み切る」という戦略が多く、個人開発での新規参入や継続運用のハードルが高くなりがちです。
その点、日本の老舗である
さくらのインターネット(さくらのVPS)
は価格面でも運用の面でも圧倒的な安定感があり、個人的にとても信頼して推しています。
「海外サービスの急な仕様変更に振り回されたくない」「自分のインフラ拠点を国内に1つ持っておきたい」という方は、ぜひ一度触ってみてください!
次回予告
次回は、もう一つのコアデータである「ゲーム専用データ(buckshot_stats)側のテーブル作成」と、実際にこれらをWorkersから叩くためのAPIエンドポイントのガワ(ルート定義など)を作っていきたいと思います!
次回ゲームデータ編:関連記事は、2026年6月13日に公開予定 (あと1時間)
ここまで読んでいただきありがとうございます。 では、次の記事で。 lumenHero