メインコンテンツへスキップ
友田 陽大
決済・課金
Stripe
決済
サブスクリプション
Next.js
TypeScript
B2B SaaS
冪等性

Stripe Billing 実装ガイド(2026年版・公式準拠):サブスク・従量課金(Billing Meters / Metronome)・顧客ポータル・プロレーションを実コードで

Stripe Billing公式準拠の実装ガイド。サブスク開始(Checkout / Subscriptions API)、従量課金(Billing Meters)、Customer Portal、プロレーション、Webhook冪等処理をNext.js 16 + TypeScriptの実コードで解説。

公開日
読了時間
20分
著者
友田 陽大
シェア

単発の決済が「お金を1回受け取る」問題なら、サブスクリプションは「時間軸に沿って、正しい金額を、毎回、欠かさず受け取る」問題です。難しさの本質は、状態が時間とともに変わり続けること——トライアルが切れ、カードが期限切れになり、プランが途中でアップグレードされ、リトライが走り、解約が予約される——にあります。ここを構造で押さえないと、「請求漏れ」「過剰請求」「アクセス権の不整合」が静かに積み上がります。

この記事は、Stripe公式ドキュメントの最新仕様に忠実でありながら、「どの場面で・なぜ・どう使うか」がわかるように書いた Billing(サブスク/請求)専門の実装ガイドです。執筆時点の最新 API バージョンは 2026-05-27.dahlia。サンプルは Next.js 16(App Router / RSC / Server Actions)+ TypeScript strict で示します。

決済受け入れの基礎(Checkout Sessions・署名検証・Webhookの2層冪等モデル)は本記事では再説明しません。 そちらは姉妹記事「Stripe決済を本番品質で実装する完全ガイド(2026年版)」に分離しています。本記事は サブスク特有の論点——構成要素・従量課金・プロレーション・顧客ポータル・ライフサイクルWebhook——に集中します。

筆者の実務背景:私は Next.js 16.1 + Stripe 17 で本番サブスクリプション基盤を構築しました。Webhookは event.id の一意制約+event.created による順序保証+再帰的なPII墨消しで冪等化、マルチチャネルの料金計算は純粋関数として実装、銀行振込のサブスク状態を状態機械でモデル化し、433本のテストで守っています。加えて、環境分野のサーバーレス決済プラットフォームで信頼性レイヤーを主導し 本番二重課金0件 を達成しました。本文のStripe仕様はすべて公式ドキュメントで裏取りし、MRR・チャーン・ROIといった未確認数値は扱いません。


1. サブスクリプションの構成要素

Stripe Billing は5つのオブジェクトの組み合わせです。ここを曖昧にしたまま実装に入ると、後で「どこにアクセス権の真実があるのか」が分からなくなります。

オブジェクト役割重要ポイント
Customer請求情報の入れ物支払い方法・住所・次回以降の請求先を保持。あなたのDBの user に1対1で紐づける
Product売る対象(プラン名など)「Proプラン」「Businessプラン」といった概念。Entitlements(機能アクセス)と紐づく
Pricerecurring な金額・通貨・周期「月額 ¥1,980」「年額 ¥19,800」。1つのProductに複数Price(月/年、通貨違い)を持てる
SubscriptionCustomer と Price を結ぶ継続関係ライフサイクル(trialing→active→past_due…)の主体。アクセス権判定はここ
Invoice各請求周期の請求書毎周期 Stripe が自動生成。PaymentIntent を内包し、支払い結果が status に反映される

関係を図にすると次の通りです。

Customer
 └─ Subscription ── Price (recurring) ── Product
       └─ Invoice(毎周期) ── PaymentIntent(支払い処理)

Subscription.status の遷移は実装の生命線です。公式の定義を要約します。

status意味アクセス権
trialingトライアル中(まだ課金なし)付与(試用)
active正常。最新請求書が支払い済み付与
incomplete初回支払い未確定(最大23時間の猶予)保留
incomplete_expired初回支払いが23時間以内に確定せず失効付与しない
past_due最新請求書の支払い失敗。リトライ中要ポリシー判断(猶予 or 制限)
unpaidリトライ枯渇。最新請求書が未払いのまま剥奪
canceled解約済み(最終・不変)剥奪
pausedトライアル終了時に支払い方法が無く一時停止剥奪

