feat: group activities into boards with their own stages, like sales pipelines

Existing stages and activities move into a default board per environment; new activities pick a board in the form.
This commit is contained in:
2026-10-20 17:23:27 +03:30
parent 9127fa334b
commit e6aa4c64f0
11 changed files with 769 additions and 58 deletions
+42
View File
@@ -79,6 +79,11 @@ export class ListActivitiesQueryDto {
@IsString()
stageId?: string;
/** گروه فعالیت؛ خالی = همهٔ گروه‌ها (در شمارش ستون‌ها = گروه پیش‌فرض) */
@IsOptional()
@IsString()
boardId?: string;
@IsOptional()
@IsString()
personId?: string;
@@ -121,7 +126,33 @@ export class ListActivitiesQueryDto {
const STAGE_COLORS = ['green', 'orange', 'purple', 'blue', 'rose', 'slate'] as const;
export class CreateActivityBoardDto {
@IsString()
@MinLength(2)
@MaxLength(80)
name!: string;
}
export class UpdateActivityBoardDto {
@IsOptional()
@IsString()
@MinLength(2)
@MaxLength(80)
name?: string;
}
export class ListActivityStagesQueryDto {
@IsOptional()
@IsString()
boardId?: string;
}
export class CreateActivityStageDto {
/** خالی = گروه پیش‌فرض */
@IsOptional()
@IsString()
boardId?: string;
@IsString()
@MinLength(1)
@MaxLength(80)
@@ -229,6 +260,11 @@ export class CreateActivityDto {
@MaxLength(200)
title!: string;
@IsOptional()
@ValidateIf((_, v) => v !== '' && v != null)
@IsString()
boardId?: string | null;
@IsOptional()
@ValidateIf((_, v) => v !== '' && v != null)
@IsString()
@@ -319,6 +355,12 @@ export class UpdateActivityDto {
@MaxLength(200)
title?: string;
/** null/خالی = گروه پیش‌فرض */
@IsOptional()
@ValidateIf((_, v) => v !== '' && v != null)
@IsString()
boardId?: string | null;
@IsOptional()
@IsIn(ACTIVITY_TYPES)
type?: (typeof ACTIVITY_TYPES)[number];