ハコヅミを作る #27:ステップ2 の方針を決め、Google アカウントでログインできるようにする
前回(#26)で、ステップ1(自分用の機能を充実させる)が終わりました。ここからは、自分以外の人が使うことを考えるステップ2 です。
今回は、作る前に決めたことと、最初の一歩の「ログイン」です。
- ステップ2 を、どこまでにするか
- 会員区分(フリー・有料・管理者)を、どう持つか
- Better Auth で、Google アカウントでログインできるようにする(#133)
ステップ2 を「公開の準備」に絞る
前回の最後に、ステップ2 は「複数ユーザーでの共有」と書きました。ところが、やることを並べてみると、量が多すぎました。ログイン、会員区分、課金、共有、公開範囲……と続きます。
Claude Code に候補を挙げてもらい、相談して、次のように分けました。
| 段階 | 中身 |
|---|---|
| ステップ2 | 一般に公開するために必要なもの(ログイン、管理者、上限、アカウントの画面、退会、エクスポート、規約など) |
| ステップ3 | 共有(キャンプ履歴やおすすめ情報をほかの人に見せる、公開範囲) |
| 課金 | 有料会員・休止。公開のあとでもよい |
共有は将来やりたい機能ですが、最初の公開には要りません。「共有を見すえて、今やっておかないと困るもの」だけをステップ2 に入れることにしました。聞いてみると、それは2つだけでした。
- 表示名:Google の名前(本名のことが多い)とは別に持つ
- 規約の書き方:「登録した内容は、初めは自分だけが見られる。公開は、本人が選んだものに限る」と書いておく
公開範囲の列や、ほかの人のデータを読む仕組みは、共有を作るときに足せば間に合います。
会員区分は、3つの軸に分ける
将来は「フリー会員」「有料会員」「管理者」を作りたいと考えています。冬はキャンプに行かないので、有料会員が休める「休止」も欲しいところです。
最初は、これを1つの区分に並べるつもりでした。Claude Code の案は、3つの軸に分けるものでした。
| 軸 | 値 | 誰が変えるか |
|---|---|---|
| 権限 | 一般/管理者 | 自分(運営)だけ |
| プラン | フリー/有料 | 本人が申し込む・解約する |
| 契約の状態 | 有効/休止/支払い遅れ/解約済み | 本人と Stripe |
1つに並べると、「管理者が有料の機能を試す」「有料会員が冬だけ休む」といった組み合わせで困ります。軸を分けておけば、画面やサーバーが見るのは、そこから決まる「今の扱い」だけで済みます。
もう1つ、先に決めたことがあります。上限を超えたデータは消さない、です。有料からフリーに戻って上限を超えていても、見る・チェックする・編集するはできます。止めるのは、新しく足すことだけです。休止や解約が怖くなければ、戻ってきやすいと考えました。
ログインは、最初から Better Auth にする
ハコヅミは、ここまで Cloudflare Access(ログインした人だけが開ける仕組み)の後ろで、自分1人で使ってきました。全部のテーブルの user_id には、固定の値 owner を入れています。
知り合いだけに使ってもらうなら、Access で招待する手もありました。ただ、それでは利用者ごとにデータを分けられません。遠回りせず、最初から Better Auth を入れることにしました。ログインの方法は、Google アカウントだけです。パスワードを預からずに済みます。
user_id は、メールアドレスにしない
Issue の下書きを読んで、1つ確かめました。user_id は、メールアドレスではなく、ランダムな値になるのか、という点です。
答えは、Better Auth が作るランダムな値でした。メールアドレスを id にすると、アドレスを変えたときに全部のデータを付け替えることになります。将来、共有の URL に id が出ても、メールアドレスは漏れません。
今のデータは、いったん消す
owner のデータを、新しい自分の id に付け替えるマイグレーションも考えました。ただ、id が決まるのは、初めてログインしたあとです。マイグレーションの時点では分かりません。
今のデータは、Notion から取り込んだものに、試しに足したサンプルです。消してしまって、ログインのあとに Notion から取り込み直すことにしました。取り込みのスクリプトは、#7で作ったものです。「全員の分を消して入れ直す」作りだったので、渡したユーザーの分だけを入れ直す形に直しています。
人が先に済ませておくこと
実装の前に、人がダッシュボードで済ませることが2つありました。
- Google Cloud で、OAuth のクライアントを作る(開発用と本番用)
- Worker の Secrets に、3つの値を入れる(Better Auth の秘密、Google のクライアント ID とシークレット)
秘密の値は、チャットには貼らないことにしています。手順だけを Claude Code に聞いて、値は自分でダッシュボードに入れました。手元で動かすときの値は .dev.vars に書き、Git の対象から外しています。
実装で気をつけたこと

ログインの画面。ログインしていないときは、ヘッダーのメニューを出さない
「誰がログインしているか」を決める場所は、1か所
今までも、user_id を決める場所は src/hooks.server.ts だけにしていました。そこを、固定の値から Better Auth のセッションに差し替えています。ログインしていなければ、ログインの画面と Better Auth の処理のほかは、すべてログインの画面に移します。
ページの側は、今までどおり locals.userId を使うだけです。ページのコードは、ほとんど変えずに済みました。
戻る先は、アプリの中だけ
ログインの画面に移すときは、もとの URL を redirectTo に付けて、ログインのあとに戻れるようにしています。ここは、悪用されやすいところです。//example.com のような値を受け付けると、ログインのあとに別のサイトへ飛ばされます。
戻る先として受け付けるのは、アプリの中のパスだけにしました。判定は関数に切り出して、ユニットテストしています。
セッションは30日
ハコヅミを使うのは、車に荷物を積んでいるときです。そこでログインし直しになると困ります。セッションは30日にして、使うたびに延びるようにしました。
E2E は、Google に行かない
E2E テストで、本物の Google のログインは通せません。そこで、テスト用のユーザーとセッションを、テストの前にローカルの D1 に入れておきます。Better Auth と同じ形で署名したクッキーを、全部のテストのブラウザに付けます。
つまずいた点が2つありました。
Google へ移るところを、止められない
「Google でログイン」を押すと、Google の画面へ移ります。テストでは、移る先の URL だけを確かめたいところです。Playwright の page.route() で止めようとしましたが、サーバーからのリダイレクトは止まりませんでした。
結局、フォームを直接送り、リダイレクトを追わずに、応答の location を確かめる形にしています。
秘密の値を探すテストが、自分に引っかかる
「秘密の値がリポジトリに入っていない」ことを確かめるテストも書きました。Google のクライアント シークレットの形の文字を、全部のファイルから探します。
ところが、テストのコメントに、探している文字の例を書いていました。テストのファイルをコミットしたとたんに、自分自身に引っかかって落ちます。コメントを直して通しました。
取り込み直しと、本番での失敗
マージして、開発環境でログインし、Notion から取り込み直しました。ここでも、細かくつまずいています。
- ファイル名の空白:Notion から書き出した CSV は、名前に空白が入っています。引用符で囲まずにコマンドに渡して、「ファイルがない」と言われました
- コンソールに貼るもの:SQL をクリップボードに入れる
pbcopyのコマンドごと、D1 のコンソールに貼ってしまいました(エラーになるだけで、害はありません)。#7でも、同じような間違いをしています
取り込みのあと、開発用の D1 を見ると、ギア 56 件・コンテナ 6 件が、自分の新しい id で入っていました。
本番でログインできない
本番リリースのあと、本番でログインすると、「ログインできませんでした」と出ました。URL には error=invalid_code と付いています。
Google から戻ってきたあと、サーバーが Google に「このコードを、トークンに換えてほしい」と頼むところで、断られていました。原因は、本番の Worker に入れた、Google のクライアント シークレットの入れ間違いです。入れ直すと、ログインできました。
この失敗で、画面に出る理由が「ログインできませんでした」だけでは、何が起きたか分からないことにも気づきました。あとで直す候補に入れてあります。
おわりに
- 段階の名前より、「何ができたら次に進むか」で区切る。ステップ2 は「一般に公開できる」まで
- 区分は、変える人が違うものを別の軸にする
user_idは、ランダムな値にする。メールアドレスは変わるし、漏らしたくない- 「誰がログインしているか」を決める場所が1か所なら、ログインの仕組みを入れ替えても、ページは変えずに済む
- E2E のログインは、本物を通さず、署名したクッキーを付ける
次回は、1回に10分近くかかるようになっていた E2E を、速くした話です。