設計の勘所:自前のDBに「有効/無効」フラグを二重に持たない。真実は Subscription.status であり、あなたのDBはそのキャッシュです。Webhookで同期し、判定ロジックは1箇所に集約します(§7・§8)。


2. サブスク開始:Checkout か Subscriptions API か

サブスクの「開始」には2つの道があります。公式の立場は明快で、Checkout が最小実装・推奨、Subscriptions API直接叩きはフル制御が要るときのみです。

観点Checkout(mode: 'subscription'Subscriptions API 直接
実装量最小大(支払い方法の収集・確定を自前で)
支払いUIStripeホスト型 / 埋め込み型Payment Element を自前で組む
税・割引・支払い方法保存組み込み手動設定
向く場面MVP・標準フロー・早く安全に決済UXが事業の核・独自の状態管理が必要

2-A. 推奨:Checkout Session(mode: 'subscription')

決済受け入れの基礎(リダイレクト型/埋め込み型・success_url・署名検証)は基礎記事に譲ります。サブスク化で変わるのは、mode: 'subscription' にし、line_items に recurring な Price を渡す点だけです。

// app/actions/start-subscription.ts
"use server";

import Stripe from "stripe";
import { redirect } from "next/navigation";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function startSubscription(formData: FormData): Promise<void> {
  const priceId = String(formData.get("priceId"));
  // 顧客は自サイトの認証済みユーザーから解決する(クライアントの値は信用しない)
  const customerId = await resolveStripeCustomerId(); // 自前: users → cus_xxx

  const session = await stripe.checkout.sessions.create(
    {
      mode: "subscription",
      customer: customerId,
      line_items: [{ price: priceId, quantity: 1 }],
      // トライアルや支払い方法保存はここで指定(§5)
      subscription_data: { trial_period_days: 14 },
      success_url: `${process.env.APP_URL}/billing/return?session_id={CHECKOUT_SESSION_ID}`,
      cancel_url: `${process.env.APP_URL}/pricing`,
    },
    // 同一ユーザーの二重作成を防ぐ決定的キー(送信側冪等性)
    { idempotencyKey: `sub-start:${customerId}:${priceId}:v1` },
  );

  if (!session.url) throw new Error("Checkout session URL missing");
  redirect(session.url); // Next.jsのredirectはthrowするので戻り値はvoidで良い
}

ポイントは3つ。①顧客IDはサーバーの認証情報から解決する(priceId ですらクライアント由来なら、許可されたPrice集合に対してホワイトリスト検証すべきです)。idempotencyKey は決定的にし、ダブルクリックやリトライでサブスクが二重生成されるのを防ぐ。③確定はこのリダイレクトではなくWebhookで行う(§7)。

2-B. フル制御:Subscriptions API 直接

支払いUIを自前のPayment Elementで完全制御したい場合は、サブスクを default_incomplete で作り、初回 Invoice の confirmation_secret をクライアントに渡して確定させます。

const subscription = await stripe.subscriptions.create(
  {
    customer: customerId,
    items: [{ price: priceId }],
    // 初回支払いが確定するまで incomplete に留める(推奨パターン)
    payment_behavior: "default_incomplete",
    payment_settings: { save_default_payment_method: "on_subscription" },
    // 初回InvoiceのPaymentIntent確定情報を展開して取得
    expand: ["latest_invoice.confirmation_secret"],
  },
  { idempotencyKey: `sub-create:${customerId}:${priceId}:v1` },
);

// この confirmation_secret をクライアントへ渡し、Payment Element で確定する
const invoice = subscription.latest_invoice;
// invoice.confirmation_secret をフロントの stripe.confirmPayment() に渡す

payment_behavior: "default_incomplete"重要です。これにより「サブスクは作ったが初回課金は未確定」という状態を安全に表現でき、3Dセキュア(requires_action)にも自然に対応できます。確定の合図はやはりWebhook(invoice.paid)です。


3. 従量課金(usage-based):2026年の正解

ここは2026年に推奨が変わったポイントなので、古い記事を鵜呑みにすると誤ります。公式ドキュメントの現在の立場は明確です。

「Metronome は Stripe の主力の従量課金プラットフォームであり、すべての新規実装で推奨されます。」 「基本的な従量課金(Billing Meters)は、すでに Billing Meters で顧客に課金している場合にのみ継続してください。」

つまり判断は次の通りです。

状況推奨
これから従量課金を新規実装するMetronome(Stripeの新しい従量課金基盤)
既存の定額サブスクに従量を足すが、Connect / Checkout / Adaptive Pricing / Workflows との完全互換が必要Billing Meters(Metronomeは一部サポートが限定的)
すでに Billing Meters で課金中そのまま Billing Meters を継続

本記事の方針:新規なら Metronome を検討する、という公式の推奨を尊重します。一方で多くの既存システムは Billing Meters 上にあるため、ここでは Billing Meters のメーターイベントの考え方を、冪等性に絞って解説します。API シグネチャの最終形は公式ドキュメントで必ず確認してください(後述の理由で、ここでは挙動を保守的に説明します)。

Billing Meters の考え方

Billing Meters では、集計(aggregation)はStripe側が担当します。あなたの責務は「いつ・誰が・どれだけ使ったか」を表すメーターイベントを送ることだけ。Price は「メーターに紐づくPrice」として定義され、請求周期末にStripeがイベントを合算して請求します。

メーターイベント送信で最重要なのが冪等性です。使用量の記録は「API呼び出しがネットワークで重複する」前提で設計しなければ、二重計上=過剰請求につながります。メーターイベントには冪等用の識別子identifier)を付与でき、同一識別子のイベントは重複排除されます。

