Skip to content

Commit 593719c

Browse files
bchapuisclaude
andcommitted
Fix trigger plan resolution by querying users table instead of org subscription status
The org subscriptionStatus can diverge from users.plan (e.g. canceled-but-in-period, trialing, or manually upgraded users). Replace resolveUserPlan with resolveOrganizationPlan which checks if any org member has plan "pro", matching the same source of truth used by manual execution. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 95afea8 commit 593719c

7 files changed

Lines changed: 28 additions & 25 deletions

File tree

apps/api/src/db/queries.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,19 +2156,22 @@ export async function getOrganizationBillingInfo(
21562156
}
21572157

21582158
/**
2159-
* Derive user plan from organization billing info.
2160-
* Pro if has active subscription OR canceled but still in billing period.
2161-
*/
2162-
export function resolveUserPlan(billingInfo: {
2163-
subscriptionStatus: string | null;
2164-
currentPeriodEnd: Date | null;
2165-
}): string {
2166-
const hasProAccess =
2167-
billingInfo.subscriptionStatus === "active" ||
2168-
(billingInfo.subscriptionStatus === "canceled" &&
2169-
billingInfo.currentPeriodEnd !== null &&
2170-
billingInfo.currentPeriodEnd > new Date());
2171-
return hasProAccess ? "pro" : "trial";
2159+
* Resolve user plan for an organization by checking its members.
2160+
* Used by automated triggers where no specific user context is available.
2161+
* Returns "pro" if any member has a pro plan, "trial" otherwise.
2162+
*/
2163+
export async function resolveOrganizationPlan(
2164+
db: ReturnType<typeof createDatabase>,
2165+
organizationId: string
2166+
): Promise<string> {
2167+
const [user] = await db
2168+
.select({ plan: users.plan })
2169+
.from(users)
2170+
.where(
2171+
and(eq(users.organizationId, organizationId), eq(users.plan, Plan.PRO))
2172+
)
2173+
.limit(1);
2174+
return user?.plan ?? Plan.TRIAL;
21722175
}
21732176

21742177
/**

apps/api/src/email.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { Bindings } from "./context";
44
import {
55
createDatabase,
66
getOrganizationBillingInfo,
7-
resolveUserPlan,
7+
resolveOrganizationPlan,
88
} from "./db";
99
import { getAgentByName } from "./durable-objects/agent-utils";
1010
import { createWorkerRuntime } from "./runtime/cloudflare-worker-runtime";
@@ -179,7 +179,7 @@ async function triggerWorkflowForEmail({
179179
userId: "email_trigger",
180180
organizationId,
181181
computeCredits: billingInfo.computeCredits,
182-
userPlan: resolveUserPlan(billingInfo),
182+
userPlan: await resolveOrganizationPlan(db, organizationId),
183183
workflow: {
184184
id: workflow.id,
185185
name: workflow.name,

apps/api/src/queue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { createDatabase } from "./db";
44
import {
55
getOrganizationBillingInfo,
66
getQueueTriggersByQueue,
7-
resolveUserPlan,
7+
resolveOrganizationPlan,
88
} from "./db/queries";
99
import { getAgentByName } from "./durable-objects/agent-utils";
1010
import { createWorkerRuntime } from "./runtime/cloudflare-worker-runtime";
@@ -42,7 +42,7 @@ async function executeWorkflow(
4242
userId: "queue_trigger",
4343
organizationId: workflowInfo.organizationId,
4444
computeCredits: billingInfo.computeCredits,
45-
userPlan: resolveUserPlan(billingInfo),
45+
userPlan: await resolveOrganizationPlan(db, workflowInfo.organizationId),
4646
workflow: {
4747
id: workflowInfo.id,
4848
name: workflowData.name,

apps/api/src/routes/discord-webhook.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
getDiscordBotById,
99
getDiscordTriggersByBot,
1010
getOrganizationBillingInfo,
11-
resolveUserPlan,
11+
resolveOrganizationPlan,
1212
} from "../db";
1313
import { getAgentByName } from "../durable-objects/agent-utils";
1414
import { createWorkerRuntime } from "../runtime/cloudflare-worker-runtime";
@@ -299,7 +299,7 @@ async function executeWorkflow(
299299
userId: "discord_trigger",
300300
organizationId,
301301
computeCredits: billingInfo.computeCredits,
302-
userPlan: resolveUserPlan(billingInfo),
302+
userPlan: await resolveOrganizationPlan(db, organizationId),
303303
workflow: {
304304
id: workflow.id,
305305
name: workflow.name,

apps/api/src/routes/telegram-webhook.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
getTelegramBot,
99
getTelegramSecretTokenByBot,
1010
getTelegramTriggersByBot,
11-
resolveUserPlan,
11+
resolveOrganizationPlan,
1212
} from "../db";
1313
import { getAgentByName } from "../durable-objects/agent-utils";
1414
import { createWorkerRuntime } from "../runtime/cloudflare-worker-runtime";
@@ -216,7 +216,7 @@ async function executeWorkflow(
216216
userId: "telegram_trigger",
217217
organizationId,
218218
computeCredits: billingInfo.computeCredits,
219-
userPlan: resolveUserPlan(billingInfo),
219+
userPlan: await resolveOrganizationPlan(db, organizationId),
220220
workflow: {
221221
id: workflow.id,
222222
name: workflow.name,

apps/api/src/routes/whatsapp-webhook.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
getWhatsAppAccount,
99
getWhatsAppTriggersByAccount,
1010
getWhatsAppVerifyTokenByAccount,
11-
resolveUserPlan,
11+
resolveOrganizationPlan,
1212
} from "../db";
1313
import { getAgentByName } from "../durable-objects/agent-utils";
1414
import { createWorkerRuntime } from "../runtime/cloudflare-worker-runtime";
@@ -322,7 +322,7 @@ async function executeWorkflow(
322322
userId: "whatsapp_trigger",
323323
organizationId,
324324
computeCredits: billingInfo.computeCredits,
325-
userPlan: resolveUserPlan(billingInfo),
325+
userPlan: await resolveOrganizationPlan(db, organizationId),
326326
workflow: {
327327
id: workflow.id,
328328
name: workflow.name,

apps/api/src/scheduled.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
createDatabase,
66
getActiveScheduledTriggers,
77
getOrganizationBillingInfo,
8-
resolveUserPlan,
8+
resolveOrganizationPlan,
99
} from "./db";
1010
import { getAgentByName } from "./durable-objects/agent-utils";
1111
import { createWorkerRuntime } from "./runtime/cloudflare-worker-runtime";
@@ -74,7 +74,7 @@ export async function handleScheduledEvent(
7474
userId: "scheduled_trigger",
7575
organizationId: workflow.organizationId,
7676
computeCredits: billingInfo.computeCredits,
77-
userPlan: resolveUserPlan(billingInfo),
77+
userPlan: await resolveOrganizationPlan(db, workflow.organizationId),
7878
workflow: {
7979
id: workflow.id,
8080
name: workflow.name,

0 commit comments

Comments
 (0)