From aed3ffc54514e721ab6dca6afd61eba62810808c Mon Sep 17 00:00:00 2001 From: Lewis Carhart Date: Thu, 3 Apr 2025 20:53:33 -0400 Subject: [PATCH] feat: integrate Stripe customer creation in organization action - Added `createStripeCustomer` function to handle Stripe customer creation. - Updated `createOrganizationAction` to create a Stripe customer upon organization creation and store the customer ID in the database. - Introduced new `stripe.ts` file for Stripe configuration and error handling. - Updated the `Organization` model to include `stripeCustomerId` field. - Removed outdated seeding scripts to streamline database management. --- .../create-organization-action.ts | 17 ++++++++ .../lib/create-stripe-customer.ts | 24 +++++++++++ .../src/actions/organization/lib/stripe.ts | 15 +++++++ bun.lock | 6 +-- packages/db/package.json | 3 -- .../migration.sql | 2 + packages/db/prisma/schema/organization.prisma | 1 + packages/db/prisma/seed.js | 13 ------ packages/db/prisma/seed.ts | 14 ------- yarn.lock | 42 ++++++++++++------- 10 files changed, 88 insertions(+), 49 deletions(-) create mode 100644 apps/app/src/actions/organization/lib/create-stripe-customer.ts create mode 100644 apps/app/src/actions/organization/lib/stripe.ts create mode 100644 packages/db/prisma/migrations/20250404004853_stripecustomerid/migration.sql delete mode 100644 packages/db/prisma/seed.js delete mode 100644 packages/db/prisma/seed.ts diff --git a/apps/app/src/actions/organization/create-organization-action.ts b/apps/app/src/actions/organization/create-organization-action.ts index dfcb9d1bf8..b9180cf0f9 100644 --- a/apps/app/src/actions/organization/create-organization-action.ts +++ b/apps/app/src/actions/organization/create-organization-action.ts @@ -11,6 +11,8 @@ import { createOrganizationEvidence, createControlArtifacts, } from "./lib/utils"; +import { createStripeCustomer } from "./lib/create-stripe-customer"; +import { db } from "@comp/db"; export const createOrganizationAction = authActionClient .schema(organizationSchema) @@ -41,6 +43,21 @@ export const createOrganizationAction = authActionClient const organizationId = session.session.activeOrganizationId; + const stripeCustomerId = await createStripeCustomer({ + name, + email: session.user.email, + organizationId, + }); + + if (!stripeCustomerId) { + throw new Error("Failed to create Stripe customer"); + } + + await db.organization.update({ + where: { id: organizationId }, + data: { stripeCustomerId }, + }); + const organizationFrameworks = await Promise.all( frameworks.map((frameworkId) => createFrameworkInstance(organizationId, frameworkId), diff --git a/apps/app/src/actions/organization/lib/create-stripe-customer.ts b/apps/app/src/actions/organization/lib/create-stripe-customer.ts new file mode 100644 index 0000000000..51d1b0991a --- /dev/null +++ b/apps/app/src/actions/organization/lib/create-stripe-customer.ts @@ -0,0 +1,24 @@ +import { stripe } from "./stripe"; + +async function createStripeCustomer(input: { + name: string; + email: string; + organizationId: string; +}): Promise { + try { + const customer = await stripe.customers.create({ + name: input.name, + email: input.email, + metadata: { + organizationId: input.organizationId, + }, + }); + + return customer.id; + } catch (error) { + console.error("Error creating Stripe customer", error); + throw error; + } +} + +export { createStripeCustomer }; diff --git a/apps/app/src/actions/organization/lib/stripe.ts b/apps/app/src/actions/organization/lib/stripe.ts new file mode 100644 index 0000000000..0613041041 --- /dev/null +++ b/apps/app/src/actions/organization/lib/stripe.ts @@ -0,0 +1,15 @@ +import Stripe from "stripe"; + +if (!process.env.STRIPE_SECRET_KEY) { + throw new Error("STRIPE_SECRET_KEY is not set"); +} + +if (!process.env.STRIPE_WEBHOOK_SECRET) { + throw new Error("STRIPE_WEBHOOK_SECRET is not set"); +} + +export const stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET; + +export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { + apiVersion: "2025-02-24.acacia", +}); diff --git a/bun.lock b/bun.lock index 9127ae36af..4cb72d3d65 100644 --- a/bun.lock +++ b/bun.lock @@ -4,8 +4,8 @@ "": { "name": "comp", "dependencies": { - "@aws-sdk/client-s3": "^3.758.0", - "@aws-sdk/client-securityhub": "^3.758.0", + "@aws-sdk/client-s3": "^3.782.0", + "@aws-sdk/client-securityhub": "^3.782.0", "@azure/core-http": "^3.0.5", "@azure/identity": "^4.8.0", "@manypkg/cli": "^0.23.0", @@ -23,7 +23,7 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@types/lodash": "^4.17.16", - "turbo": "^2.4.4", + "turbo": "^2.5.0", "typescript": "5.7.3", }, }, diff --git a/packages/db/package.json b/packages/db/package.json index 757e923e02..9614ed10a5 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -34,8 +34,5 @@ "devDependencies": { "@comp/tsconfig": "workspace:*", "typescript": "^5.8.2" - }, - "prisma": { - "seed": "bun prisma/seed.ts" } } diff --git a/packages/db/prisma/migrations/20250404004853_stripecustomerid/migration.sql b/packages/db/prisma/migrations/20250404004853_stripecustomerid/migration.sql new file mode 100644 index 0000000000..82c133ca77 --- /dev/null +++ b/packages/db/prisma/migrations/20250404004853_stripecustomerid/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Organization" ADD COLUMN "stripeCustomerId" TEXT; diff --git a/packages/db/prisma/schema/organization.prisma b/packages/db/prisma/schema/organization.prisma index 74ade43bc6..065f34da52 100644 --- a/packages/db/prisma/schema/organization.prisma +++ b/packages/db/prisma/schema/organization.prisma @@ -5,6 +5,7 @@ model Organization { logo String? createdAt DateTime metadata String? + stripeCustomerId String? apiKeys ApiKey[] artifacts Artifact[] diff --git a/packages/db/prisma/seed.js b/packages/db/prisma/seed.js deleted file mode 100644 index b4cad214b2..0000000000 --- a/packages/db/prisma/seed.js +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const client_1 = require("@prisma/client"); -const prisma = new client_1.PrismaClient(); -async function main() { } -main() - .catch((e) => { - console.error("\n❌ Error during seeding:", e); - process.exit(1); -}) - .finally(async () => { - await prisma.$disconnect(); -}); diff --git a/packages/db/prisma/seed.ts b/packages/db/prisma/seed.ts deleted file mode 100644 index fae977bc32..0000000000 --- a/packages/db/prisma/seed.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { PrismaClient } from "@prisma/client"; - -const prisma = new PrismaClient(); - -async function main() {} - -main() - .catch((e) => { - console.error("\n❌ Error during seeding:", e); - process.exit(1); - }) - .finally(async () => { - await prisma.$disconnect(); - }); diff --git a/yarn.lock b/yarn.lock index c68cbe843e..3593a482c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -266,7 +266,7 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.6.2" -"@aws-sdk/client-s3@^3.758.0", "@aws-sdk/client-s3@^3.779.0": +"@aws-sdk/client-s3@^3.779.0", "@aws-sdk/client-s3@^3.782.0": version "3.782.0" resolved "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.782.0.tgz" integrity sha512-V6JR2JAGYQY7J8wk5un5n/ja2nfCUyyoRCF8Du8JL91NGI8i41Mdr/TzuOGwTgFl6RSXb/ge1K1jk30OH4MugQ== @@ -328,7 +328,7 @@ "@smithy/util-waiter" "^4.0.3" tslib "^2.6.2" -"@aws-sdk/client-securityhub@^3.0.0", "@aws-sdk/client-securityhub@^3.758.0": +"@aws-sdk/client-securityhub@^3.0.0", "@aws-sdk/client-securityhub@^3.782.0": version "3.782.0" resolved "https://registry.npmjs.org/@aws-sdk/client-securityhub/-/client-securityhub-3.782.0.tgz" integrity sha512-hT/MMK4h9iOmj59RrzpRC1HG/4BkZ7YDFpEi7V3MfWZaEe3zDiet46RehPBTpJNdBRDpY8BO9gUtU/rUnn64xg== @@ -1448,19 +1448,20 @@ picocolors "^1.0.0" sisteransi "^1.0.5" -"@comp/analytics@packages/analytics": +"@comp/analytics@^workspace:packages/analytics": version "workspace:packages/analytics" resolved "workspace:packages/analytics" dependencies: posthog-js "^1.215.3" posthog-node "^4.4.1" -"@comp/app@apps/app", "@comp/app@workspace:*": +"@comp/app@^workspace:apps/app", "@comp/app@workspace:*": version "workspace:apps/app" resolved "workspace:apps/app" devDependencies: "@comp/auth" "workspace:*" "@comp/db" "workspace:*" + devDependencies: "@trigger.dev/build" "3.3.17" "@types/node" "^22.13.17" "@types/react" "19.0.10" @@ -1476,9 +1477,11 @@ "@aws-sdk/client-s3" "^3.779.0" "@aws-sdk/s3-request-presigner" "^3.779.0" "@browserbasehq/sdk" "^2.5.0" + dependencies: "@comp/auth" "workspace:*" "@comp/data" "workspace:*" "@comp/notifications" "workspace:*" + dependencies: "@date-fns/tz" "^1.2.0" "@dnd-kit/core" "^6.3.1" "@dnd-kit/modifiers" "^9.0.0" @@ -1551,7 +1554,7 @@ yarn "^1.22.22" zustand "^5.0.3" -"@comp/auth@packages/auth", "@comp/auth@workspace:*": +"@comp/auth@^workspace:packages/auth", "@comp/auth@workspace:*": version "workspace:packages/auth" resolved "workspace:packages/auth" devDependencies: @@ -1560,22 +1563,25 @@ typescript "^5.7.3" dependencies: "@comp/email" "workspace:*" + dependencies: better-auth "^1.2.5" server-only "0.0.1" -"@comp/data@packages/data", "@comp/data@workspace:*": +"@comp/data@^workspace:packages/data", "@comp/data@workspace:*": version "workspace:packages/data" resolved "workspace:packages/data" devDependencies: "@comp/db" "workspace:*" + devDependencies: tsup "^8.4.0" typescript "^5.8.2" -"@comp/db@packages/db", "@comp/db@workspace:*": +"@comp/db@^workspace:packages/db", "@comp/db@workspace:*": version "workspace:packages/db" resolved "workspace:packages/db" devDependencies: "@comp/tsconfig" "workspace:*" + devDependencies: typescript "^5.8.2" dependencies: "@auth/prisma-adapter" "^2.8.0" @@ -1585,7 +1591,7 @@ "@prisma/extension-accelerate" "^1.2.2" prisma "^6.5.0" -"@comp/email@packages/email", "@comp/email@workspace:*": +"@comp/email@^workspace:packages/email", "@comp/email@workspace:*": version "workspace:packages/email" resolved "workspace:packages/email" devDependencies: @@ -1596,6 +1602,7 @@ dependencies: "@comp/ui" "workspace:*" "@comp/utils" "workspace:*" + dependencies: "@react-email/components" "0.0.31" "@react-email/render" "0.0.10" "@react-email/tailwind" "1.0.4" @@ -1605,7 +1612,7 @@ react-email "3.0.4" responsive-react-email "^0.0.5" -"@comp/integrations@packages/integrations": +"@comp/integrations@^workspace:packages/integrations": version "workspace:packages/integrations" resolved "workspace:packages/integrations" devDependencies: @@ -1616,7 +1623,9 @@ "@ai-sdk/openai" "^0.0.66" "@aws-sdk/client-securityhub" "^3.0.0" "@azure/identity" "^3.0.0" + dependencies: "@comp/app" "workspace:*" + dependencies: "@google-cloud/security-center" "^7.0.0" "@slack/bolt" "^3.22.0" "@slack/web-api" "^7.8.0" @@ -1626,14 +1635,14 @@ sharp "^0.33.5" zod "^3.24.2" -"@comp/kv@packages/kv": +"@comp/kv@^workspace:packages/kv": version "workspace:packages/kv" resolved "workspace:packages/kv" dependencies: "@upstash/redis" "^1.34.2" server-only "0.0.1" -"@comp/notifications@packages/notifications", "@comp/notifications@workspace:*": +"@comp/notifications@^workspace:packages/notifications", "@comp/notifications@workspace:*": version "workspace:packages/notifications" resolved "workspace:packages/notifications" devDependencies: @@ -1642,12 +1651,13 @@ "@novu/node" "^2.0.1" nanoid "5.1.0" -"@comp/portal@apps/portal": +"@comp/portal@^workspace:apps/portal": version "workspace:apps/portal" resolved "workspace:apps/portal" devDependencies: "@comp/db" "workspace:*" "@comp/ui" "workspace:*" + devDependencies: "@types/node" "^22.13.2" "@types/react" "^19.0.8" "@types/react-dom" "^19.0.3" @@ -1662,11 +1672,11 @@ react-dom "^19.0.0" react-otp-input "^3.1.1" -"@comp/tsconfig@packages/tsconfig", "@comp/tsconfig@workspace:*": +"@comp/tsconfig@^workspace:packages/tsconfig", "@comp/tsconfig@workspace:*": version "workspace:packages/tsconfig" resolved "workspace:packages/tsconfig" -"@comp/ui@packages/ui", "@comp/ui@workspace:*": +"@comp/ui@^workspace:packages/ui", "@comp/ui@workspace:*": version "workspace:packages/ui" resolved "workspace:packages/ui" devDependencies: @@ -1730,7 +1740,7 @@ use-callback-ref "^1.3.3" vaul "^1.0.0" -"@comp/utils@packages/utils", "@comp/utils@workspace:*": +"@comp/utils@^workspace:packages/utils", "@comp/utils@workspace:*": version "workspace:packages/utils" resolved "workspace:packages/utils" devDependencies: @@ -14360,7 +14370,7 @@ tunnel-rat@^0.1.2: dependencies: zustand "^4.3.2" -turbo@^2.4.4: +turbo@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/turbo/-/turbo-2.5.0.tgz" integrity sha512-PvSRruOsitjy6qdqwIIyolv99+fEn57gP6gn4zhsHTEcCYgXPhv6BAxzAjleS8XKpo+Y582vTTA9nuqYDmbRuA==