Concepts

Entities & mapping

How Clivly maps your existing tables onto CRM concepts, and keeps that mapping current.

Discover and map your entities

Two different things flow to Clivly. Discovery sends table and column names so you can build a mapping; sync sends rows.

Package manager
terminal
# Push everything your config declares, without deploying:
#   1. table + column NAMES  (never row data — discovery is names only)
#   2. custom object types you declared with objectType
#   3. the mappings that make those objects actually receive rows
npx clivly push-schema
  • discoverFromDrizzle(schema) reports every table in your schema, not just the ones wired as sources — that is what makes the dashboard mapping step possible.
  • Open Integrations → Data model to map tables and columns onto CRM concepts.
  • Clivly applies the field map on its side, so re-mapping never needs a redeploy. entities[].fields values are real column names (full_name), which is what discovery reports and what fromDrizzle keys rows by.
  • Upgrading from 0.7.3 or earlier? Those versions keyed rows by Drizzle property names, so on a snake_case schema those fields mirrored as empty. If you worked around it by mapping to the Drizzle key, revert to the column name on upgrade.

The entity config shape

An entity is keyed by CRM conceptcontact, company, deal, or custom — and points at a host table by name:

clivly.config.ts
const entities = defineClivlyConfig({
entities: {
  participants: {
    concept: "contact",
    source: "participants",
    fields: { name: "full_name", email: "email" },
  },
  accounts: {
    concept: "company",
    source: "accounts",
    fields: { name: "legal_name", domain: "website" },
  },
},
});

source on the SDK config (the object passed to createClivlySDK) is keyed by CRM conceptcontacts / companies / deals / custom. The entity's own source: field above is a host table name. Conflating the two means an entity resolves to no source and silently syncs nothing.