feat: add DISC profiles and a sales copilot as an org module

Help reps capture a customer's likely behavior style and get negotiation guidance, with the feature gated from super admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-18 21:04:26 +03:30
co-authored by Cursor
parent 96befd3867
commit 002f697dfe
27 changed files with 2838 additions and 26 deletions
+106
View File
@@ -0,0 +1,106 @@
import { Type } from 'class-transformer';
import {
IsBoolean,
IsDateString,
IsIn,
IsObject,
IsOptional,
IsString,
MaxLength,
ValidateIf,
} from 'class-validator';
import {
COPILOT_GOALS,
COPILOT_TOPICS,
type CopilotGoal,
type CopilotTopic,
} from '@mento/shared';
export class SaveDiscDto {
@IsObject()
answers!: Record<string, string | null>;
@IsOptional()
@IsString()
@MaxLength(4000)
note?: string;
}
export class AnalyzeCopilotDto {
@IsOptional()
@IsString()
personId?: string;
@IsOptional()
@IsString()
leadId?: string;
@IsOptional()
@IsString()
dealId?: string;
@IsIn([...COPILOT_TOPICS])
topic!: CopilotTopic;
@IsIn([...COPILOT_GOALS])
goal!: CopilotGoal;
@IsString()
@MaxLength(4000)
customerStatement!: string;
@IsOptional()
@IsString()
@MaxLength(2000)
behaviorNotes?: string;
}
export class SaveCopilotDto extends AnalyzeCopilotDto {
@IsIn(['confirmed', 'dismissed'])
status!: 'confirmed' | 'dismissed';
@IsOptional()
@IsString()
@MaxLength(4000)
confirmedResponse?: string;
@IsOptional()
@IsString()
@MaxLength(500)
nextAction?: string;
@IsOptional()
@ValidateIf((_, value) => value != null && value !== '')
@IsDateString()
followUpAt?: string | null;
@IsOptional()
@IsString()
@MaxLength(500)
callOutcome?: string;
@IsOptional()
@IsString()
@MaxLength(4000)
agentNote?: string;
@IsOptional()
@IsString()
@MaxLength(2000)
messageDraft?: string;
}
export class CopilotFollowUpDto {
@IsOptional()
@IsDateString()
dueAt?: string;
@IsOptional()
@IsString()
assigneeId?: string;
@IsOptional()
@IsBoolean()
@Type(() => Boolean)
createTask?: boolean;
}