Database Schema

All data is stored in Cloudflare D1 (serverless SQLite). The schema is defined across migration files in the migrations/ directory. The createDB(d1) factory in src/db.js returns async store objects for each table.

Tables

oauth_tokens

Stores Pipedrive OAuth2 tokens per user. Used for both interactive sessions and automation user lookups.

Column Type Description
user_id INTEGER Primary key. Pipedrive user ID.
company_id INTEGER Pipedrive company ID. Indexed for session restoration.
access_token TEXT Current OAuth2 access token.
refresh_token TEXT OAuth2 refresh token.
expires_at INTEGER Token expiration timestamp (Unix epoch).
api_domain TEXT Pipedrive API domain (e.g., https://api.pipedrive.com).
created_at INTEGER Row creation timestamp.
updated_at INTEGER Last update timestamp.

Indexes: idx_oauth_company on company_id.


app_settings

Per-company key-value configuration store. Holds webhook URLs, field mappings, notification preferences, Google Ads settings, webhook credentials, and more.

Column Type Description
company_id INTEGER Pipedrive company ID. Part of compound primary key.
key TEXT Setting key (e.g., webhookUrl, adwordsWebhookUsername, adwordsCurrencyCode). Part of compound primary key.
value TEXT Setting value. Complex values are JSON-serialized.
updated_at INTEGER Last update timestamp.

Primary key: (company_id, key).


sessions

D1-backed session store managed by src/session.js. Cookie-based session tracking with proxy-based dirty detection.

Column Type Description
sid TEXT Primary key. Session ID (from cookie).
data TEXT JSON-serialized session data.
expires_at INTEGER Expiration timestamp. Expired sessions are cleaned up probabilistically.

Indexes: idx_sessions_expires on expires_at.


flip_merge

Temporary storage for flip-merge state (swapping primary and secondary deals). Replaces an in-memory Map for stateless Workers.

Column Type Description
user_id INTEGER Primary key. Pipedrive user ID.
deal_id TEXT The deal ID to flip.
created_at INTEGER Row creation timestamp.

merge_logs

Audit log of all deal/person merges performed through the extension.

Column Type Description
id INTEGER Primary key. Auto-increment.
company_id INTEGER Pipedrive company ID.
user_id INTEGER User who performed the merge.
created_at INTEGER Merge timestamp.
primary_deal_id INTEGER Surviving deal ID.
primary_deal_title TEXT Surviving deal title.
secondary_deal_id INTEGER Merged (deleted) deal ID.
secondary_deal_title TEXT Merged deal title.
primary_person_id INTEGER Surviving person ID (nullable).
primary_person_name TEXT Surviving person name.
secondary_person_id INTEGER Merged person ID (nullable).
secondary_person_name TEXT Merged person name.
merge_persons INTEGER Whether person merge was requested (0/1).
resubscribe_primary INTEGER Whether resubscribe flag was set (0/1).
skip_unsubscribe INTEGER Whether unsubscribe was skipped (0/1).
person_merged INTEGER Whether person merge succeeded (0/1).
person_merge_error TEXT Error message if person merge failed.
unsubscribe_success INTEGER Whether webhook unsubscribe succeeded (nullable).
resubscribe_success INTEGER Whether webhook resubscribe succeeded (nullable).
preserve_deal_count INTEGER Number of deal fields preserved.
preserve_person_count INTEGER Number of person fields preserved.
snapshot TEXT JSON snapshot of field values at merge time.

Indexes: idx_merge_logs_company on company_id, idx_merge_logs_created on (company_id, created_at DESC).


google_ads_tokens

Stores Google Ads OAuth2 tokens per company. Separate from the Pipedrive OAuth tokens.

Column Type Description
company_id INTEGER Primary key. Pipedrive company ID.
access_token TEXT Google OAuth2 access token.
refresh_token TEXT Google OAuth2 refresh token.
expires_at INTEGER Token expiration timestamp (Unix epoch).
created_at TEXT Row creation timestamp.
updated_at TEXT Last update timestamp.

adwords_conversions

Log of all Google Ads conversion uploads. Includes full request/response payloads for debugging.

Column Type Description
id INTEGER Primary key. Auto-increment.
company_id INTEGER Pipedrive company ID.
deal_id INTEGER Pipedrive deal ID.
milestone TEXT Conversion name (stored in the milestone column for backward compatibility).
gclid TEXT Google Click ID.
conversion_action_id TEXT Google Ads conversion action resource name.
conversion_value REAL Monetary value of the conversion.
currency_code TEXT Currency code (default: USD).
conversion_date_time TEXT Conversion timestamp in Google Ads format.
order_id TEXT Unique order ID for deduplication.
adjustment_type TEXT CONVERSION for all new uploads.
status TEXT success, error, or queued.
error_message TEXT Error details if upload failed.
group_id INTEGER Conversion action row ID (nullable).
group_uuid TEXT Legacy field (nullable, no longer used).
group_name TEXT Conversion action name at time of upload.
request_payload TEXT JSON of the request sent to Google Ads API.
response_payload TEXT JSON of the response from Google Ads API.
webhook_source_ip TEXT IP address of the inbound webhook.
webhook_request TEXT JSON of the inbound webhook request body.
webhook_response TEXT JSON of the response sent back to the webhook caller.
created_at TEXT Row creation timestamp.

Indexes: idx_adwords_conv_company, idx_adwords_conv_deal, idx_adwords_conv_group.


conversion_groups

Defines conversion actions. Each row maps to one Google Ads conversion action with a name and value.

Column Type Description
id INTEGER Primary key. Auto-increment.
company_id INTEGER Pipedrive company ID.
uuid TEXT Unique. Legacy identifier (no longer used in webhook URLs).
name TEXT Conversion name used in webhook body (e.g., Inquiry).
conversion_action_id TEXT Google Ads conversion action resource name.
conversion_action_name TEXT Display name of the conversion action.
upload_customer_id TEXT Target customer ID for uploads (may differ from MCC for cross-account tracking).
initial_value REAL Conversion value (accessed as value in the application layer).
initial_milestone_id TEXT Legacy field (unused).
currency_code TEXT Legacy field (currency is now a global setting).
milestones TEXT Legacy field (restatements removed).
created_at TEXT Row creation timestamp.
updated_at TEXT Last update timestamp.

Indexes: idx_conv_groups_company on company_id.


retry_queue

General-purpose retry queue for deferred background tasks. Used for Google Ads GCLID retry (gads_click_not_found).

Column Type Description
id INTEGER Primary key. Auto-increment.
company_id INTEGER Pipedrive company ID.
queue_type TEXT Task type identifier (e.g., gads_click_not_found).
payload TEXT JSON-serialized task data.
status TEXT pending, processing, completed, or failed. Default: pending.
retry_after TEXT Earliest processing time (datetime).
attempt_count INTEGER Number of attempts made. Default: 0.
max_attempts INTEGER Maximum retry attempts before marking as failed. Default: 5.
error_message TEXT Most recent error message (nullable).
created_at TEXT Row creation timestamp.
updated_at TEXT Last update timestamp.

Indexes: idx_retry_queue_pending on (status, retry_after), idx_retry_queue_company on company_id.