// lib/usage/report.ts —— 使用量の冪等記録
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

type UsageEvent = {
  readonly eventName: string;        // メーター作成時に決めた event_name
  readonly stripeCustomerId: string; // cus_xxx
  readonly value: number;            // 今回の使用量(整数で扱う)
  readonly occurredAt: Date;         // 使用が発生した時刻
  readonly dedupeKey: string;        // 自システム側の決定的キー(例: 集計バッチID + 行ID)
};

export async function reportUsage(e: UsageEvent): Promise<void> {
  await stripe.billing.meterEvents.create({
    event_name: e.eventName,
    // payload のキーは作成したメーターの設定に合わせる(value / stripe_customer_id 等)
    payload: {
      value: String(e.value),
      stripe_customer_id: e.stripeCustomerId,
    },
    // 使用が発生した実時刻(請求周期の帰属を正しくするため)
    timestamp: Math.floor(e.occurredAt.getTime() / 1000),
    // ★冪等キー:同一値の重複イベントは排除される。リトライ安全。
    identifier: e.dedupeKey,
  });
}

設計上の鉄則は3つです。identifier を決定的に(タイムスタンプやUUIDのランダム生成ではなく、「集計バッチID+行ID」のように再送しても同じ値になるキー)。value は整数で扱い、丸めはアプリ側で確定させてから送る。timestamp は使用発生時刻——送信時刻ではなく発生時刻を使うことで、月末ギリギリの使用が翌月にズレ込む事故を防げます。

なぜここまで慎重か:私が運用してきた決済基盤で痛感したのは、**「お金に関わるイベントは exactly-once を構造で保証する」**という一点です。私のサブスク基盤ではマルチチャネルの料金計算を純粋関数化し、Webhookを event.id で冪等化しました。従量課金も同じ思想で、「再送・重複は正常系」として identifier で吸収します。


4. トライアル & プロレーション(日割り)

トライアル

最も簡単なのは trial_period_days。Checkoutなら subscription_data.trial_period_days、Subscriptions APIなら直接指定します(§2のコード参照)。トライアル中は status: trialing で、終了3日前に customer.subscription.trial_will_end が飛ぶので、ここで支払い方法の有無を確認するのが定石です。

プロレーション:途中のアップグレード/ダウングレード

月の途中でプランを変えたとき、Stripeは未使用分のクレジット新プランの残り期間請求を自動計算します。挙動は proration_behavior で制御します。

挙動
create_prorations(既定)差額のプロレーション明細を作成(次回請求にまとめる場合あり)
always_invoice変更時点で即時に請求書を発行・課金
none日割りなし。次回周期から新価格

例:月額 ¥1,000 → ¥2,000 に、ちょうど折り返し地点でアップグレードした場合——旧プラン未使用分 −¥500、新プラン残り期間 +¥1,000、差し引き +¥500 が請求されます。

