Slide 1

Slide 1 text

Stripe & Next.js + AWS Amplify Ͱձһ + ఆظ՝ۚػೳ JP_Stripes Online Hidetaka Okamoto #JP_Stripes

Slide 2

Slide 2 text

H i d e t a k a O k a m o t o • Digitalcube Co. Ltd. • JavaScript Developer • WordPress 4.7 / 5.0 / 5.3 Core contributor

Slide 3

Slide 3 text

H i d e t a k a O k a m o t o • Digitalcube Co. Ltd. • JavaScript Developer • WordPress 4.7 / 5.0 / 5.3 Core contributor https://zenn.dev/hideokamoto/books/e961b4bad92429

Slide 4

Slide 4 text

Agenda • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes

Slide 5

Slide 5 text

Agenda • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes

Slide 6

Slide 6 text

ؾʹͳΔπʔϧ΍ ৽ػೳͰ༡Ϳ৔ॴ͕ཉ͍͠

Slide 7

Slide 7 text

ݸਓαΠτʹ શ෦ϒνࠐΜͩ #JP_Stripes https://wp-kyoto.net Ͱ 9݄தެ։༧ఆ

Slide 8

Slide 8 text

• AWS Amplify: Authentication • AWS CDK: IaC • Stripe: Subscription • Algolia: Advanced Search • Next.js: Framework • Ionic: UI library • WordPress: Headless CMS • Capacitor / Sentry / etc… #JP_Stripes ٕज़ελοΫ

Slide 9

Slide 9 text

༗ྉձһαΠτ։ൃͷγϣʔτΧοτίʔε • ෳࡶͳػೳ͸͢΂ͯSaaS / Frameworkʹ೚ͤΔ • ΞϓϦ͸ʮAPIΛΑͼͩ͢ʯʮAPIͷ݁ՌΛදࣔ͢ΔʯʹಛԽ • ʮܾࡁʯͱʮೝূೝՄʯΛͲΕ͚ͩ࠷୹ڑ཭Ͱ࡞ΕΔ͔͕伴 • ೝূೝՄ: Auth0 / Cognito / Firebase / Superbase / etc… • ܾࡁ: Stripe / pay.jp / PayPal / Paidy / etc… #JP_Stripes

Slide 10

Slide 10 text

Stripeͷ Low codeܥػೳΛ׆༻ #JP_Stripes

Slide 11

Slide 11 text

#JP_Stripes SpeakerDeck

Slide 12

Slide 12 text

SaaS APIΛ׆༻ͯ͠ɺίʔυͷྔΛ཈͑Δ • ܾࡁͱܾࡁ؅ཧ͸΄΅ඞͣඞཁʹͳΔػೳཁ݅ • StripeͰܾࡁ͢Δ৔߹ɺҎԼͷ2఺͕Low CodeԽͰ͖Δ • ஫จϑΥʔϜ(Χʔυ / ߪೖऀ৘ใೖྗ) -> Checkout • ఆظ՝ۚ৘ใ؅ཧ -> Customer Portal • ʮࣗ༝ͱޮ཰ʯͲͬͪΛॏࢹ͢Δ͔ͰಓΛબ΅͏ #JP_Stripes

Slide 13

Slide 13 text

Agenda • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes

Slide 14

Slide 14 text

Next.js & AWS AmplifyʹStripeΛ૊ΈࠐΉ • React AppଆʹStripe JS SDK • REST APIଆʹStripe Nodejs SDK • CheckoutͱCustomer Portal͚ͩͳΒReact SDK͸ෆཁ • React SDK͸Stripe ElementΛ࢖͏ͨΊͷSDK • APIΩʔͷऔΓѻ͍ʹ஫ҙʢޙड़ʣ #JP_Stripes

Slide 15

Slide 15 text

