conversation-columns.ts5.4 KBView on GitHub
/**
 * Default CRM Conversation column configuration.
 *
 * ── FE ↔ BE field parity ─────────────────────────────────────────────────────────────────────
 * The backend has a canonical field registry at
 * `apps/server/src/services/crm/conversation-fields.ts` that is the source of truth for what
 * each conversation field can do (filter / sort / return) and derives the flexible_query filter
 * enum, sort map, and returnable-`extraFields` map from one place. There is no shared FE/BE
 * package, so this file MIRRORS it — the column `id`s here are the frontend/column_filters
 * aliases, recorded on the backend side as each field's `frontendId`.
 *
 * A few ids intentionally differ from the backend canonical key (kept because stored canvases
 * reference these ids); keep both sides in sync when adding/removing a column:
 *   FE column id            → backend canonical key
 *   'lastMeetingTime'       → 'lastMeetingAt'
 *   'lastOutboundEmailTime' → 'lastOutboundEmailAt'
 *   'lastInboundEmailTime'  → 'lastInboundAt'
 *   'primaryUser'           → 'ownerId'
 *   'type'                  → 'aopName'
 *   'primaryCompany'        → 'primaryCompanyName' / 'name'
 * The backend parity test (`conversation-fields.parity.test.ts`) mirrors the id list below and
 * fails if a column here lacks a backend `frontendId` mapping — update both together.
 */

import { DEFAULT_CRM_SYNCED_OPTIONS, DEFAULT_HISTORY_OPTIONS } from '../field-enums';
import type { CRMColumnMetadata } from '../store/crmSlice';

/**
 * Default columns shown in agent canvas mode.
 * These provide the most relevant context for agent-driven batch operations.
 * The agent can override these by specifying visibleColumns in findCRMConversationsTool.
 */
export const AGENT_CANVAS_DEFAULT_COLUMNS = ['primaryCompany', 'status', 'currentAction'] as const;

export const conversationColumnsConfig: CRMColumnMetadata[] = [
  {
    id: 'primaryCompany',
    name: 'Company',
    type: 'company-combined',
    description: 'Primary company and conversation name',
    isFixed: true,
  },
  {
    id: 'nextStepDate',
    name: 'Next Step Date',
    type: 'date',
    description: 'Planned next action date',
  },
  {
    id: 'nextSteps',
    name: 'Next Steps',
    type: 'text',
    description: 'Planned next actions',
  },
  {
    // Sits immediately after Next Steps by design: "is a meeting already booked?" is the
    // first thing you ask about a next step, so the two read as one unit. This array's
    // order is the fallback column order for any canvas that doesn't pin an explicit
    // `order` in its columnConfiguration (see use-canvas-configuration.ts).
    id: 'hasFutureCalendar',
    name: 'Upcoming Meeting',
    type: 'date',
    description: 'Date of next upcoming calendar event',
    enumOptions: [
      { value: 'true', label: 'Has meeting', color: 'blue', enumOrder: 0 },
      { value: 'false', label: 'No meeting', color: 'gray', enumOrder: 1 },
    ],
  },
  {
    id: 'dealValue',
    name: 'Deal Size',
    type: 'number',
    description: 'Monetary value of the deal',
  },
  {
    id: 'status',
    name: 'Stage',
    type: 'status-badge',
    description: 'Current deal stage',
    enumOptions: [], // Will be populated from AOP or show all unique values
  },
  {
    id: 'statusOverview',
    name: 'Status Overview',
    type: 'text',
    description: 'Status overview text',
  },
  {
    id: 'lastContactedAt',
    name: 'Last Contact',
    type: 'date',
    description: 'Date of last contact',
  },
  {
    id: 'priority',
    name: 'Priority',
    type: 'select',
    description: 'Priority level',
    enumOptions: [], // Will be populated from AOP or show all unique values
  },
  {
    id: 'risk',
    name: 'Risk',
    type: 'select',
    description: 'Risk level',
    enumOptions: [], // Will be populated from AOP or show all unique values
  },
  {
    id: 'type',
    name: 'Type',
    type: 'aop-type',
    description: 'Type of conversation (derived from AOP)',
  },
  {
    id: 'history',
    name: 'Recent Activity',
    type: 'timeline',
    description: 'Recent events and interactions',
    enumOptions: DEFAULT_HISTORY_OPTIONS,
  },
  {
    id: 'activityOverview',
    name: 'Activity Timeline',
    type: 'activity-overview',
    description: 'Visual timeline of activity over time',
  },
  {
    id: 'workingMemory',
    name: 'Custom Fields',
    type: 'working-memory',
    description: 'Agent custom fields',
  },
  {
    id: 'crmSynced',
    name: 'CRM Synced',
    type: 'crm-synced',
    description: 'Whether synced to an external CRM',
    enumOptions: DEFAULT_CRM_SYNCED_OPTIONS,
  },
  {
    id: 'currentAction',
    name: 'Suggested Action',
    type: 'current-action',
    description: 'Most overdue task or last activity if no tasks',
  },
  {
    id: 'lastMeetingTime',
    name: 'Last Meeting',
    type: 'date',
    description: 'Date of last meeting',
  },
  {
    id: 'lastOutboundEmailTime',
    name: 'Last Email Sent',
    type: 'date',
    description: 'Date of last outbound email sent',
  },
  {
    id: 'lastInboundEmailTime',
    name: 'Last Email Received',
    type: 'date',
    description: 'Date of last inbound email received from prospect',
  },
  {
    id: 'primaryUser',
    name: 'Owner',
    type: 'user',
    description: 'The team member who owns this conversation',
  },
];