Skip to content

Commit 9813b97

Browse files
authored
Merge pull request #131 from apsinghdev/feat/auto-onboarding
auto onboarding
2 parents 043d5a4 + 304a9d5 commit 9813b97

File tree

47 files changed

+2598
-233
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2598
-233
lines changed

apps/api/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
"express-rate-limit": "^7.5.0",
3535
"helmet": "^7.2.0",
3636
"jsonwebtoken": "^9.0.2",
37+
"razorpay": "^2.9.6",
38+
"superjson": "^2.2.5",
39+
"zeptomail": "^6.2.1",
3740
"zod": "^4.1.9"
3841
}
3942
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- CreateTable
2+
CREATE TABLE "QueryCount" (
3+
"id" INTEGER NOT NULL DEFAULT 1,
4+
"total_queries" INTEGER NOT NULL,
5+
6+
CONSTRAINT "QueryCount_pkey" PRIMARY KEY ("id")
7+
);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "QueryCount" ALTER COLUMN "total_queries" SET DATA TYPE BIGINT;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
-- CreateTable
2+
CREATE TABLE "User" (
3+
"id" TEXT NOT NULL,
4+
"email" TEXT NOT NULL,
5+
"firstName" TEXT NOT NULL,
6+
"authMethod" TEXT NOT NULL,
7+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8+
"lastLogin" TIMESTAMP(3) NOT NULL,
9+
10+
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
11+
);
12+
13+
-- CreateTable
14+
CREATE TABLE "Account" (
15+
"id" TEXT NOT NULL,
16+
"userId" TEXT NOT NULL,
17+
"type" TEXT NOT NULL,
18+
"provider" TEXT NOT NULL,
19+
"providerAccountId" TEXT NOT NULL,
20+
"refresh_token" TEXT,
21+
"access_token" TEXT,
22+
"expires_at" INTEGER,
23+
"token_type" TEXT,
24+
"scope" TEXT,
25+
"id_token" TEXT,
26+
"session_state" TEXT,
27+
28+
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
29+
);
30+
31+
-- CreateIndex
32+
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
33+
34+
-- CreateIndex
35+
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
36+
37+
-- AddForeignKey
38+
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
-- CreateTable
2+
CREATE TABLE "Payment" (
3+
"id" TEXT NOT NULL,
4+
"userId" TEXT NOT NULL,
5+
"subscriptionId" TEXT,
6+
"razorpayPaymentId" TEXT NOT NULL,
7+
"razorpayOrderId" TEXT NOT NULL,
8+
"amount" INTEGER NOT NULL,
9+
"currency" TEXT NOT NULL DEFAULT 'INR',
10+
"status" TEXT NOT NULL,
11+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
12+
"updatedAt" TIMESTAMP(3) NOT NULL,
13+
14+
CONSTRAINT "Payment_pkey" PRIMARY KEY ("id")
15+
);
16+
17+
-- CreateTable
18+
CREATE TABLE "Subscription" (
19+
"id" TEXT NOT NULL,
20+
"userId" TEXT NOT NULL,
21+
"planId" TEXT NOT NULL,
22+
"status" TEXT NOT NULL,
23+
"startDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
24+
"endDate" TIMESTAMP(3) NOT NULL,
25+
"autoRenew" BOOLEAN NOT NULL DEFAULT true,
26+
27+
CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
28+
);
29+
30+
-- CreateTable
31+
CREATE TABLE "Plan" (
32+
"id" TEXT NOT NULL,
33+
"name" TEXT NOT NULL,
34+
"interval" TEXT NOT NULL,
35+
"price" INTEGER NOT NULL,
36+
"currency" TEXT NOT NULL DEFAULT 'INR',
37+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
38+
"updatedAt" TIMESTAMP(3) NOT NULL,
39+
40+
CONSTRAINT "Plan_pkey" PRIMARY KEY ("id")
41+
);
42+
43+
-- CreateIndex
44+
CREATE UNIQUE INDEX "Payment_razorpayPaymentId_key" ON "Payment"("razorpayPaymentId");
45+
46+
-- CreateIndex
47+
CREATE INDEX "Subscription_userId_idx" ON "Subscription"("userId");
48+
49+
-- AddForeignKey
50+
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
51+
52+
-- AddForeignKey
53+
ALTER TABLE "Payment" ADD CONSTRAINT "Payment_subscriptionId_fkey" FOREIGN KEY ("subscriptionId") REFERENCES "Subscription"("id") ON DELETE SET NULL ON UPDATE CASCADE;
54+
55+
-- AddForeignKey
56+
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
57+
58+
-- AddForeignKey
59+
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_planId_fkey" FOREIGN KEY ("planId") REFERENCES "Plan"("id") ON DELETE CASCADE ON UPDATE CASCADE;

