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:contactsusage 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:
- Re-links all related records (deals, activities, tasks) from the duplicate to the primary
- Merges non-conflicting field values into the primary
- Soft-deletes the duplicate (
deleted_atis set) - Writes a
contact.mergedaudit 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.