// プランをアップグレードし、即時に差額請求する
const updated = await stripe.subscriptions.update(
  subscriptionId,
  {
    items: [{ id: subscriptionItemId, price: newPriceId }],
    proration_behavior: "always_invoice",
    // 後述のプレビューと「同じ proration_date」を渡すと金額が一致する
    proration_date: prorationDate,
  },
  { idempotencyKey: `sub-upgrade:${subscriptionId}:${newPriceId}:v1` },
);

変更前に金額をユーザーへ提示するには invoices.createPreview を使います。サブスクを変更せずに「次の請求書がこうなる」を返してくれます。

// 確定せずに差額を見積もる(UIで「+¥500を本日請求します」と表示できる)
const prorationDate = Math.floor(Date.now() / 1000);

const preview = await stripe.invoices.createPreview({
  customer: customerId,
  subscription: subscriptionId,
  subscription_details: {
    items: [{ id: subscriptionItemId, price: newPriceId }],
    proration_date: prorationDate,
  },
});

// preview.lines のうち proration: true の明細が日割り(クレジット/デビット)

実装の落とし穴:プロレーションは秒単位で計算されるため、プレビューと実行で proration_date がズレると金額が変わります。プレビューと更新で同じ proration_date を渡すことを徹底してください。


5. 顧客ポータル(Customer Portal):解約UIを自作しない

サブスクで最も「車輪の再発明」になりがちなのが、解約・プラン変更・カード更新・請求書ダウンロードのUIです。これらを自作すると、PCI境界・3Dセキュア・多言語・税表示・領収書をすべて自前で背負うことになります。

結論:作らない。 Stripeの Customer Portal へリダイレクトします。stripe.billingPortal.sessions.create で短命のセッションURLを発行し、そこへ飛ばすだけです。許可する操作(解約可否・変更可能なPrice)はDashboardのポータル設定で制御します。

// app/actions/open-billing-portal.ts
"use server";

import Stripe from "stripe";
import { redirect } from "next/navigation";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function openBillingPortal(): Promise<void> {
  const customerId = await resolveStripeCustomerId(); // 認証済みユーザーから解決

  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    // 操作完了後に自サイトへ戻すURL
    return_url: `${process.env.APP_URL}/settings/billing`,
    // 任意: 特定フロー(解約確認など)に直接入る場合は flow_data を指定
  });

  redirect(session.url); // 短命セッション。都度発行する
}

ポータルセッションは短命で都度発行が原則です。URLをキャッシュ・再利用してはいけません。

UI側はServer Actionを呼ぶだけ。アクセシビリティ観点では、リダイレクトが起きることを事前に伝えるのが親切です(スクリーンリーダー利用者は突然のページ遷移に戸惑います)。

// app/settings/billing/portal-button.tsx
import { openBillingPortal } from "@/app/actions/open-billing-portal";

export function BillingPortalButton() {
  return (
    <form action={openBillingPortal}>
      <button
        type="submit"
        // 外部のStripe管理画面へ遷移する旨をAT利用者に明示
        aria-label="お支払い情報の管理画面(Stripe)へ移動します"
      >
        お支払い・プランの管理
      </button>
    </form>
  );
}

なぜ自作を避けるのか:解約フローはビジネスにとってもユーザーにとっても繊細で、Stripeはここを継続的に改善し、各国の法令(クーリングオフ等)にも追従しています。自作は初期コストだけでなく永続的な保守債務になります。差別化要素でない限り、委譲が正解です。


6. Billingのライフサイクルを Webhook で処理する

サブスクの状態は時間とともに勝手に変わります(更新・失敗・リトライ・解約予約の発火)。これを知る唯一の方法がWebhookです。署名検証と2層の冪等モデル(event.id の一意制約+event.created の順序比較)基礎記事で詳述しているのでそちらに従ってください。ここではどのイベントを・どう扱うかに絞ります。

イベント意味推奨アクション
customer.subscription.createdサブスク作成(incomplete の場合あり)DBに sub_id 記録。statusを保存
customer.subscription.updatedプラン変更・status遷移などstatus を同期。active化でアクセス付与判定
customer.subscription.deleted解約完了(最終)アクセス剥奪
customer.subscription.trial_will_endトライアル終了3日前支払い方法の有無を確認し通知
invoice.paid請求書の支払い成功アクセス付与statusactive
invoice.payment_failed支払い失敗顧客に通知・カード更新を促す(dunning)
invoice.upcoming次回請求が近い必要なら明細を追加

