Connecting HubSpot — mirror Companies, Contacts, and Deals

The HubSpot connector mirrors your HubSpot Companies, Contacts, and Deals into Turtini's CRM. Companies land in Accounts, Contacts in Contacts, Deals in Opportunities — all carrying a `hubspotId` and `hubspotSyncedAt` so you can trace any record back to the source.

How to connect:
1. Settings → Integrations → HubSpot card
2. Click "Connect HubSpot"
3. A HubSpot login popup appears — sign in with the user account whose access the connector should use (typically a Super Admin in HubSpot)
4. Approve the requested scopes — `crm.objects.companies.read`, `crm.objects.contacts.read`, `crm.objects.deals.read`, `oauth`
5. The popup closes and the connection activates. You'll see your HubSpot Hub ID + last-sync timestamp.

What mirrors over:
• HubSpot Companies → `accounts` (name, domain, industry, address, phone, employee count, lifecycle stage)
• HubSpot Contacts → `contacts` (name, email, phone, job title, linked to the parent company via `accountId`)
• HubSpot Deals → `opportunities` (deal name, amount, close date, stage, deal stage → Turtini stage mapping, pipeline)
• Standard HubSpot properties only; custom properties aren't synced in Phase 1.

Sync cadence:
• Daily scheduled sync pulls everything new or changed since the last run
• "Sync now" button on the integration card runs the same sync on demand
• Sync is idempotent — re-running won't create duplicates; existing records get updated in place by `hubspotId`

Sync scope toggles:
You can disable any of the three object types if you only want a partial mirror. Defaults are all on. Toggle from the integration card — the next "Sync now" or scheduled run honors the new scope; previously-synced records of a disabled type are left intact.

What this is NOT (Phase 1):
• Two-way sync. Changes in Turtini don't write back to HubSpot.
• Custom-property sync. Standard properties only.
• Webhooks / real-time push. Updates arrive on the next scheduled run or manual sync.

OAuth client setup:
Turtini ships a HubSpot OAuth app, so your org doesn't need to register one in HubSpot. The redirect URL must include `{your-turtini-domain}/oauth-callback.html` — this is handled automatically. If you see "POPUP_CLOSED" or "redirect URL mismatch," it's because your browser blocked the popup or you're running on a custom domain that hasn't been added to the HubSpot app — contact support to add it.

Disconnect: the same integration card shows "Disconnect" — clears the stored refresh token; mirrored records remain in Turtini with their `hubspotId` intact so you can reconnect later without losing the link.

Last-sync visibility: the card shows last-sync time, per-object counts (companies, contacts, deals) from the most recent run, and the last-sync error (if any). The same data is available to Wally so you can ask "When did HubSpot last sync?" or "How many deals did we pull from HubSpot yesterday?" from the chat surface.