SSM·ͨ͸Secret Manager͔ΒAPIΩʔΛऔಘ export const createStripeClient = async () => { const data = await new SSM({ region: “us-east-1"ɹ}) .getParameter({ Name: !!process.env.AWS_LAMBDA_FUNCTION_NAME ? "STRIPE_LIVE_SECRET_KEY": "STRIPE_TEST_SECRET_KEY", WithDecryption: true, }).promise(); const stripe = new Stripe(data.Parameter?.Value;, { apiVersion: "2020-08-27", maxNetworkRetries: 3, }); return stripe; }; #JP_Stripes

Slide 16

Slide 16 text

Stripe CustomerͱCognito User poolͷ࿈ܞ // Authorization HeaderͳͲͰऔಘͨ͠tokenͰCognito UserΛGet const user = await cognito.getUser({ AccessToken: req.headers.authorization || “" }).promise() // User attributes͔ΒEmailΛऔಘ const emailAttribute = user.UserAttributes.find((data) => data.Name === "email"); const email = emailAttribute?.Value || “"; // EmailΛ͔ͭͬͯStripe CustomerΛ࡞੒ const customer = await stripe.customers.create({ email }); #JP_Stripes

Slide 17

Slide 17 text

Stripe CustomerͱCognito User poolͷ࿈ܞ // ࡞੒ͨ͠Stripe Customer const customer = await stripe.customers.create({ email }); // User Attributeʹอଘ͢Δ await cognito .updateUserAttributes({ AccessToken: req.headers.authorization, UserAttributes: [{ Name: "custom:stripeCustomerId", Value: customer.id, }], }).promise(); #JP_Stripes

Slide 18

Slide 18 text

Customer idΛηοτͯ͠checkout.sessions.create const session = await stripe.checkout.sessions.create({ customer: customerId, allow_promotion_codes: true, line_items: [{ price: price.id, quantity: 1, }], mode: "subscription", success_url: `${appUrl.replace(/\/$/, "")}/mypages/subscriptions`, cancel_url: `${appUrl.replace(/\/$/, "")}/mypages/plans`, payment_method_types: ["card"], }); res.status(200).json({ session_id: session.id }); #JP_Stripes

Slide 19

Slide 19 text

Customer Portal͸Customer IDΛ࢖͏ // Cognito͔ΒϢʔβʔΛऔಘ const user = await cognito.getUser({ AccessToken: req.headers.authorization }).promise() const attribute = user.UserAttributes.find((data) => { return data.Name === “custom:stripeCustomerId" }); // Customer Poral SessionΛ࡞੒ const session = await stripe.billingPortal.sessions.create({ customer: attribute?.Value, return_url: `${appUrl.replace(/\/$/, "")}/mypages/subscriptions`, }); res.status(200).json({ url: session.url }); #JP_Stripes

Slide 20

Slide 20 text

#JP_Stripes ໘౗ͳ ੥ٻ؅ཧܥը໘͕ ͨͬͨ4ߦͰ࡞ΕΔ

Slide 21

Slide 21 text

APIͰϙʔλϧͷURLΛੜ੒ͯ͠ϦμΠϨΫτ const { push } = useRouter(); return ( { const session = await Auth.currentSession(); const token = session.getAccessToken().getJwtToken(); const data = await fetch("/api/portal", { method: "POST", headers: { "Content-Type": "application/json", Authorization: token, }, }).then(data => data.json()); push(data.url); }}>Button) #JP_Stripes

Slide 22

Slide 22 text

࣮૷࣌ͷϙΠϯτ 1. StripeͷCustomer IDΛϢʔβʔ৘ใͱඥ͚ͮΔඞཁ͋Γ • Customer Portal Linkͷੜ੒͸αʔόʔଆॲཧ 2. Customer Portalʹग़͢ίϯςϯπͷ੍ޚ͸ݪଇDashboard • API͔ΒͳΒઃఆ͸ෳ਺࡞ΕΔ໛༷ʢະݕূʣ 3. Stripe Secret APIΩʔͷѻ͍͕ෆ҆ͳΒ੍ݶ෇͖ΩʔΛ࢖͓͏ #JP_Stripes

Slide 23

Slide 23 text

Agenda • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes

Slide 24

Slide 24 text

ར༻ن໿ϖʔδͱ ϓϥΠόγʔϙϦγʔϖʔδ ͸ొ࿥ඞਢ #JP_Stripes

Slide 25

Slide 25 text

#JP_Stripes AWS Amplify͸ Next.jsΛLambda@edge Ͱ࣮ߦ͢Δ

Slide 26

Slide 26 text

#JP_Stripes ͍͍ͩͨ ͜Εͩͱࢥͬͯ ѻ͓͏

Slide 27

Slide 27 text

ΞϓϦ֎ͰStripeͷσʔλ͕มΘΔ͜ͱʹ஫ҙ • ϓϥϯมߋɾղ໿ɾϢʔβʔ৘ใͷมߋͳͲͷૢ࡞ • Customer PortalͰى͖ͨมߋΛγεςϜʹ൓өͤ͞Δඞཁ͕͋Δ • Stripe WebhookͰΠϕϯτΛड͚ͯσʔλΛมߋ͠Α͏ • Customer Portalʹ͸ʮCustomer࡟আʯ͕ݱঢ়ͳ͍ 1. Subscriptions.delete WebhookͰσʔλΛফ͢ 2. CognitoͳͲͷϢʔβʔ࡟আ࣌ʹফ͢Α͏ʹγεςϜΛߏங #JP_Stripes

Slide 28

Slide 28 text

ඞཁͳAPIΛݺͼग़ͯ͠ ػೳΛ։ൃ͢Δ ↓ ඞཁͳWebhookΠϕϯτΛ Subscribeͯ͠։ൃ͢Δ

Slide 29

Slide 29 text

Agenda • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes

Slide 30

Slide 30 text

ઃఆ߲໨͸೔ʹ೔ʹ૿Ճ͍ͯ͠Δ

Slide 31

Slide 31 text

Customer Portalͱ ಉ౳ͷػೳΛ ࣗલͰ։ൃɾఏڙͰ͖Δ͔ʁ

Slide 32

Slide 32 text

ίΞϏδωεྖҬ֎ͷػೳΛ୭͕࡞Δ͔ʁ A. ࣗྗ։ൃ͢Δ͜ͱͰɺσβΠϯ΍࢓༷ͷࣗ༝౓Λ֬อͰ͖Δ • ػೳ͕૿͑Δͱอकɾӡ༻ͷൣғ΋૿͑Δ • ͦͷࣗ༝Λ׆༻Ͱ͖Δ͚ͩͷ։ൃϦιʔε͕͋Δ͔൱͔ B. SaaS / Low Codeʹҕৡͯ͠ɺॏཁͳػೳʹूத͢Δ • ϕϯμʔ͕࠷దͱ͢ΔUI΍ػೳΛৗʹड͚औΕΔ • υϝΠϯ΍σβΠϯɾػೳͷ੍໿Λڐ༰Ͱ͖Δ͔൱͔ #JP_Stripes

Slide 33

Slide 33 text

ΠϕϯτۦಈͳγεςϜ͔ͩΒͰ͖Δ͜ͱ #JP_Stripes • Checkout / Customer Portal͸WebhookͰγεςϜͱ࿈ܞ͢Δ࢓૊Έ • ϓϥϯมߋͳͲͷΠϕϯτΛड͚ͯಈ࡞͢ΔγεςϜʹͳΔ • ʮಉ͡ΠϕϯτΛൃՐͰ͖Ε͹ʯ͍ͭͰ΋ஔ͖׵͑Ͱ͖Δ • ্ཱͪ͛࣌͸྆ػೳΛ࢖ͬͯίΞ։ൃʹϦιʔεΛूத͢Δ • Ҡߦ͢Δ࣌͸ɺΠϕϯτ୯ҐͰஈ֊తʹ੾Γସ͍͑ͯ͘ • ʮΠϕϯτۦಈΞʔΩςΫνϟʯ΁ͷୈҰาʹ

Slide 34

Slide 34 text

More info

Slide 35

Slide 35 text

ϝʔϧͰߋ৽৘ใΛ ͬ͟ͱݟͰ͖Δ Developer Digest #JP_Stripes https://stripe.dev/

Slide 36

Slide 36 text

https://www.youtube.com/stripedevelopers

Slide 37

Slide 37 text

Thanks! • ࠷খݶͷ։ൃ޻਺Ͱ༗ྉձһϝσΟΞΛ࡞Δ • Next.js / Stripe / AWS AmplifyͰ࣮૷͢Δ • ઃܭɾ։ൃ࣌ͷ஫ҙ఺ • ʮਖ਼͘͠SaaSʹґଘ͢Δʯ #JP_Stripes