Chiapuru.comにメンバーシップ機能を実装しました
「会員限定のコンテンツを配信したい」
ブログやツールを公開していると、いずれ出てくる要望です。
今回、Google OAuth + Supabaseを使った無料会員登録機能を実装し、本番環境へのデプロイまで完了しました。
何ができるようになったか
- Googleアカウントでワンクリックログイン
- ダッシュボードでメンバーシップ情報を確認
- メンバー限定ブログ・メンバー限定ツールへのアクセス
- 未ログインユーザーはサインインページへ自動リダイレクト
技術スタック
| レイヤー | 技術 |
|---|---|
| 認証 | NextAuth v4 + Google OAuth |
| データベース | Supabase (PostgreSQL) |
| セッション | JWT (httpOnly Cookie) |
| ルート保護 | Next.js Middleware |
| フロントエンド | Next.js 15 App Router |
仕組み
ログインの流れはシンプルです:
- ユーザーが「Sign in」をクリック
- Googleアカウントで認証
- NextAuthの
signInコールバックでSupabaseにメンバーシップを自動作成 - ダッシュボードにリダイレクト
メンバー限定コンテンツの保護は2段階で行っています:
- Middleware:
/member-only-*と/dashboard/*へのアクセスを早期にブロック - Server Component:
getServerSession()で二重チェック
Claude Codeとの開発
今回の実装はClaude Codeをフル活用しました。
特に助かったのは:
- Supabase URLの形式ミスを発見・修正(ダッシュボードURLとAPI URLの違い)
- ビルドエラーの即座な対応(
useSearchParams()のSuspenseラップ、Supabaseクライアントの遅延初期化) - 10箇所の改善点を一括で洗い出し・修正
1人で作業していたら半日以上かかる作業が、数時間で完了しました。
苦労したポイント
Vercelビルドでの環境変数問題
ローカルでは動くのに、VercelのビルドでsupabaseUrl is requiredエラー。
原因は、Supabaseクライアントがモジュール読み込み時に初期化されるため、環境変数が未設定のビルドフェーズでクラッシュしていたこと。
解決策:遅延初期化パターンに変更。クライアントを関数呼び出し時に初めて生成するようにしました。
Supabase URLの形式
Supabaseのダッシュボード画面のURL(https://supabase.com/dashboard/project/...)をAPI URLと間違えて設定していました。正しくはhttps://<project-ref>.supabase.coの形式です。
今後の展開
現在は無料会員のみですが、将来的には:
- プレミアム会員の導入(Stripe連携)
- メンバー限定コンテンツの拡充
- 会員向けメール通知
まずはメンバー限定のブログ記事やツールを充実させていきます。
まとめ
Google OAuth + Supabaseの組み合わせは、個人開発のメンバーシップ機能としてちょうどいいバランスです。無料枠の範囲で十分に運用できます。
興味のある方は、ぜひサインインしてみてください!