Chat Story 実装ガイド
対象サービス: https://chat-story.number55number55.workers.dev/
作成日: 2025年12月11日
プラットフォーム: Cloudflare Workers
概要
本ドキュメントは Chat Story サービスに以下の機能を実装するための技術選定と実装方針をまとめたものです。
| 機能 | 推奨技術 | 代替選択肢 |
|---|---|---|
| 認証(Auth) | Better Auth | Clerk, Auth0, Lucia |
| 決済(Payment) | Polar.sh | Creem.io, Stripe + Tax |
| メール送信 | Resend | SendGrid, Mailgun |
1. 認証(Authentication): Better Auth
選定理由
Better Auth は TypeScript 向けの包括的な認証フレームワークで、以下の特徴があります。
- フレームワーク非依存: React, Vue, Svelte, Astro, Hono など多くのフレームワークに対応
- 豊富な機能が標準搭載: 2FA, パスキー, マルチテナント, セッション管理など
- プラグインエコシステム: 機能拡張が容易
- ユーザーあたりの課金なし: Auth0/Clerk と違い、ユーザー数に関係なく無料
- データは自分のDB: ユーザーデータがサードパーティに渡らない
料金
| 項目 | Better Auth | Auth0 | Clerk |
|---|---|---|---|
| 基本料金 | 無料(OSS) | 無料〜$35/月 | 無料〜$25/月 |
| MAU課金 | なし | 7,000MAU以降課金 | 10,000MAU以降課金 |
| セルフホスト | ◯ | × | × |
主要機能
✅ メール/パスワード認証
✅ ソーシャルログイン(Google, GitHub, Discord, Twitter など)
✅ 2要素認証(2FA)
✅ パスキー / WebAuthn
✅ マジックリンク
✅ セッション管理
✅ マルチテナント / 組織管理
✅ レート制限
実装例(Cloudflare Workers + Hono)
// auth.ts
import { betterAuth } from "better-auth";
import { D1Adapter } from "better-auth/adapters/d1";
export const auth = betterAuth({
database: D1Adapter(env.DB),
emailAndPassword: {
enabled: true,
},
socialProviders: {
google: {
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
},
},
});
// クライアント側
import { createAuthClient } from "better-auth/client";
export const authClient = createAuthClient({
baseURL: "https://chat-story.number55number55.workers.dev",
});
// サインアップ
await authClient.signUp.email({
email: "user@example.com",
password: "securepassword",
name: "User Name",
});
// サインイン
await authClient.signIn.email({
email: "user@example.com",
password: "securepassword",
});
セットアップ手順
- パッケージインストール
npm install better-auth - DBスキーマ生成
npx @better-auth/cli generate npx @better-auth/cli migrate - 環境変数設定
BETTER_AUTH_SECRET=your-secret-key GOOGLE_CLIENT_ID=xxx GOOGLE_CLIENT_SECRET=xxx
参考リンク
- 公式ドキュメント: https://www.better-auth.com/docs
- GitHub: https://github.com/better-auth/better-auth
- LLMs.txt(AI向け): https://better-auth.com/llms.txt
2. 決済(Payment): Polar.sh
Stripe vs MoR(Merchant of Record)の違い
決済システムを選ぶ際、最も重要な判断ポイントは Stripe(決済代行) か MoR(販売代行) かの選択です。
| 項目 | Stripe(決済代行) | Polar.sh / Creem(MoR) |
|---|---|---|
| 法的な販売者 | あなた | MoR事業者 |
| 税務処理(VAT/GST) | 自分で申告・納付 | 自動で全世界対応 |
| 手数料 | 約3.6% | 約4% + 40¢ |
| 請求書発行 | 自分で対応 | 自動発行 |
| チャージバック対応 | 自分で対応 | MoRが対応 |
| コンプライアンス | 自分で対応 | MoRが対応 |
推奨: Polar.sh
選定理由
- オープンソース(Apache 2.0)で透明性が高い
- 手数料が安い: 4% + 40¢(従来MoRより20%安い)
- 開発者向け機能が充実:
- ライセンスキー自動発行
- GitHubリポジトリアクセス管理
- Discordロール自動付与
- ファイルダウンロード配信
- DXが優秀: API/SDK設計が洗練されている
- $10M調達済み(Accel主導)で信頼性あり
料金体系
基本手数料: 4% + 40¢ / 取引
- 追加の国際カード手数料: なし
- 月額固定費: なし
- 初期費用: なし
主要機能
✅ サブスクリプション(定期課金)
✅ 単発購入
✅ 使用量ベース課金(Usage-based billing)
✅ グローバル税務コンプライアンス(VAT/GST/消費税)
✅ ライセンスキー発行
✅ ファイル配信(最大10GB)
✅ 顧客ポータル
✅ Webhook
✅ 分析ダッシュボード
実装例
// サーバー側: チェックアウトセッション作成
import { Polar } from "@polar-sh/sdk";
const polar = new Polar({
accessToken: env.POLAR_ACCESS_TOKEN,
});
// チェックアウトURL生成
const checkout = await polar.checkouts.create({
productId: "prod_xxx",
successUrl: "https://chat-story.../success",
customerEmail: user.email,
});
return Response.redirect(checkout.url);
// Webhook処理
app.post("/webhook/polar", async (c) => {
const payload = await c.req.json();
const signature = c.req.header("polar-signature");
// 署名検証
const event = polar.webhooks.constructEvent(payload, signature, env.POLAR_WEBHOOK_SECRET);
switch (event.type) {
case "subscription.created":
// サブスクリプション開始処理
await activatePremium(event.data.customer.email);
break;
case "subscription.canceled":
// サブスクリプション解約処理
await deactivatePremium(event.data.customer.email);
break;
}
return c.json({ received: true });
});
代替選択肢: Creem.io
Polar.sh が合わない場合の代替として Creem.io も検討可能です。
| 項目 | Polar.sh | Creem.io |
|---|---|---|
| 手数料 | 4% + 40¢ | 3.9% + 40¢ |
| オープンソース | ◯ | × |
| PMF前無料 | × | ◯(0%手数料) |
| 主なターゲット | 開発者・OSS | SaaS全般 |
| 設立 | 2023年 | 2024年 |
参考リンク
- Polar.sh: https://polar.sh
- Polar Docs: https://docs.polar.sh
- Creem.io: https://creem.io
3. メール送信: Resend
選定理由
Resendは開発者向けに設計されたモダンなメールAPIサービスです。
- React Email統合: Reactコンポーネントでメールテンプレート作成
- 優れたDX: シンプルなAPI、充実したSDK
- 高い到達率: SPF/DKIM/DMARC対応、専用IPオプション
- リアルタイム追跡: 開封、クリック、バウンスのWebhook通知
- 無料枠が充実: 月3,000通まで無料
料金体系
| プラン | 月額 | 送信数 | 特徴 |
|---|---|---|---|
| Free | $0 | 3,000通/月 | 開発・小規模向け |
| Pro | $20 | 50,000通/月 | SSO対応 |
| Scale | $100 | 200,000通/月 | 専用IP(オプション) |
Chat Story での活用シーン
📧 ウェルカムメール(新規登録時)
🔐 パスワードリセット
🔔 サブスクリプション開始/解約通知
📊 利用状況レポート
💳 決済完了/失敗通知
実装例
基本的なメール送信
import { Resend } from "resend";
const resend = new Resend(env.RESEND_API_KEY);
// シンプルなメール送信
await resend.emails.send({
from: "Chat Story <noreply@chat-story.com>",
to: user.email,
subject: "Chat Storyへようこそ!",
html: `
<h1>ご登録ありがとうございます</h1>
<p>${user.name}さん、Chat Storyへようこそ!</p>
`,
});
React Emailでテンプレート作成
// emails/welcome.tsx
import { Html, Head, Body, Container, Heading, Text, Button } from "@react-email/components";
export function WelcomeEmail({ name, loginUrl }: { name: string; loginUrl: string }) {
return (
<Html>
<Head />
<Body style={{ fontFamily: "sans-serif" }}>
<Container>
<Heading>ようこそ、{name}さん!</Heading>
<Text>Chat Storyへのご登録ありがとうございます。</Text>
<Button href={loginUrl} style={{ background: "#3b82f6", color: "#fff", padding: "12px 24px" }}>
ログインする
</Button>
</Container>
</Body>
</Html>
);
}
// メール送信
import { WelcomeEmail } from "./emails/welcome";
import { render } from "@react-email/render";
const html = await render(WelcomeEmail({
name: user.name,
loginUrl: "https://chat-story.../login"
}));
await resend.emails.send({
from: "Chat Story <noreply@chat-story.com>",
to: user.email,
subject: "Chat Storyへようこそ!",
html,
});
Better Auth との統合
// auth.ts
import { betterAuth } from "better-auth";
import { Resend } from "resend";
const resend = new Resend(env.RESEND_API_KEY);
export const auth = betterAuth({
emailAndPassword: {
enabled: true,
sendResetPassword: async ({ user, url }) => {
await resend.emails.send({
from: "Chat Story <noreply@chat-story.com>",
to: user.email,
subject: "パスワードリセット",
html: `<a href="${url}">こちらをクリックしてパスワードをリセット</a>`,
});
},
sendVerificationEmail: async ({ user, url }) => {
await resend.emails.send({
from: "Chat Story <noreply@chat-story.com>",
to: user.email,
subject: "メールアドレスの確認",
html: `<a href="${url}">こちらをクリックしてメールアドレスを確認</a>`,
});
},
},
});
セットアップ手順
- Resendアカウント作成: https://resend.com/signup
- ドメイン認証(DNS設定)
- APIキー取得
- パッケージインストール
npm install resend @react-email/components
参考リンク
- Resend: https://resend.com
- React Email: https://react.email
- Resend Docs: https://resend.com/docs
4. 実装フェーズとタスク
Phase 1: 認証(優先度: 高)
📝 Google OAuth の詳細な設定手順は Google OAuth 設定ガイド を参照
□ Better Auth セットアップ
□ D1データベーススキーマ作成
□ 認証エンドポイント実装
□ クライアント側認証フック作成
□ ログイン/サインアップUI作成
□ メール/パスワード
□ Google OAuth(オプション)→ [設定ガイド](/2025-12-11/google-oauth-setup-guide)
□ セッション管理
□ 保護されたルート実装
□ ログアウト処理
Phase 2: メール送信(優先度: 中)
□ Resend セットアップ
□ ドメイン認証
□ APIキー設定
□ メールテンプレート作成
□ ウェルカムメール
□ パスワードリセット
□ メール確認
□ Better Auth との統合
Phase 3: 決済(優先度: 中)
□ Polar.sh アカウント作成
□ 組織設定
□ 商品/プラン作成
□ チェックアウトフロー実装
□ 料金ページ作成
□ チェックアウトリダイレクト
□ 成功/キャンセルページ
□ Webhook処理
□ エンドポイント作成
□ サブスクリプション状態管理
□ 顧客ポータルリンク
5. 環境変数一覧
# Better Auth
BETTER_AUTH_SECRET=your-32-char-secret
BETTER_AUTH_URL=https://chat-story.number55number55.workers.dev
# Google OAuth(オプション)
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxx
# Resend
RESEND_API_KEY=re_xxx
# Polar.sh
POLAR_ACCESS_TOKEN=polar_xxx
POLAR_WEBHOOK_SECRET=whsec_xxx
POLAR_ORGANIZATION_ID=org_xxx
6. 参考リソース
公式ドキュメント
| サービス | URL |
|---|---|
| Better Auth | https://www.better-auth.com/docs |
| Polar.sh | https://docs.polar.sh |
| Resend | https://resend.com/docs |
| React Email | https://react.email/docs |
ボイラープレート・サンプル
- SaaSKit (TanStack Start): https://github.com/saaskit
- Better Auth Examples: https://github.com/better-auth/better-auth/tree/main/examples
Cloudflare Workers 関連
- Hono + Cloudflare Workers: https://hono.dev/getting-started/cloudflare-workers
- D1 Database: https://developers.cloudflare.com/d1/
7. 注意事項・Tips
認証
- セッショントークンは HttpOnly Cookie で管理(XSS対策)
- CSRF対策は Better Auth が自動対応
- パスワードは Argon2 でハッシュ化(Better Auth標準)
決済
- 本番環境移行前にテストモードで十分にテスト
- Webhookは冪等性を考慮した実装を
- 日本での消費税はPolar.shが自動処理
メール
- 送信ドメインは必ず認証(SPF/DKIM)
- 開発中はテストモードでリアル送信を防止
- バウンスメールの自動処理を設定
このドキュメントは Chat Story サービスの実装ガイドとして作成されました。技術選定は2025年12月時点の情報に基づいています。