fix: init billing server for new users

This commit is contained in:
Harshith Mullapudi 2025-10-02 11:25:52 +05:30
parent 489fb5934a
commit 27762262d2
5 changed files with 100 additions and 15 deletions

View File

@ -2,6 +2,7 @@ import type { Prisma, User } from "@core/database";
import type { GoogleProfile } from "@coji/remix-auth-google"; import type { GoogleProfile } from "@coji/remix-auth-google";
import { prisma } from "~/db.server"; import { prisma } from "~/db.server";
import { env } from "~/env.server"; import { env } from "~/env.server";
import { ensureBillingInitialized } from "~/services/billing.server";
export type { User } from "@core/database"; export type { User } from "@core/database";
type FindOrCreateMagicLink = { type FindOrCreateMagicLink = {
@ -156,11 +157,6 @@ export async function findOrCreateGoogleUser({
authIdentifier, authIdentifier,
email, email,
authenticationMethod: "GOOGLE", authenticationMethod: "GOOGLE",
UserUsage: {
create: {
availableCredits: 200,
},
},
}, },
}); });

View File

@ -1,5 +1,6 @@
import { type Workspace } from "@core/database"; import { type Workspace } from "@core/database";
import { prisma } from "~/db.server"; import { prisma } from "~/db.server";
import { ensureBillingInitialized } from "~/services/billing.server";
import { sendEmail } from "~/services/email.server"; import { sendEmail } from "~/services/email.server";
import { logger } from "~/services/logger.service"; import { logger } from "~/services/logger.service";
import { SpaceService } from "~/services/space.server"; import { SpaceService } from "~/services/space.server";
@ -40,6 +41,8 @@ export async function createWorkspace(
}, },
}); });
await ensureBillingInitialized(workspace.id);
await spaceService.createSpace({ await spaceService.createSpace({
name: "Profile", name: "Profile",
description: profileRule, description: profileRule,

View File

@ -6,11 +6,7 @@
*/ */
import { prisma } from "~/db.server"; import { prisma } from "~/db.server";
import { import { getPlanConfig } from "~/config/billing.server";
BILLING_CONFIG,
isBillingEnabled,
getPlanConfig,
} from "~/config/billing.server";
import type { PlanType, Subscription } from "@prisma/client"; import type { PlanType, Subscription } from "@prisma/client";
export type CreditOperation = "addEpisode" | "search" | "chatMessage"; export type CreditOperation = "addEpisode" | "search" | "chatMessage";
@ -114,7 +110,7 @@ export async function initializeSubscription(
/** /**
* Ensure workspace has billing records initialized * Ensure workspace has billing records initialized
*/ */
async function ensureBillingInitialized(workspaceId: string) { export async function ensureBillingInitialized(workspaceId: string) {
const workspace = await prisma.workspace.findUnique({ const workspace = await prisma.workspace.findUnique({
where: { id: workspaceId }, where: { id: workspaceId },
include: { include: {

View File

@ -760,7 +760,7 @@ export async function hasCredits(
} }
const userUsage = workspace.user.UserUsage; const userUsage = workspace.user.UserUsage;
const subscription = workspace.Subscription; // const subscription = workspace.Subscription;
// If has available credits, return true // If has available credits, return true
if (userUsage.availableCredits >= creditCost) { if (userUsage.availableCredits >= creditCost) {
@ -768,9 +768,9 @@ export async function hasCredits(
} }
// If overage is enabled (Pro/Max), return true // If overage is enabled (Pro/Max), return true
if (subscription.enableUsageBilling) { // if (subscription.enableUsageBilling) {
return true; // return true;
} // }
// Free plan with no credits left // Free plan with no credits left
return false; return false;

View File

@ -574,8 +574,19 @@ model UserUsage {
updatedAt DateTime @updatedAt updatedAt DateTime @updatedAt
deleted DateTime? deleted DateTime?
// Current period tracking
availableCredits Int @default(0) availableCredits Int @default(0)
usedCredits Int @default(0) usedCredits Int @default(0)
overageCredits Int @default(0) // Credits used beyond monthly allocation
// Last reset tracking
lastResetAt DateTime @default(now())
nextResetAt DateTime?
// Usage breakdown (optional analytics)
episodeCreditsUsed Int @default(0)
searchCreditsUsed Int @default(0)
chatCreditsUsed Int @default(0)
user User @relation(fields: [userId], references: [id]) user User @relation(fields: [userId], references: [id])
userId String @unique userId String @unique
@ -614,6 +625,69 @@ model WebhookDeliveryLog {
createdAt DateTime @default(now()) createdAt DateTime @default(now())
} }
model Subscription {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Stripe integration
stripeCustomerId String? @unique
stripeSubscriptionId String? @unique
stripePriceId String?
stripeCurrentPeriodEnd DateTime?
// Plan details
planType PlanType @default(FREE)
status SubscriptionStatus @default(ACTIVE)
// Monthly credits allocation
monthlyCredits Int @default(0)
// Billing cycle tracking
currentPeriodStart DateTime @default(now())
currentPeriodEnd DateTime
// Usage-based pricing (for PRO plan)
enableUsageBilling Boolean @default(false)
usagePricePerCredit Float? // Price per credit after monthly quota
// Overage tracking
overageCreditsUsed Int @default(0)
overageAmount Float @default(0)
// Relations
workspace Workspace @relation(fields: [workspaceId], references: [id])
workspaceId String @unique
BillingHistory BillingHistory[]
}
model BillingHistory {
id String @id @default(uuid())
createdAt DateTime @default(now())
// Billing period
periodStart DateTime
periodEnd DateTime
// Credits tracking
monthlyCreditsAllocated Int
creditsUsed Int
overageCreditsUsed Int
// Charges
subscriptionAmount Float
usageAmount Float // Overage charges
totalAmount Float
// Stripe integration
stripeInvoiceId String? @unique
stripePaymentStatus String?
// Relations
subscription Subscription @relation(fields: [subscriptionId], references: [id])
subscriptionId String
}
model Workspace { model Workspace {
id String @id @default(uuid()) id String @id @default(uuid())
createdAt DateTime @default(now()) createdAt DateTime @default(now())
@ -643,6 +717,21 @@ model Workspace {
RecallLog RecallLog[] RecallLog RecallLog[]
Space Space[] Space Space[]
MCPSession MCPSession[] MCPSession MCPSession[]
Subscription Subscription?
}
enum PlanType {
FREE
PRO
MAX
}
enum SubscriptionStatus {
ACTIVE
CANCELED
PAST_DUE
TRIALING
PAUSED
} }
enum AuthenticationMethod { enum AuthenticationMethod {
@ -656,6 +745,7 @@ enum IngestionStatus {
COMPLETED COMPLETED
FAILED FAILED
CANCELLED CANCELLED
NO_CREDITS
} }
enum UserType { enum UserType {