- Create brain module with service, controller, and DTOs - POST /api/brain/query - Structured queries for tasks, events, projects - GET /api/brain/context - Get current workspace context for agents - GET /api/brain/search - Search across all entities - Support filters: status, priority, date ranges, assignee, etc. - 41 tests covering service (27) and controller (14) - Integrated with AuthGuard, WorkspaceGuard, PermissionGuard
165 lines
3.6 KiB
TypeScript
165 lines
3.6 KiB
TypeScript
import { TaskStatus, TaskPriority, ProjectStatus, EntityType } from "@prisma/client";
|
|
import {
|
|
IsUUID,
|
|
IsEnum,
|
|
IsOptional,
|
|
IsString,
|
|
IsInt,
|
|
Min,
|
|
Max,
|
|
IsDateString,
|
|
IsArray,
|
|
ValidateNested,
|
|
IsBoolean,
|
|
} from "class-validator";
|
|
import { Type } from "class-transformer";
|
|
|
|
export class TaskFilter {
|
|
@IsOptional()
|
|
@IsEnum(TaskStatus, { message: "status must be a valid TaskStatus" })
|
|
status?: TaskStatus;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@IsEnum(TaskStatus, { each: true, message: "statuses must be valid TaskStatus values" })
|
|
statuses?: TaskStatus[];
|
|
|
|
@IsOptional()
|
|
@IsEnum(TaskPriority, { message: "priority must be a valid TaskPriority" })
|
|
priority?: TaskPriority;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@IsEnum(TaskPriority, { each: true, message: "priorities must be valid TaskPriority values" })
|
|
priorities?: TaskPriority[];
|
|
|
|
@IsOptional()
|
|
@IsUUID("4", { message: "assigneeId must be a valid UUID" })
|
|
assigneeId?: string;
|
|
|
|
@IsOptional()
|
|
@IsUUID("4", { message: "projectId must be a valid UUID" })
|
|
projectId?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "dueDateFrom must be a valid ISO 8601 date string" })
|
|
dueDateFrom?: Date;
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "dueDateTo must be a valid ISO 8601 date string" })
|
|
dueDateTo?: Date;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
overdue?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
unassigned?: boolean;
|
|
}
|
|
|
|
export class EventFilter {
|
|
@IsOptional()
|
|
@IsUUID("4", { message: "projectId must be a valid UUID" })
|
|
projectId?: string;
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "startFrom must be a valid ISO 8601 date string" })
|
|
startFrom?: Date;
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "startTo must be a valid ISO 8601 date string" })
|
|
startTo?: Date;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
allDay?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
upcoming?: boolean;
|
|
}
|
|
|
|
export class ProjectFilter {
|
|
@IsOptional()
|
|
@IsEnum(ProjectStatus, { message: "status must be a valid ProjectStatus" })
|
|
status?: ProjectStatus;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@IsEnum(ProjectStatus, { each: true, message: "statuses must be valid ProjectStatus values" })
|
|
statuses?: ProjectStatus[];
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "startDateFrom must be a valid ISO 8601 date string" })
|
|
startDateFrom?: Date;
|
|
|
|
@IsOptional()
|
|
@IsDateString({}, { message: "startDateTo must be a valid ISO 8601 date string" })
|
|
startDateTo?: Date;
|
|
}
|
|
|
|
export class BrainQueryDto {
|
|
@IsUUID("4", { message: "workspaceId must be a valid UUID" })
|
|
workspaceId!: string;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
query?: string;
|
|
|
|
@IsOptional()
|
|
@IsArray()
|
|
@IsEnum(EntityType, { each: true, message: "entities must be valid EntityType values" })
|
|
entities?: EntityType[];
|
|
|
|
@IsOptional()
|
|
@ValidateNested()
|
|
@Type(() => TaskFilter)
|
|
tasks?: TaskFilter;
|
|
|
|
@IsOptional()
|
|
@ValidateNested()
|
|
@Type(() => EventFilter)
|
|
events?: EventFilter;
|
|
|
|
@IsOptional()
|
|
@ValidateNested()
|
|
@Type(() => ProjectFilter)
|
|
projects?: ProjectFilter;
|
|
|
|
@IsOptional()
|
|
@IsString()
|
|
search?: string;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt({ message: "limit must be an integer" })
|
|
@Min(1, { message: "limit must be at least 1" })
|
|
@Max(100, { message: "limit must not exceed 100" })
|
|
limit?: number;
|
|
}
|
|
|
|
export class BrainContextDto {
|
|
@IsUUID("4", { message: "workspaceId must be a valid UUID" })
|
|
workspaceId!: string;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
includeEvents?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
includeTasks?: boolean;
|
|
|
|
@IsOptional()
|
|
@IsBoolean()
|
|
includeProjects?: boolean;
|
|
|
|
@IsOptional()
|
|
@Type(() => Number)
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(30)
|
|
eventDays?: number;
|
|
}
|