apps/api/prisma/migrations/20251030121123_add_payment_constraints/migration.sql

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
Warnings:
3+
4+
- Changed the type of `status` on the `Payment` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
5+
- Changed the type of `status` on the `Subscription` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required.
6+
7+
*/
8+
-- CreateEnum
9+
CREATE TYPE "PaymentStatus" AS ENUM ('created', 'authorized', 'captured', 'refunded', 'failed');
10+
11+
-- CreateEnum
12+
CREATE TYPE "SubscriptionStatus" AS ENUM ('created', 'authenticated', 'active', 'pending', 'halted', 'cancelled', 'completed', 'expired');
13+
14+
-- AlterTable: Migrate Payment.status from TEXT to PaymentStatus enum
15+
-- First, temporarily drop NOT NULL constraint to allow safe conversion
16+
ALTER TABLE "Payment" ALTER COLUMN "status" DROP NOT NULL;
17+
18+
-- Convert the column type preserving existing data
19+
ALTER TABLE "Payment" ALTER COLUMN "status" TYPE "PaymentStatus" USING status::"PaymentStatus";
20+
21+
-- Backfill any NULLs with a default value if needed (shouldn't be necessary but being safe)
22+
-- If there are NULLs, we'd set a default here, but since original was NOT NULL, this shouldn't be needed
23+
24+
-- Re-add NOT NULL constraint after successful conversion
25+
ALTER TABLE "Payment" ALTER COLUMN "status" SET NOT NULL;
26+
27+
-- AlterTable: Migrate Subscription.status from TEXT to SubscriptionStatus enum
28+
-- First, temporarily drop NOT NULL constraint to allow safe conversion
29+
ALTER TABLE "Subscription" ALTER COLUMN "status" DROP NOT NULL;
30+
31+
-- Convert the column type preserving existing data
32+
ALTER TABLE "Subscription" ALTER COLUMN "status" TYPE "SubscriptionStatus" USING status::"SubscriptionStatus";
33+
34+
-- Backfill any NULLs with a default value if needed (shouldn't be necessary but being safe)
35+
-- If there are NULLs, we'd set a default here, but since original was NOT NULL, this shouldn't be needed
36+
37+
-- Re-add NOT NULL constraint after successful conversion
38+
ALTER TABLE "Subscription" ALTER COLUMN "status" SET NOT NULL;
39+
40+
-- AlterTable: Make Subscription.endDate nullable
41+
ALTER TABLE "Subscription" ALTER COLUMN "endDate" DROP NOT NULL;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Please do not edit this file manually
2+
# It should be added in your version-control system (i.e. Git)
3+
provider = "postgresql"

apps/api/prisma/schema.prisma

Lines changed: 79 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,48 +12,92 @@ model QueryCount {
1212
total_queries BigInt
1313
}
1414

15-
model User {
16-
id String @id @default(cuid())
17-
18-
email String @unique
19-
20-
firstName String
21-
22-
authMethod String
23-
24-
createdAt DateTime @default(now())
15+
enum PaymentStatus {
16+
created
17+
authorized
18+
captured
19+
refunded
20+
failed
21+
}
2522

26-
lastLogin DateTime @updatedAt
23+
enum SubscriptionStatus {
24+
created
25+
authenticated
26+
active
27+
pending
28+
halted
29+
cancelled
30+
completed
31+
expired
32+
}
2733

28-
accounts Account[]
34+
model User {
35+
id String @id @default(cuid())
36+
email String @unique
37+
firstName String
38+
authMethod String
39+
createdAt DateTime @default(now())
40+
lastLogin DateTime @updatedAt
41+
accounts Account[]
42+
payments Payment[]
43+
subscriptions Subscription[]
2944
}
3045

3146
model Account {
32-
id String @id @default(cuid())
33-
34-
userId String // Foreign key to User
35-
36-
type String // "oauth", "email", etc.
37-
38-
provider String // "google", "github", etc.
47+
id String @id @default(cuid())
48+
userId String
49+
type String
50+
provider String
51+
providerAccountId String
52+
refresh_token String?
53+
access_token String?
54+
expires_at Int?
55+
token_type String?
56+
scope String?
57+
id_token String?
58+
session_state String?
59+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
3960
40-
providerAccountId String // ID from the provider
41-
42-
refresh_token String?
43-
44-
access_token String?
45-
46-
expires_at Int?
47-
48-
token_type String?
49-
50-
scope String?
51-
52-
id_token String?
61+
@@unique([provider, providerAccountId])
62+
}
5363

54-
session_state String?
64+
model Payment {
65+
id String @id @default(cuid())
66+
userId String
67+
subscriptionId String?
68+
razorpayPaymentId String @unique
69+
razorpayOrderId String
70+
amount Int // Amount in paise (smallest currency unit)
71+
currency String @default("INR")
72+
status PaymentStatus
73+
createdAt DateTime @default(now())
74+
updatedAt DateTime @updatedAt
75+
subscription Subscription? @relation(fields: [subscriptionId], references: [id])
76+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
77+
}
5578

56-
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
79+
model Subscription {
80+
id String @id @default(cuid())
81+
userId String
82+
planId String
83+
status SubscriptionStatus
84+
startDate DateTime @default(now())
85+
endDate DateTime?
86+
autoRenew Boolean @default(true)
87+
payments Payment[]
88+
plan Plan @relation(fields: [planId], references: [id], onDelete: Cascade)
89+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
90+
91+
@@index([userId])
92+
}
5793

58-
@@unique([provider, providerAccountId])
94+
model Plan {
95+
id String @id @default(cuid())
96+
name String
97+
interval String
98+
price Int
99+
currency String @default("INR")
100+
createdAt DateTime @default(now())
101+
updatedAt DateTime @updatedAt
102+
subscriptions Subscription[]
59103
}

apps/api/src/clients/razorpay.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Razorpay from "razorpay";
2+
3+
const RAZORPAY_KEY_ID = process.env.RAZORPAY_KEY_ID;
4+
const RAZORPAY_KEY_SECRET = process.env.RAZORPAY_KEY_SECRET;
5+
6+
if (!RAZORPAY_KEY_ID) {
7+
throw new Error(
8+
"RAZORPAY_KEY_ID is required but not set in environment variables. Please configure it in your .env file."
9+
);
10+
}
11+
12+
if (!RAZORPAY_KEY_SECRET) {
13+
throw new Error(
14+
"RAZORPAY_KEY_SECRET is required but not set in environment variables. Please configure it in your .env file."
15+
);
16+
}
17+
18+
export const rz_instance = new Razorpay({
19+
key_id: RAZORPAY_KEY_ID,
20+
key_secret: RAZORPAY_KEY_SECRET,
21+
});

0 commit comments

Comments
 (0)