Skip to content

feat(enterprise): cloud whitelabeling for enterprise orgs#4047

Merged
waleedlatif1 merged 20 commits intostagingfrom
feat/enterprise
Apr 8, 2026
Merged

feat(enterprise): cloud whitelabeling for enterprise orgs#4047
waleedlatif1 merged 20 commits intostagingfrom
feat/enterprise

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Adds a Whitelabeling settings tab (Enterprise section) for enterprise org admins on the hosted platform
  • Stores per-org branding config (logo, brand name, colors, links, hide powered-by toggle) in a new whitelabel_settings JSON column on the organization table
  • Merges org-level settings over instance env var branding via a layered resolution system — self-hosted env var behavior is unchanged
  • Injects CSS variable overrides for custom colors across the workspace via a new BrandingProvider React context in the workspace layout
  • Sidebar uses useOrgBrandConfig() to reflect org branding live
  • API route (GET/PUT /api/organizations/[id]/whitelabel) with session, membership, role, and enterprise plan checks + audit logging
  • Logo uploads reuse existing profile-pictures storage context — no new bucket needed

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Apr 8, 2026 7:20pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 8, 2026

PR Summary

Medium Risk
Introduces a new org-scoped settings API and persists arbitrary branding JSON on organization, plus runtime CSS injection in the workspace; issues here could leak branding data across orgs or cause UI/theme regressions if gating or merging logic is wrong.

Overview
Adds cloud whitelabeling per enterprise organization by storing org-specific branding in a new organization.whitelabel_settings JSON column and exposing it via a new GET/PUT /api/organizations/[id]/whitelabel route with session, membership, owner/admin, and enterprise-plan checks plus audit logging.

Updates the workspace UI to consume org branding dynamically: a new BrandingProvider merges org settings over instance env branding and injects CSS variable overrides, the sidebar switches to useOrgBrandConfig(), and a new Enterprise settings tab (whitelabeling) provides a form to edit logo/name/colors/links and the "hide powered by" toggle using React Query hooks.

Reviewed by Cursor Bugbot for commit ebe7e5c. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 8, 2026

Greptile Summary

This PR adds a cloud whitelabeling feature for enterprise orgs, storing per-org branding config (logo, colors, brand name, links, hide-powered-by toggle) in a new whitelabel_settings JSON column on the organization table. Org-level settings are layered over instance env-var branding via mergeOrgBrandConfig, injected as CSS variable overrides through a new BrandingProvider React context, and surfaced in a new enterprise settings tab gated behind membership, admin/owner role, and enterprise plan checks.

Confidence Score: 5/5

Safe to merge — all previously flagged issues have been resolved and the two remaining findings are minor P2 suggestions.

The critical concerns from prior review rounds (enterprise plan scope check, onSuccess→onSettled, auth layering) have all been addressed. The two new findings — a serial fetch waterfall causing a brief flash of default branding, and redundant CSS variable declarations in generateOrgThemeCSS — are both P2 style suggestions that do not affect correctness or data integrity. The migration is purely additive (nullable column), the API guards are correctly layered, and color values are strictly validated before CSS injection.

apps/sim/ee/whitelabeling/components/branding-provider.tsx (waterfall fetch), apps/sim/ee/whitelabeling/org-branding-utils.ts (duplicate CSS declarations)

Vulnerabilities

No security concerns identified. Color values are validated with a strict hex regex before being injected into <style> elements, preventing CSS injection. The PUT endpoint enforces membership, admin/owner role, and org-scoped enterprise plan checks. Logo URLs are validated as well-formed URLs. The GET endpoint intentionally allows any org member to read branding settings (required for the BrandingProvider to serve all workspace users).

Important Files Changed

Filename Overview
apps/sim/app/api/organizations/[id]/whitelabel/route.ts New GET/PUT API route for org whitelabel settings; enterprise plan check correctly scoped to target org, membership + role guards in place, audit logging wired
apps/sim/ee/whitelabeling/components/branding-provider.tsx Client-side context provider merging instance and org branding; serial fetch waterfall (orgs → whitelabel) can cause brief flash of default colors
apps/sim/ee/whitelabeling/components/whitelabeling-settings.tsx Settings form with logo upload, color pickers, link fields; render-phase setState pattern is consistent with other forms; enterprise/role guards applied behind billing flag
apps/sim/ee/whitelabeling/hooks/whitelabel.ts React Query hooks for fetching and mutating whitelabel settings; correctly uses onSettled for cache invalidation, signal forwarded, staleTime set
apps/sim/ee/whitelabeling/org-branding-utils.ts Merge helpers and CSS variable generator; duplicate CSS declarations when both primaryColor and primaryHoverColor are set (functionally correct but redundant)
apps/sim/ee/whitelabeling/org-branding.ts Server-side org branding fetch utility, correctly logs errors and returns null on failure
apps/sim/lib/branding/types.ts Adds OrganizationWhitelabelSettings interface as the shared source of truth for org branding fields
packages/db/schema.ts Adds whitelabel_settings JSON column to the organization table; inline type is consistent with cross-package boundary constraints
packages/db/migrations/0188_short_luke_cage.sql Additive migration: ALTER TABLE adds nullable json column — safe to run on live data
apps/sim/app/workspace/[workspaceId]/layout.tsx Wraps workspace in BrandingProvider; correct placement ensures sidebar and all child components can consume org brand config
apps/sim/app/workspace/[workspaceId]/settings/navigation.ts Adds whitelabeling nav item under enterprise section, correctly gated with requiresHosted and requiresEnterprise flags

Sequence Diagram

sequenceDiagram
    participant Browser
    participant BrandingProvider
    participant OrgQuery as useOrganizations()
    participant WLQuery as useWhitelabelSettings()
    participant API as /api/organizations/[id]/whitelabel

    Browser->>BrandingProvider: Mount workspace layout
    BrandingProvider->>OrgQuery: fetch active org
    OrgQuery-->>BrandingProvider: { activeOrganization: { id } }
    BrandingProvider->>WLQuery: fetch whitelabel settings (orgId)
    WLQuery->>API: GET /api/organizations/:id/whitelabel
    API-->>WLQuery: { data: OrganizationWhitelabelSettings }
    WLQuery-->>BrandingProvider: orgSettings
    BrandingProvider->>Browser: inject CSS vars + provide BrandConfig context
    Note over Browser: Sidebar reads useOrgBrandConfig() → org logo & brand name

    Browser->>API: PUT /api/organizations/:id/whitelabel
    Note over API: Checks: session → member → admin/owner → enterprise plan
    API-->>Browser: { data: updated settings }
    Note over Browser: onSettled invalidates whitelabelKeys + organizationKeys.detail
Loading

Reviews (3): Last reviewed commit: "fix(enterprise): remove webp from logo a..." | Re-trigger Greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

@waleedlatif1 waleedlatif1 reopened this Apr 8, 2026
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ebe7e5c. Configure here.

… injection

React Query returns isLoading: false with data: undefined during SSR, so the
previous brandingLoading condition was always false on the server — initialCache
was never injected into brandConfig. Changing to !orgSettings correctly applies
the cookie cache both during SSR and while the client-side query loads, eliminating
the logo flash on hard refresh.
@waleedlatif1 waleedlatif1 merged commit 1189400 into staging Apr 8, 2026
11 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/enterprise branch April 8, 2026 19:33
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.

1 participant