Skip to content

fix: route organization creation through auth hooks#5055

Merged
Kitenite merged 2 commits into
mainfrom
debug-veedoo-payment-issu
Jun 3, 2026
Merged

fix: route organization creation through auth hooks#5055
Kitenite merged 2 commits into
mainfrom
debug-veedoo-payment-issu

Conversation

@Kitenite

@Kitenite Kitenite commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Root Cause

The desktop app creates additional organizations through the tRPC organization.create route. That route inserted directly into the database, bypassing Better Auth afterCreateOrganization hooks where billing setup runs. As a result, second organizations could miss billing lifecycle setup and the upgrade flow would fail to open checkout.

Validation

  • bun run lint
  • bun run typecheck

Open in Stage

Summary by cubic

Route organization creation through Better Auth to trigger org hooks for billing and default setup, and add error handling for failed creates. Fixes failed upgrade checkout for second organizations created via the desktop app.

  • Bug Fixes
    • Replace direct DB inserts with auth.api.createOrganization to run Stripe and default setup hooks.
    • Remove manual member/status seeding; hooks are the source of truth.
    • Throw TRPCError when createOrganization returns no org to prevent silent failures.

Written for commit 4feea34. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Refactor
    • Centralized organization creation into a shared authentication service for more consistent and maintainable behavior.
  • Bug Fixes
    • Improved error handling: failed organization creation now surfaces a clear internal-server error instead of continuing silently.

@stage-review

stage-review Bot commented Jun 2, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 1 individual chapter for you:

Title
1 Route organization creation through Better Auth
Open in Stage

Chapters generated by Stage for commit 4feea34 on Jun 2, 2026 9:20pm UTC.

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e093bc8-9123-4862-992e-81507237a09b

📥 Commits

Reviewing files that changed from the base of the PR and between 0bbdac6 and 4feea34.

📒 Files selected for processing (1)
  • packages/trpc/src/router/organization/organization.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/trpc/src/router/organization/organization.ts

📝 Walkthrough

Walkthrough

The tRPC organization router's create mutation now imports auth and delegates organization creation to auth.api.createOrganization(name, slug, logo, userId), removing inline organization inserts, owner membership creation, and default-status seeding; it throws INTERNAL_SERVER_ERROR if the API returns falsy.

Changes

Organization Creation Delegation

Layer / File(s) Summary
Organization creation delegated to auth API
packages/trpc/src/router/organization/organization.ts
Adds auth import from @superset/auth/server, removes seedDefaultStatuses import, and refactors organizationRouter.create to call auth.api.createOrganization with name, slug, logo, and the session userId; the mutation throws INTERNAL_SERVER_ERROR if the API result is falsy.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through imports, tidy and spry,

Pushed creation upward to the auth sky,
No more inline seeds or dual-way toil,
One API call — clean fields in the soil,
A happy rabbit nibbles the spoil.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: routing organization creation through Better Auth hooks instead of direct database inserts.
Description check ✅ Passed The description provides clear context on the bug fix, root cause, validation steps, and related issue. All key sections from the template are addressed.
Linked Issues check ✅ Passed The PR successfully addresses issue #5048 by routing organization creation through Better Auth hooks to ensure billing setup runs for second organizations, preventing upgrade checkout failures.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the organization creation routing through Better Auth and removing unused imports related to direct database operations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch debug-veedoo-payment-issu

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@capy-ai

capy-ai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@greptile-apps

greptile-apps Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes second-organization billing setup by routing the tRPC organization.create mutation through auth.api.createOrganization instead of inserting directly into the database. Previously, direct DB inserts bypassed the afterCreateOrganization Better Auth hook where Stripe customer creation and seedDefaultStatuses run.

  • Removes manual db.insert(organizations), db.insert(members), and seedDefaultStatuses calls from the tRPC create mutation and replaces them with a single auth.api.createOrganization call passing userId in the body.
  • Removes the now-unused seedDefaultStatuses import; other imports (stripeClient, organizations, members) remain in use by other handlers in the file.

Confidence Score: 3/5

The core fix is correct and necessary, but the create mutation can silently return null to callers if auth.api.createOrganization does not produce an organization, leaving the client with no error signal.

The existing codebase at packages/auth/src/server.ts already defends against a null return from auth.api.createOrganization with personalOrg?.id ?? null, yet the new tRPC handler returns the result directly without any null check. If the call fails silently, downstream code receives null instead of an organization object and no TRPCError is raised.

