-
Notifications
You must be signed in to change notification settings - Fork 190
fix: keep plan usage off real credits (PAYG=default only) #2658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
678d914
d0e95a7
600bae3
d50b26f
0cd3e64
a1e295a
c2b0c46
a1784da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| import { db, tables, eq } from "@llmgateway/db"; | ||
| import { db, tables } from "@llmgateway/db"; | ||
|
|
||
| interface PersonalOrgUser { | ||
| id: string; | ||
|
|
@@ -55,12 +55,10 @@ export async function getOrCreatePersonalOrg(user: PersonalOrgUser) { | |
| } | ||
|
|
||
| // Get or create the dedicated "Chat" organization for a user. This backs | ||
| // chat.llmgateway.io (apps/playground): the chat plan, pay-as-you-go top-ups, | ||
| // and all playground billing live here, kept separate from the DevPass personal | ||
| // org used by the coding product. | ||
| // | ||
| // On first creation, any pay-as-you-go balance the user had on their personal | ||
| // org is migrated to the chat org so the playground keeps access to it. | ||
| // chat.llmgateway.io (apps/playground), kept separate from the DevPass personal | ||
| // org used by the coding product. Chat orgs run purely on virtual chat-plan | ||
| // credits and never hold a real `credits` balance — pay-as-you-go lives on | ||
| // default orgs. | ||
|
Comment on lines
+59
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When PAYG stops being copied into the Chat org, opening Useful? React with 👍 / 👎. |
||
| export async function getOrCreateChatOrg(user: PersonalOrgUser) { | ||
| const userOrgs = await db.query.userOrganization.findMany({ | ||
| where: { | ||
|
|
@@ -79,14 +77,6 @@ export async function getOrCreateChatOrg(user: PersonalOrgUser) { | |
| return existingChatOrg.organization; | ||
| } | ||
|
|
||
| const personalOrg = userOrgs.find( | ||
| (uo) => uo.organization?.kind === "devpass", | ||
| )?.organization; | ||
| const migratedCredits = | ||
| personalOrg && parseFloat(personalOrg.credits || "0") > 0 | ||
| ? personalOrg.credits | ||
| : null; | ||
|
|
||
| return await db.transaction(async (tx) => { | ||
| const [newOrg] = await tx | ||
| .insert(tables.organization) | ||
|
|
@@ -95,7 +85,6 @@ export async function getOrCreateChatOrg(user: PersonalOrgUser) { | |
| kind: "chat", | ||
| billingEmail: user.email, | ||
| retentionLevel: "none", | ||
| ...(migratedCredits ? { credits: migratedCredits } : {}), | ||
| }) | ||
| .returning(); | ||
|
|
||
|
|
@@ -111,33 +100,6 @@ export async function getOrCreateChatOrg(user: PersonalOrgUser) { | |
| mode: "credits", | ||
| }); | ||
|
|
||
| // One-time migration of the personal org's pay-as-you-go balance into the | ||
| // chat org. Recorded as offsetting credit_gift transactions (excluded from | ||
| // revenue analytics) so the move is auditable on both orgs. | ||
| if (migratedCredits && personalOrg) { | ||
| await tx | ||
| .update(tables.organization) | ||
| .set({ credits: "0" }) | ||
| .where(eq(tables.organization.id, personalOrg.id)); | ||
|
|
||
| await tx.insert(tables.transaction).values([ | ||
| { | ||
| organizationId: personalOrg.id, | ||
| type: "credit_gift", | ||
| creditAmount: `-${migratedCredits}`, | ||
| status: "completed", | ||
| description: "Balance migrated to Chat organization", | ||
| }, | ||
| { | ||
| organizationId: newOrg.id, | ||
| type: "credit_gift", | ||
| creditAmount: migratedCredits, | ||
| status: "completed", | ||
| description: "Balance migrated from personal organization", | ||
| }, | ||
| ]); | ||
| } | ||
|
|
||
| return newOrg; | ||
| }); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For
kind: "chat"orgs this rejects the samecreditsbalance that powers Chat pay-as-you-go:getOrCreateChatOrgdocuments that the Chat org owns chat plans, PAYG top-ups, and playground billing, and it migrates an existing PAYG balance intoorganization.credits(apps/api/src/utils/personal-org.ts:57-63,90-99). Since the admin org detail page still exposes the Gift Credits action for these orgs, support can no longer grant or adjust Chat PAYG credits and will always get a 400; this guard should not block Chat orgs unless there is a replacement path for gifting their real balance.Useful? React with 👍 / 👎.