アクセス制御の真実源を1つにします。私のおすすめは「invoice.paid で付与、customer.subscription.deleted / status === 'unpaid' で剥奪」というルールをハンドラ1箇所に集約することです。

// app/api/stripe/webhook/route.ts(抜粋。署名検証・冪等化は基礎記事の実装を前提)
import type Stripe from "stripe";

async function handleBillingEvent(event: Stripe.Event): Promise<void> {
  switch (event.type) {
    case "invoice.paid": {
      const invoice = event.data.object as Stripe.Invoice;
      // 支払い成功 → アクセス付与。subscription IDで自DBを更新
      await grantAccessForSubscription(invoice);
      break;
    }
    case "customer.subscription.updated": {
      const sub = event.data.object as Stripe.Subscription;
      // statusをDBへ同期(active/past_due/unpaid…)
      await syncSubscriptionStatus(sub);
      if (sub.status === "unpaid") await revokeAccess(sub.id);
      break;
    }
    case "customer.subscription.deleted": {
      const sub = event.data.object as Stripe.Subscription;
      await revokeAccess(sub.id); // 解約 → 剥奪
      break;
    }
    case "invoice.payment_failed": {
      const invoice = event.data.object as Stripe.Invoice;
      // dunning: 通知のみ。剥奪はせず Smart Retries に委ねる
      await notifyPaymentFailed(invoice);
      break;
    }
    // それ以外は記録のみ(未知のイベントで500を返さない)
  }
}

dunning(督促)と revenue recovery

支払い失敗時にすぐアクセスを切るのはほぼ常に間違いです。カードの一時的な失敗・期限切れは日常的に起き、Stripeの Smart Retries(データに基づく最適なタイミングでの自動再試行)が回収してくれます。実装側は次のスタンスが堅牢です。

  • invoice.payment_failed通知のみ。statusは past_due になるが、即時剥奪はしない(猶予ポリシーを設ける)。
  • Smart Retries が枯渇し statusunpaid(または canceled)になったら 初めて剥奪
  • リトライ・督促メールのスケジュールはDashboardで設定(コード不要)。アプリ側で再実装しない。

past_due の扱いはプロダクト判断です。BtoBなら「猶予を与えて関係を守る」、無料枠への降格で対応する、などの選択肢があります。剥奪トリガーを unpaid / deleted に固定しておくと、ポリシー変更がハンドラ1箇所で済みます。


7. 設計のコツ(本番で効く7原則)

  1. IDを自DBに保存する。 cus_xxx(Customer)と sub_xxx(Subscription)を user に紐づけて保存。これが無いとWebhookと自システムを照合できません。
  2. Stripeを真実源にする。 自DBの status はキャッシュ。乖離したらWebhookで上書き同期。二重管理の「権威」をDBに置かない。
  3. アクセス判定を1箇所に集約。 status から「使える/使えない」を導く関数を1つにし、UI・API・バッチが同じ関数を呼ぶ。
  4. お金は整数。 金額・使用量は最小通貨単位の整数で扱う。手数料率はベーシスポイントの整数で持ち、丸めをアプリ側で確定。浮動小数を請求計算に挟まない。
  5. クライアントを信用しない。 priceId はホワイトリスト検証、customerId は認証情報から解決。金額・数量をクライアントから受け取らない。
  6. 冪等性を二段で。 送信側は決定的 idempotencyKey / identifier、受信側は event.id の一意制約。リトライ・重複は正常系として吸収。
  7. 時間依存をテスト可能に。 更新・失効・リトライは Test Clocks で仮想的に時間を進めて検証。料金・プロレーション計算は純粋関数に切り出し、ユニットテストで固める(私のサブスク基盤の433テストはこの方針です)。

8. よくある質問(FAQ)

Q. サブスクの「解約」はどう実装するのが正解? A. 自作しないのが正解です。Customer Portal(§5)にリダイレクトし、解約・即時/期末解約・再開をStripeに任せます。どうしてもアプリ内で完結したい場合のみ stripe.subscriptions.cancel(id)(即時)か update(id, { cancel_at_period_end: true })(期末)を使い、結果は customer.subscription.deleted / updated のWebhookで自DBへ反映します。

