Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@devkiran
Copy link
Collaborator

@devkiran devkiran commented Sep 15, 2025

Summary by CodeRabbit

  • New Features

    • HubSpot integration: OAuth install flow, install URL, webhook endpoints with auto-tracking for leads and closed‑won deals.
  • Documentation

    • Added HubSpot app README, CLAUDE guidance, and HubSpot project/manifest docs.
  • Chores

    • Public env example updated with HubSpot credentials and reinstated webhook token; seed data now creates a HubSpot integration; HubSpot app package scaffold added.
  • Refactor

    • Prisma index syntax cleanup (no user-facing impact).

@vercel
Copy link
Contributor

vercel bot commented Sep 15, 2025

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

Project Deployment Preview Updated (UTC)
dub Ready Ready Preview Sep 19, 2025 6:17pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds a HubSpot integration: env vars, OAuth install URL and callback, webhook receiver with signature verification, token refresh and persistence, contact/deal fetchers and Zod schemas/types, event handlers mapping HubSpot events to internal trackLead/trackSale flows, HubSpot app manifests/docs, and minor Prisma index syntax tweaks.

Changes

Cohort / File(s) Summary
Environment variables
apps/web/.env.example
Re-adds SINGULAR_WEBHOOK_TOKEN and adds HUBSPOT_CLIENT_ID and HUBSPOT_CLIENT_SECRET under a new "Hubspot" section.
API routes
apps/web/app/(ee)/api/hubspot/callback/route.ts, apps/web/app/(ee)/api/hubspot/webhook/route.ts
New OAuth callback GET route (validates state, exchanges code, installs integration) and webhook POST route (verifies X-HubSpot-Signature, parses events, dispatches handlers).
Integration wiring
apps/web/lib/actions/get-integration-install-url.ts, apps/web/lib/integrations/hubspot/install.ts
Adds hubspot branch to getIntegrationInstallUrl and generates HubSpot authorize URL with nanoid state stored in Redis (TTL).
Constants & config
apps/web/lib/integrations/hubspot/constants.ts
New HubSpot constants: client id/secret, redirect URI, API host, scopes, state cache prefix, object type IDs.
Schemas & types
apps/web/lib/integrations/hubspot/schema.ts, apps/web/lib/integrations/hubspot/types.ts
Zod schemas for tokens, contacts, deals, webhooks, events and exported TS types inferred from schemas.
Data fetchers
apps/web/lib/integrations/hubspot/get-contact.ts, apps/web/lib/integrations/hubspot/get-deal.ts
Helpers to fetch and validate HubSpot contact and deal objects; return parsed data or null on failure.
Token refresh & persistence
apps/web/lib/integrations/hubspot/refresh-token.ts
refreshAccessToken that refreshes OAuth tokens with HubSpot API, validates existing token expiry, persists new credentials to DB.
Event handlers
apps/web/lib/integrations/hubspot/track-lead.ts, apps/web/lib/integrations/hubspot/track-sale.ts
Handlers mapping webhook payloads to internal trackLead/trackSale flows with lookups, validations, and mode semantics.
Install seed
apps/web/scripts/create-integration.ts
Changes seeded integration record name/slug/description from "Singular" to "HubSpot".
HubSpot app package & manifests
packages/hubspot-app/package.json, packages/hubspot-app/hsproject.json, packages/hubspot-app/src/app/*, packages/hubspot-app/README.md, packages/hubspot-app/CLAUDE.md
New package + HubSpot app/webhook manifests, README and CLAUDE guidance for HubSpot app.
Prisma index syntax
packages/prisma/schema/integration.prisma
Convert array index declarations to shorthand single-field syntax for four indexes (syntactic change, no behavioral difference).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Web as Web App
  participant Redis
  participant Prisma
  participant HubSpot

  rect rgba(200,220,255,0.14)
    note over User,Web: Install initiation
    User->>Web: Click "Install HubSpot"
    Web->>Redis: SET hubspot:install:state:{state} -> workspaceId (TTL)
    Web-->>User: Redirect to HubSpot authorize URL
  end

  rect rgba(200,255,200,0.14)
    note over HubSpot,Web: OAuth callback
    HubSpot-->>Web: GET /api/hubspot/callback?code&state
    Web->>Redis: GET hubspot:install:state:{state} -> workspaceId
    Web->>Prisma: Verify workspace & user ownership
    Web->>HubSpot: POST /oauth/v1/token (exchange code)
    Web->>Prisma: Save InstalledIntegration with credentials
    Web-->>User: Redirect to workspace HubSpot settings
  end

  rect rgba(255,230,200,0.12)
    note over Web: Errors -> structured responses
  end
Loading
sequenceDiagram
  autonumber
  participant HS as HubSpot Webhooks
  participant WA as Webhook Route
  participant P as Prisma
  participant TR as Token Refresh
  participant DF as Data Fetchers
  participant ET as Event Trackers

  HS-->>WA: POST /api/hubspot/webhook (events)
  WA->>WA: Verify X-HubSpot-Signature using HUBSPOT_CLIENT_SECRET
  loop per event
    WA->>P: Resolve InstalledIntegration by hub_id
    WA->>TR: refreshAccessToken(installationId, credentials)
    alt contact.created (objectTypeId "0-1")
      WA->>DF: getHubSpotContact(contactId, accessToken)
      WA->>ET: trackHubSpotLeadEvent(...)
    else deal.created (objectTypeId "0-3")
      WA->>DF: getHubSpotDeal(dealId, accessToken) -> getHubSpotContact(...)
      WA->>ET: trackHubSpotLeadEvent(...)
    else deal.dealstage change (propertyChange)
      WA->>DF: getHubSpotDeal(dealId, accessToken) -> getHubSpotContact(...)
      WA->>ET: trackHubSpotSaleEvent(...)
    end
  end
  WA-->>HS: 200 OK
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • steven-tey

Poem

"I hopped to OAuth, state tucked in hay,
Webhooks sang carrots on a sunny day,
I fetched contacts, deals, refreshed with care,
Installed and signed — a rabbit's share,
Hooray for HubSpot hops! 🥕🐇"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Hubspot integration" directly matches the primary change in the diff — adding a HubSpot integration (OAuth flow, webhooks, integration modules, and HubSpot app artifacts) — and succinctly summarizes the main intent. It is concise and clear for a reviewer scanning PR history. Minor nit: the codebase uses the brand form "HubSpot", so the title's casing is slightly inconsistent with project usage.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hubspot

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6406465 and 0face1b.

📒 Files selected for processing (1)
  • packages/hubspot-app/src/app/app-hsmeta.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/hubspot-app/src/app/app-hsmeta.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: api-tests
  • GitHub Check: build

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.

@socket-security
Copy link

socket-security bot commented Sep 15, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​hubspot/​cli@​7.6.29110093100100

View full report

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/web/lib/integrations/hubspot/track-lead.ts (1)

33-36: Improve observability context in error log

Include workspace id to correlate incidents across tenants.

Apply this diff:

-      console.error(`[HubSpot] No dub_id found for contact ${objectId}.`);
+      console.error(
+        `[HubSpot] No dub_id found for contact ${objectId} (workspace ${workspace.id}).`,
+      );
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bc4342 and 1bae936.

📒 Files selected for processing (1)
  • apps/web/lib/integrations/hubspot/track-lead.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-17T06:41:45.620Z
Learnt from: devkiran
PR: dubinc/dub#2637
File: apps/web/app/(ee)/api/singular/webhook/route.ts:0-0
Timestamp: 2025-07-17T06:41:45.620Z
Learning: In the Singular integration (apps/web/app/(ee)/api/singular/webhook/route.ts), the event names in the singularToDubEvent object have intentionally different casing: "Copy GAID" and "copy IDFA". This casing difference is valid and should not be changed, as these are the correct event names expected from Singular.

Applied to files:

  • apps/web/lib/integrations/hubspot/track-lead.ts
🧬 Code graph analysis (1)
apps/web/lib/integrations/hubspot/track-lead.ts (6)
apps/web/lib/types.ts (1)
  • WorkspaceProps (184-200)
apps/web/lib/integrations/hubspot/types.ts (1)
  • HubSpotAuthToken (4-4)
apps/web/lib/integrations/hubspot/schema.ts (1)
  • hubSpotLeadEventSchema (59-63)
apps/web/lib/integrations/hubspot/get-contact.ts (1)
  • getHubSpotContact (4-39)
apps/web/lib/api/conversions/track-lead.ts (1)
  • trackLead (29-353)
apps/web/lib/integrations/hubspot/get-deal.ts (1)
  • getHubSpotDeal (4-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Vade Review
🔇 Additional comments (2)
apps/web/lib/integrations/hubspot/track-lead.ts (2)

17-19: Overall flow and validation look good

Schema-guarded parse and branching by objectTypeId are sensible.

Also applies to: 21-21, 55-55


42-52: Confirm data‑minimization for HubSpot rawBody (redact to identifiers?)

  • rawBody from the HubSpot webhook is forwarded into the conversions pipeline and JSON.stringified (apps/web/lib/integrations/hubspot/track-lead.ts — rawBody: payload at ~lines 50 & 91; apps/web/lib/api/conversions/track-lead.ts — body: JSON.stringify(rawBody) at 249–250).
  • Same pattern in HubSpot sale and Singular integrations (apps/web/lib/integrations/hubspot/track-sale.ts:77–78; apps/web/lib/integrations/singular/track-lead.ts:~61; apps/web/lib/integrations/singular/track-sale.ts:~64).
  • If you want to redact rawBody to identifiers-only, confirm that change matches your logging/analytics retention and PII/debugging requirements and then update all above call sites to send identifiers-only instead of raw payloads.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json (1)

6-8: Throughput/backpressure check for maxConcurrentRequests=10.

Ensure the webhook handler is idempotent and quick to 2xx under burst loads; otherwise consider lowering concurrency or adding queueing.

packages/hubspot-app/src/app/app-hsmeta.json (1)

14-23: Right‑size scopes (principle of least privilege).

If you aren’t writing contacts, drop crm.objects.contacts.write to reduce install friction; if you do write deals, add crm.objects.deals.write. Pick one of the diffs below accordingly.

-      "requiredScopes": [
-        "oauth",
-        "crm.objects.contacts.read",
-        "crm.objects.contacts.write",
-        "crm.objects.leads.read",
-        "crm.objects.deals.read"
-      ],
+      "requiredScopes": [
+        "oauth",
+        "crm.objects.contacts.read",
+        "crm.objects.leads.read",
+        "crm.objects.deals.read"
+      ],

or

-      "requiredScopes": [
-        "oauth",
-        "crm.objects.contacts.read",
-        "crm.objects.contacts.write",
-        "crm.objects.leads.read",
-        "crm.objects.deals.read"
-      ],
+      "requiredScopes": [
+        "oauth",
+        "crm.objects.contacts.read",
+        "crm.objects.contacts.write",
+        "crm.objects.leads.read",
+        "crm.objects.deals.read",
+        "crm.objects.deals.write"
+      ],
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28d12bb and dedb740.

📒 Files selected for processing (2)
  • packages/hubspot-app/src/app/app-hsmeta.json (1 hunks)
  • packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: api-tests
  • GitHub Check: build
🔇 Additional comments (5)
packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json (2)

6-7: Prod webhook URL looks good; confirm env routing.

Good removal of the ngrok URL. Please confirm your deploy process updates this per environment (e.g., staging/sandbox projects) so preview/dev traffic doesn't hit prod.


10-27: Validate subscription set vs. handlers and property internal name.

Double‑check that your handlers cover contact/deal creation and that "dealstage" matches the internal property name you expect for Closed‑Won transitions.

packages/hubspot-app/src/app/app-hsmeta.json (3)

10-13: Redirect URIs are stable; verify backend config matches exactly.

Make sure your OAuth install/callback code uses these exact URIs per environment to avoid HubSpot mismatch errors.


24-28: Permitted URLs check.

If you plan any client‑side (HubSpot UI) calls beyond api.hubapi.com, add them here; server‑to‑server calls from dub.co don’t need to be listed.


30-33: Docs/live support readiness.

Confirm the documentation URL is published before app review/listing.

@steven-tey steven-tey merged commit a60fa55 into main Sep 19, 2025
8 checks passed
@steven-tey steven-tey deleted the hubspot branch September 19, 2025 18:45
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.

3 participants