packages/trpc/src/router/organization/organization.ts — specifically the new create mutation return value handling.

Important Files Changed

Filename Overview
packages/trpc/src/router/organization/organization.ts Replaces manual DB inserts with auth.api.createOrganization to route through Better Auth hooks; return value is not null-checked, which can silently return null to the caller on failure.

Sequence Diagram

sequenceDiagram
    participant Client
    participant tRPC as tRPC create handler
    participant BetterAuth as auth.api.createOrganization
    participant DB as Database
    participant Hooks as afterCreateOrganization hook
    participant Stripe

    Client->>tRPC: organization.create(name, slug, logo)
    tRPC->>tRPC: domain guard check
    tRPC->>BetterAuth: "createOrganization({ name, slug, logo, userId })"
    BetterAuth->>DB: INSERT organizations
    BetterAuth->>DB: INSERT members (owner)
    BetterAuth->>Hooks: afterCreateOrganization
    Hooks->>Stripe: customers.create(...)
    Hooks->>DB: seedDefaultStatuses(org.id)
    BetterAuth-->>tRPC: organization (or null)
    tRPC-->>Client: organization
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/trpc/src/router/organization/organization.ts:217-226
**Unhandled null return from `createOrganization`**

`auth.api.createOrganization` can return `null` — the in-repo call at `packages/auth/src/server.ts:189` already handles this with `personalOrg?.id ?? null`. Here the return value is used directly as the mutation result: if Better Auth returns `null` (e.g., a slug collision after the domain guard or an internal error in the hook chain), the tRPC mutation silently returns `null` to the caller instead of throwing a `TRPCError`. A null result will silently fail any downstream code that expects an organization object, and the user gets no meaningful error message.

Reviews (1): Last reviewed commit: "fix billing upgrade for second orgs" | Re-trigger Greptile

Comment thread packages/trpc/src/router/organization/organization.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Architecture diagram
sequenceDiagram
    participant Client as Desktop Client
    participant TRPC as tRPC Router
    participant BA as Better Auth
    participant DB as Database
    participant Stripe as Stripe API
    participant Internal as Internal Hooks

    Note over Client,Internal: Organization Creation Flow

    Client->>TRPC: CHANGED: tRPC organization.create
    TRPC->>BA: CHANGED: auth.api.createOrganization({body:{name,slug,logo,userId}})
    
    Note over BA: AFTER: New organization created
    BA->>DB: Create organization record
    BA->>DB: Create owner membership record
    BA-->>BA: Trigger afterCreateOrganization hook
    
    BA->>Internal: Run default status seeding hook
    Internal->>DB: Insert default statuses
    Internal-->>BA: Statuses created
    
    BA->>Stripe: Run Stripe customer creation hook
    Stripe-->>BA: Customer created
    
    BA-->>TRPC: Return created organization
    TRPC-->>Client: Return organization response

    Note over Client,Internal: Key Change: Better Auth now handles all side effects<br/>instead of direct DB inserts and manual hook calls
Loading

Re-trigger cubic

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@Kitenite Kitenite merged commit d949c10 into main Jun 3, 2026
17 checks passed
saddlepaddle added a commit that referenced this pull request Jun 3, 2026
Bundled fixes since 0.2.21 (no command-surface changes):
- #5067 pty-daemon: raise RLIMIT_NOFILE + surface real spawn errno
- #5066 projects: restrict deletion to organization owners
- #5055 route organization creation through auth hooks

Also syncs bun.lock with the desktop 1.12.2 / host-service 0.8.18 bump
that landed in e173c89 without a lockfile update.
saddlepaddle added a commit that referenced this pull request Jun 3, 2026
* chore(desktop): bump version to 1.12.2 (host-service 0.8.17 -> 0.8.18)

* release(cli): cut cli v0.2.22

Bundled fixes since 0.2.21 (no command-surface changes):
- #5067 pty-daemon: raise RLIMIT_NOFILE + surface real spawn errno
- #5066 projects: restrict deletion to organization owners
- #5055 route organization creation through auth hooks

Also syncs bun.lock with the desktop 1.12.2 / host-service 0.8.18 bump
that landed in e173c89 without a lockfile update.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] the upgrade button does not open the upgrade page if i create a 2nd org from superset app and try to upgrade it

2 participants