Q. 途中でプランを変えたときの日割りは? A. proration_behavior で制御します(§4)。即時に差額課金するなら always_invoice、次回周期からなら none変更前に invoices.createPreview で金額を提示し、プレビューと更新で同じ proration_date を渡すのが事故防止の鉄則です。

Q. 従量課金の集計は自分でやるの? A. いいえ。集計はStripe側が行います。あなたは使用が発生するたびにメーターイベントを送るだけ(§3)。ただし新規実装は Metronome が公式推奨で、Billing Meters は既存利用者向けの位置づけに変わりました。どちらでも「使用量イベントを identifier で冪等に送る」という設計思想は共通です。

Q. アクセス権はDBのフラグで管理していいですか? A. DBはキャッシュとして持って構いませんが、真実源は Subscription.status です。invoice.paid で付与、unpaid / deleted で剥奪、というルールをWebhookハンドラ1箇所に集約し、DBはそれを反映するだけにします。二重に「権威」を持たせると必ず乖離します。

Q. 支払いが失敗したらすぐアクセスを切るべき? A. いいえ。一時的な失敗は日常的に起きます。invoice.payment_failed では通知のみにして Smart Retries に回収を委ね、statusunpaid(リトライ枯渇)または canceled になって初めて剥奪します(§6)。

Q. 1ヶ月後の更新やトライアル終了をテストしたい。 A. Test Clocks で仮想時計を進めれば、更新・失効・リトライ・trial_will_end を数秒で再現できます。料金・プロレーションのロジックは純粋関数に切り出し、ユニットテストで網羅するのが堅牢です。


まとめ:サブスクの正しさは「状態」と「冪等性」で作る

サブスクリプションの実装は、APIの呼び方ではなく 「時間とともに変わる状態を、信頼できない外部(クライアント・ネットワーク・リトライ)の中で、正しく1箇所に保ち続ける」 ことです。要点を畳みます。

  • 構成要素CustomerSubscriptionPrice/ProductInvoice。アクセス判定は Subscription.status に集約。
  • 開始:まず Checkout(mode: 'subscription')。フル制御時のみ default_incomplete で Subscriptions API。
  • 従量課金:新規は Metronome が公式推奨。既存は Billing Meters のメーターイベントを identifier で冪等送信。
  • プロレーションproration_behaviorinvoices.createPreview で確定前に金額提示。
  • 顧客ポータル:解約・カード更新UIは自作しない。billingPortal.sessions.create に委譲。
  • Webhookinvoice.paid で付与、unpaid/deleted で剥奪。dunningは即時剥奪しない。冪等は2層。

私はこの水準を、Next.js 16.1 + Stripe 17 のサブスク基盤(冪等Webhook・純粋関数の料金計算・銀行振込の状態機械・433テスト)と、本番二重課金0件を達成した決済信頼性レイヤーで実装・運用してきました。サブスク/請求プラットフォームの新規構築、従量課金(Metronome / Billing Meters)の導入、既存サブスクの信頼性立て直し(プロレーション・dunning・Webhook設計・アクセス権の整合)をご検討でしたら、要件定義から本番運用・テスト容易性の担保まで、この記事の水準でお引き受けします。一人 × 生成AI(Claude Code)を verification gate で運用し、この品質を速く・安全にお届けします。

本記事のWebhook冪等処理・PII墨消し・状態機械の実コードレベルの深掘りは、関連事例「サブスク学習プラットフォームのアーキテクチャ徹底解剖」で公開しています。決済受け入れの基礎は姉妹記事「Stripe決済を本番品質で実装する完全ガイド(2026年版)」をご覧ください。

(本記事のStripe仕様は2026年6月時点の公式ドキュメント/API版 2026-05-27.dahlia に基づきます。従量課金の推奨(Metronome / Billing Meters)やメーターイベントの正確なシグネチャは進化が速い領域です。最新の挙動は必ず公式ドキュメントで確認してください。)

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

金融リテラシー教育のサブスク学習プラットフォーム(マルチチャネル課金・冪等な決済・代理店コミッションをNext.js 16モノレポで構築)

ケーススタディを見る