Guides

Data operations

Import, export, data cleanup, and merge operations in OpsDash.

Data import

Contact CSV import

Location: CRM → Contacts → Import

Required columns: name, email

Optional columns: phone, company, lead_source, industry, company_size, timezone, tags (comma-separated), status

Behavior:

  • Existing contacts (matched by email, case-insensitive) are updated (upsert)
  • New contacts are created
  • Each row is checked against the crm:contacts usage limit
  • Import result shows: created, updated, skipped counts with per-row errors

Deal CSV import

Location: CRM → Deals → Import Deals

Required columns: title, value, stage

Stage values: lead, qualified, proposal, negotiation, won, lost

Optional: email (links to existing contact), probability (0–100), notes, expected_close_date

Behavior: Insert-only (no upsert). If email matches an existing contact, the deal is linked to that contact.

Data export

Workspace data export (Growth)

Location: Sidebar Operations → Tools → Data Export (route /crm/export)

Downloads one JSON file (full rows per table) or one multi-section CSV (companies, contacts, leads, deals, projects, tasks). Used for backup, migration, or handoff. Gated by crm:export (minPlate: sales) plus the org flag workspace_data_export; owner/admin only. Server action: getExportData(orgSlug) in actions/export.ts.

GDPR export (all plates)

Location: Workspace Admin → Data & Privacy → Download My Data

Exports all data associated with the requesting user's account as a JSON archive. Required by GDPR Article 20 (data portability). Available to every user for their own data (crm:gdpr-export, minPlate: free). Server action: getGdprExportData() in actions/export.ts.

Data Health

Location: CRM → Data Health (gated by crm:data-cleanup, minPlate: sales). Reframed from “Data Quality” into an always-useful health view; internal routes stay under /crm/data-cleanup.

Data Health score

A 0–100 score rolls up the health checks plus duplicate detection into one number (healthy ≥ 85, fair ≥ 60, otherwise needs work). The checks surface issues such as:

  • Contacts missing email or name
  • Won deals missing a win reason / lost deals missing a loss reason
  • Duplicate contacts and duplicate deals

Server action: runDataHealthChecks(orgSlug) in actions/data-quality-checks.ts

Duplicate detection

Finds potential duplicate contacts, deals, and companies:

  • Contacts grouped by the same email address (case-insensitive)
  • Deals grouped by the same contact + title combination
  • Results are presented as groups with a “Merge keeping first” action

Merge

Select the primary record (the one to keep) and the duplicate (the one to remove). The merge operation:

  1. Re-links all related records (deals, activities, tasks) from the duplicate to the primary
  2. Merges non-conflicting field values into the primary
  3. Soft-deletes the duplicate (deleted_at is set)
  4. Writes a contact.merged audit log entry

Server actions: mergeContacts, mergeDeals, mergeCompanies in actions/data-quality-merge.ts. Bulk-fix (e.g. filling missing deal reasons) runs through bulkSetDealReason.

Soft delete behavior

Contacts, deals, leads, tasks, and support tickets are soft-deleted — a deleted_at timestamp is set rather than removing the row. This preserves audit history and prevents orphaned references. All list queries include deleted_at IS NULL filters automatically via RLS or query conditions.

Hard delete is not exposed in the UI. For GDPR deletion requests, use the account deletion flow which purges all user data via the service role client.

Data operations — OpsDash Docs | OpsDash