Skip to content

feat(console): enrich Salesforce leads with Console account status - #54255

Closed
Slickstef11 wants to merge 1 commit into
devfrom
enterprise-lead-source
Closed

Slickstef11 wants to merge 1 commit into
devfrom
enterprise-lead-source

Conversation

@Slickstef11

@Slickstef11 Slickstef11 commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Distinguish new Enterprise inquiries (enterprise website form) from Console signups (console signup) while preserving original sources on existing Leads and Contacts.
  • Store inference spend only in its dedicated field and keep Description as the visitor's exact message.
  • Enrich Enterprise inquiries with verified Console account status via the private Console lookup. If the lookup fails or takes longer than 3 seconds, the inquiry is still delivered with the Console fields left blank.
  • Add a token-authenticated signup sync endpoint that matches Contacts/unconverted Leads by email or Console Account ID before creating a Lead.
  • Set Company for new signup Leads to the business email domain or Individual for recognized personal-email providers.
  • Add the three Console account fields, field permissions/detail layouts, and Lead-to-Contact conversion mappings as Salesforce metadata.
  • Add a local runner using Salesforce CLI authentication, with sales email and EmailOctopus delivery disabled locally and specific rejection reporting.

Companion Console change

anomalyco/opencode-console#3392 contains the form/FAQ changes, private account lookup, durable signup queue, verified-signup hooks, and worker scheduling.

Validation

  • bun test src/lib/salesforce.test.ts src/lib/console-signup.test.ts script/salesforce-cli-response.test.ts — 25 passed.
  • bun typecheck in packages/console/app — passed.
  • One-off check (not committed) of the real lookup against a local stand-in for Console: when it returned 503, and when it hung, the inquiry still succeeded and created the Lead without Console fields; the hung lookup gave up after 3.0s.
  • Before the rebase, the localhost form and verified signup flows were exercised against the connected Salesforce org, including updating an existing Lead without changing its original source and creating a new console signup Lead.
  • No backfill was run.

Rollout

  • Coordinate this change with the companion Console PR. If this ships first, inquiries still go through; their Console fields stay blank until the lookup is live.
  • Configure the same server-only CONSOLE_CRM_TOKEN on the SST website and Console API/jobs. SST links CONSOLE_CRM_LOOKUP_URL to the stage's Console account-lookup route.
  • Apply/reconcile the Salesforce metadata and assign Console_Account_Sync to the integration user. The metadata was already applied to the connected OpenCode Salesforce org during the approved local setup.
  • Deploy through the normal SST workflow after human review. Application production deployment has not been performed by this PR preparation.

@opencode-agent opencode-agent 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.

Mostly sound, with one blocking regression: the Enterprise form now fails completely whenever the Console account lookup fails.

How I checked: ran the three new test files (25 pass) and bun run typecheck in packages/console/app (passes). I also called handleEnterpriseRequest with a lookup that throws (as lookupConsoleAccount does on a non-2xx response or timeout). The route returned 500 and no Salesforce lead was submitted. I couldn't exercise a real Salesforce org or the companion Console route.

Public API: OpenCode's CLI, SDK, server and plugin APIs are unchanged. The website app gains an internal, token-authenticated POST /api/console-signup endpoint and two infra resources (CONSOLE_CRM_TOKEN secret, CONSOLE_CRM_LOOKUP_URL link). These are additive, but they must be configured before deploying.

Concerns:

  • Blocking: the enterprise inquiry now hard-depends on the Console lookup (see inline). Because the lookup URL targets a route that only exists in the companion Console PR, deploying this first, or any Console outage, would drop every inquiry.
  • Tests: console-signup.test.ts spins up a real local HTTP server to fake Salesforce (see inline).

return Response.json({ error: dict["enterprise.form.error.invalidInferenceSpend"] }, { status: 400 })
}

const account = await (options.accountLookup ?? lookupConsoleAccount)(body.email)

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.

If this lookup throws (Console 5xx/404, 8s timeout, missing token), the outer catch returns 500. The Salesforce lead, the sales email and the EmailOctopus subscription are then all skipped, so the inquiry is lost. On dev this form has no Console dependency. CONSOLE_CRM_LOOKUP_URL also points to a route that only exists in the companion Console PR, so deploying this first would break the form outright.

Enrichment should be best-effort. For example, .catch(() => undefined) here leaves the Console fields off the Lead (since consoleAccount === undefined skips them). Ideally run the lookup alongside the email/subscription calls instead of before them, so it doesn't add up to 8s of latency.

) {
const people: Record<string, unknown>[] = initial.map((person) => ({ ...person }))
const writes: { method: string; path: string; payload: Record<string, unknown> }[] = []
const server = Bun.serve({

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.

syncConsoleAccount already takes an injectable SalesforceRequest, so these tests don't need a real Bun.serve instance, real fetches, or a hand-rolled SOQL/REST emulator with assertions inside the request handler. A plain in-memory request function that records calls would cover the same cases (create once, retry updates, converted Contact not duplicated, auth rejected), with far less code and no network or port state. Please cut this down to those core cases.

@thdxr

thdxr commented Oct 10, 2026

Copy link
Copy Markdown
Member

This branch has been upgraded to V2. We're no longer taking PRs for V1. If you think this is still relevant, please port it over and open it for V2.

— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants