バージョン 4.x チェンジログ
注目すべき点
- バージョン番号を取得するには、
package.jsonファイルのversionフィールドを確認してください- 3.x のチェンジログについては、バージョン 3.x チェンジログを参照してください
4.0.0
4.0.0 は書き直しレベルのアップグレードです。決済・クレジット・チームの 3 モジュールが全面的に作り直され、価格データはデータベースからコードへ移され、データベースのマイグレーションファイルはベースラインから再構築されました。3.x からのアップグレードは pnpm install だけでは完了しません。まず下記の「破壊的変更」をお読みください。
破壊的変更(3.x からのアップグレード時は必読)
- 価格をデータベースに保存しなくなりました:
pricing_plans、pricing_plan_groupsの 2 テーブルを削除し、管理画面の価格管理ページ(/dashboard/admin/prices配下の全ファイル)も削除しました。価格の唯一の情報源はconfig/pricing.tsになります - クレジット関連テーブルの再構築:
usage、credit_logsを削除し、credit_balances、organization_credit_balances、credit_transactionsを追加しました - 組織関連テーブルの追加:
organization、member、invitation(Better Auth organization プラグイン)
価格:データベースからコードへ
- 追加:
config/pricing.tsを価格の唯一の情報源としました。1 プラン = 1 オブジェクトで、プロバイダー、プロバイダー側の価格 ID({ test, live }の 2 環境分)、付与クレジット、en/zh/ja の 3 言語コピーをすべて同じ場所に記述します。i18n ファイルに散在しなくなりました - 追加:
config/credits.tsは決済以外のクレジット付与ルールを保持します。現時点では登録ボーナスsignupBonusCredits(デフォルト 30、0 にすると無効)です - 追加:各プランは
providerフィールドでどのプロバイダーが決済を処理するかを宣言し、対応するフィールドに値を入れます:stripePriceId/creemProductId/paypalPlanId - 追加:
scripts/bootstrap-stripe-prices.ts(pnpm stripe:bootstrap)。設定ファイルをもとに Stripe 側で価格を一括作成します - 改善:価格コンポーネントを
PricingSection/PricingCard/CheckoutButtonの 3 点セットに書き直し、従来のPricingAll/PricingByGroup/PricingByPaymentType/PricingCardDisplay/PricingCTAを削除しました - 規約:
planIdは再利用せず、販売実績のあるプランは削除しません(過去の注文とクレジット履歴がこれを通じて解決されるため)。提供終了はactive: falseで行います
決済のフルフィルメント:統一された lib/billing
- リファクタ:
lib/billing/を追加し、3 プロバイダーの Webhook イベントをプロバイダー非依存のフルフィルメントコアに集約しました。従来のlib/payments/、app/api/*/webhook/handlers.ts、app/api/payment/verify-success/*はすべて削除されていますtypes.ts:統一されたサブスクリプションステータスCanonicalSubscriptionStatusと各種フルフィルメント入力。金額は常に整数のセント単位ですfulfillment.ts:プロバイダー非依存のコア —— 買い切り購入、サブスクリプション支払い、プラン変更、サブスクリプション同期、サブスクリプション終了、返金stripe.ts/creem.ts/paypal.ts:プロバイダーごとに 1 つのアダプター。Webhook ペイロードをコアの入力へ変換するだけの責務で、SDK の型は外に漏れませんcancel.ts:cancelProviderSubscriptionによる統一キャンセル実装。3 プロバイダーそれぞれの「すでにキャンセル済み」エラーを許容しますduplicate.ts:重複サブスクリプションの決着 —— 後から作られた方をキャンセルし、返金し、Redis で重複排除したうえでアラートします。返金に失敗した場合は例外を投げ、プロバイダー側のリトライに委ねますreconcile.ts:失われた Webhook を補償する定期照合(更新の再実行 + PayPal の保留中キャプチャの前進)notify.ts:Webhook を起点とする通知(付与失敗の管理者アラート、更新失敗のユーザー通知、不正検知アラート)。すべて Redis で重複排除されますcustomer.ts:stripeCustomerIdの唯一の読み書き経路。古い ID を検出した場合は自動修復します
- 追加:サブスクリプションのアップグレード(プラン変更)は差分フルフィルメントを通り、差額分のクレジットを付与したうえでアップグレード通知を送ります
- 追加:PayPal eCheck などの保留中決済は、まず
status='pending'の注文行として記録され、定期実行によって成功または失敗へ前進します - 追加:管理画面の注文ページから返金操作が行えるようになりました(
RefundDialog) - 改善:冪等性を防御的なチェックではなく構造として担保します ——
orders(provider, provider_order_id)の一意インデックス +onConflictDoNothing+ 返金累計額 - 改善:返金は新しい行を追加するのではなく、元の注文行を書き換えます
- 改善:Webhook ルートは薄いままに保ちます —— リトライ可能なエラーは 5xx を返し、
PermanentFulfillmentErrorはアラート後に ack します - 改善:Creem SDK を 0.4 から 1.6 へアップグレードし、
@creem_io/nextjsを削除、lib/creem/client.tsと型定義を大幅に整理しました
クレジットシステムの書き直し
- リファクタ:
lib/credits/を追加しました。残高はledger.tsを通じてのみ変更でき、credit_transactionsは追記専用ログ(差分 + スナップショット + 連番)です - 追加:2 バケットモデル —— サブスクリプションクレジット(付与のたびにリセットされ、サブスクリプション終了時にクリア)と購入クレジット(無期限)。消費はサブスクリプションバケットから先に引かれます
- 追加:年額プランの月次ドリップ付与 —— 初月は即時付与し、残り 11 回を毎月配分します。定期実行と遅延決済が同じ入口を共有し、行ロックと再チェックにより同時実行でも付与は 1 回だけです
- 追加:
app/api/cron/creditsの定期実行エンドポイント(POST+Authorization: Bearer $CRON_SECRET)。クレジットのドリップ決済、更新遅延の照合、PayPal 保留中キャプチャの照合を担います - 追加:登録ボーナスクレジット。同一トランザクション内で重複を判定するため、再実行しても影響はありません
- 追加:
app/[locale]/(protected)/dashboard/credit-usage-example/にクレジット消費のサンプルを追加しました - 改善:残高がマイナスになることはありません。回収系の操作は 0 で打ち止めになります
チーム / 組織
- 追加:Better Auth organization プラグインによるチーム機能。組織が課金主体となり、1 つのクレジットプールを共有します(
organization_credit_balances) - 追加:
/dashboard/teamチーム管理ページ —— サブスクリプション、共有クレジットプール、メンバーとシート、クレジット履歴の 4 カード構成。チーム未作成の場合は作成/選択のオンボーディングに進みます - 追加:
components/shared/WorkspaceSwitcher.tsxによる個人/チームワークスペースの切り替え - 追加:メールによるチーム招待。
emails/organization-invitation.tsxテンプレートと/accept-invitation/[id]の受諾ページを備えます - 追加:シート上限はチームプランの
seats、サブスクリプションがない場合は 1(オーナーのみ)です。4 つの Better Auth フックで事前チェックを行い、さらにアドバイザリロックと超過分の回収で同時実行を補償します - 追加:組織削除のガード —— 有効なサブスクリプションまたは資金履歴が存在する場合は削除を拒否します。外部キーの
RESTRICTがデータベース層の最終防衛線です - 規約:チームワークスペースではクレジットパックを販売しません。資金関連の行はユーザー削除時に
SET NULL、組織削除時にRESTRICTとなります
管理画面
- 追加:クーポンコンソール
/dashboard/admin/coupons。Stripe が唯一のストアで、ローカルにテーブルもマイグレーションも作りません —— 1 クーポン = Stripe Coupon(割引、適用範囲、課金期間)+ Stripe Promotion Code(顧客向けコード、利用回数上限、有効期限、制限条件)。コードは作成後に変更できないため、UI が提供するのは有効/無効の切り替えと「複製してから編集」だけです - 追加:クレジット管理ページ
/dashboard/admin/credits。全体のクレジット履歴の監査ビューと、メールアドレス指定の一括付与(重複排除、1 回あたり最大 200 件、一致しなかったアドレスは返却)を備えます - 追加:ユーザー詳細ページ
/dashboard/admin/users/[userId]。1 ユーザーの 360 度ビュー(プロフィール、クレジット残高、サブスクリプション、累計統計と履歴)で、クレジットの手動調整にも対応します - 追加:登録メールのブロックリスト —— 管理画面でプレフィックス / サフィックス / 完全一致の 3 種類のルールを管理し、Redis に保存します。登録フックは小文字化した元の形式と正規化後の形式の両方を照合し、Gmail のドットや
+サフィックスによる回避を防ぎます。読み取りに失敗した場合は空ルールへ静かにフォールバックし、正当な登録を妨げません - 追加:ユーザーアカウント削除時に、まずそのユーザーの R2 アセットを削除します(
lib/storage/account-purge.ts)。削除に失敗した場合はアカウント削除を中止します - 刷新:Overview(概要)ページ。単一の時間ウィンドウ(
?range=7d|30d|90d、UTC 暦日)がページ全体を駆動し、5 つのセクションがそれぞれの Suspense 境界で並列にストリーミングされるため、1 つのセクションの失敗がページ全体を巻き込みません- KPI 行:純収益、MRR、新規登録、クレジット消費
- トレンドチャート:メトリクスタブ付きの単系列棒グラフ(切り替え時に再取得しません)
- 要対応:支払い遅延中のサブスクリプション、保留中の注文、期末解約予定、未対応のフィードバック、失敗した注文、基準通貨以外の注文。各行は対応する管理ページへ直接遷移します
- 分布カード + 直近 8 件の注文
- 集計基準:金額は整数セント、純収益 = 総額 − 返金、保留中/失敗は収益に含めない、基準通貨は価格設定で最初に有効なプランの通貨、登録数は匿名アカウントを除外、クレジット消費 = 消費 − 消費の払い戻し、MRR = active + past_due を設定上の月額レートで換算
- 改善:データテーブルのコンテナと各管理ページのレイアウトを統一し、モバイルでのレスポンシブ対応を改善しました
ユーザー画面
- 追加:
/dashboard/billing請求ページ —— 2 つのクレジットバケット、現在のプラン、購入履歴とクレジット履歴(2 つのテーブルは独立してページングします)。チームワークスペースでは上部バナーが/dashboard/teamへ誘導します - 刷新:
components/layout/SidebarUserCard.tsxが従来のSidebarUserNavとCurrentUserBenefitsDisplayを置き換え、サイドバーにクレジット残高を直接表示します - 追加:
--creditテーマカラー(コインゴールド)。ライト/ダークテーマで役割が入れ替わります
その他
- 追加:
/api/healthヘルスチェックエンドポイント。依存サービスを並列にプローブし、結果を単一の HTTP ステータス(200 / 503)に畳み込みます。未設定の依存は失敗ではなくskippedとして記録されます。意図的に公開かつ意図的に不透明な設計で、シークレットを必要とせず、エラー文字列・バージョン・ホスト名も返しません - 追加:
components/shared/DomTranslationGuard.tsx。ブラウザのページ全体翻訳に起因する React DOM のクラッシュを防御的に処理します - 改善:フォント体系を整理し、
@fontsource/science-gothicを削除して、Header・Footer・サイドバーなどのコンポーネントでフォントの使い方を統一しました - 改善:リポジトリ内のすべての
CLAUDE.mdとコードコメントを英語で書き直しました
依存関係のアップグレード
- Next.js
16.1.1→16.3.3 - React
19.2.3→19.2.8 - creem
0.4.0→1.6.0(@creem_io/nextjsを削除) - cloudflare
6.4.0→7.1.0 - Drizzle ORM 0.44(PostgreSQL、
publicスキーマ) - Better Auth 1.4(organization プラグインを有効化)