From 08b03219aedf63500075aed5b3fef3001fe15294 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Thu, 13 Nov 2025 22:47:26 +0100 Subject: [PATCH 1/7] feat: modified schema to support vote tracking --- .../migration.sql | 53 +++++++++++++++++++ prisma/schema.prisma | 37 +++++++++++-- 2 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql diff --git a/prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql b/prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql new file mode 100644 index 0000000..7da273d --- /dev/null +++ b/prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql @@ -0,0 +1,53 @@ +/* + Warnings: + + - You are about to drop the column `downVotes` on the `aiWorkflowRunItem` table. All the data in the column will be lost. + - You are about to drop the column `upVotes` on the `aiWorkflowRunItem` table. All the data in the column will be lost. + - You are about to drop the column `downVotes` on the `aiWorkflowRunItemComment` table. All the data in the column will be lost. + - You are about to drop the column `upVotes` on the `aiWorkflowRunItemComment` table. All the data in the column will be lost. + +*/ +-- CreateEnum +CREATE TYPE "VoteType" AS ENUM ('UPVOTE', 'DOWNVOTE'); + +-- AlterTable +ALTER TABLE "aiWorkflowRunItem" DROP COLUMN "downVotes", +DROP COLUMN "upVotes"; + +-- AlterTable +ALTER TABLE "aiWorkflowRunItemComment" DROP COLUMN "downVotes", +DROP COLUMN "upVotes"; + +-- CreateTable +CREATE TABLE "aiWorkflowRunItemVote" ( + "id" VARCHAR(14) NOT NULL DEFAULT nanoid(), + "workflowRunItemId" VARCHAR(14) NOT NULL, + "voteType" "VoteType" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdBy" TEXT, + + CONSTRAINT "aiWorkflowRunItemVote_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "aiWorkflowRunItemCommentVote" ( + "id" VARCHAR(14) NOT NULL DEFAULT nanoid(), + "workflowRunItemCommentId" VARCHAR(14) NOT NULL, + "voteType" "VoteType" NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdBy" TEXT, + + CONSTRAINT "aiWorkflowRunItemCommentVote_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId"); + +-- CreateIndex +CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId"); + +-- AddForeignKey +ALTER TABLE "aiWorkflowRunItemVote" ADD CONSTRAINT "aiWorkflowRunItemVote_workflowRunItemId_fkey" FOREIGN KEY ("workflowRunItemId") REFERENCES "aiWorkflowRunItem"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "aiWorkflowRunItemCommentVote" ADD CONSTRAINT "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_fkey" FOREIGN KEY ("workflowRunItemCommentId") REFERENCES "aiWorkflowRunItemComment"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index ed5c02e..033956e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -643,6 +643,35 @@ model llmModel { workflows aiWorkflow[] } +model aiWorkflowRunItemVote { + id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14) + workflowRunItemId String @db.VarChar(14) + voteType VoteType + createdAt DateTime @default(now()) @db.Timestamp(3) + createdBy String? @db.Text + + item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id], onDelete: Cascade) + + @@index([workflowRunItemId]) +} + +model aiWorkflowRunItemCommentVote { + id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14) + workflowRunItemCommentId String @db.VarChar(14) + voteType VoteType + createdAt DateTime @default(now()) @db.Timestamp(3) + createdBy String? @db.Text + + comment aiWorkflowRunItemComment @relation(fields: [workflowRunItemCommentId], references: [id], onDelete: Cascade) + + @@index([workflowRunItemCommentId]) +} + +enum VoteType { + UPVOTE + DOWNVOTE +} + model aiWorkflow { id String @id @default(dbgenerated("nanoid()")) @db.VarChar(14) name String @unique @db.VarChar @@ -690,8 +719,6 @@ model aiWorkflowRunItem { workflowRunId String @db.VarChar(14) scorecardQuestionId String @db.VarChar(14) content String @db.Text - upVotes Int @default(0) - downVotes Int @default(0) questionScore Float? @db.DoublePrecision createdAt DateTime @db.Timestamp(3) createdBy String? @db.Text @@ -699,6 +726,8 @@ model aiWorkflowRunItem { run aiWorkflowRun @relation(fields: [workflowRunId], references: [id]) question scorecardQuestion @relation(fields: [scorecardQuestionId], references: [id]) comments aiWorkflowRunItemComment[] + + votes aiWorkflowRunItemVote[] } model aiWorkflowRunItemComment { @@ -706,8 +735,6 @@ model aiWorkflowRunItemComment { workflowRunItemId String @db.VarChar(14) userId String @db.Text content String @db.Text - upVotes Int @default(0) - downVotes Int @default(0) parentId String? @db.VarChar(14) createdAt DateTime @default(now()) @db.Timestamp(3) createdBy String? @db.Text @@ -717,4 +744,6 @@ model aiWorkflowRunItemComment { item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id]) parent aiWorkflowRunItemComment? @relation("CommentHierarchy", fields: [parentId], references: [id]) replies aiWorkflowRunItemComment[] @relation("CommentHierarchy") + + votes aiWorkflowRunItemCommentVote[] } From 866b227ba6d895b0e73d6ffda3c0c947867b0c99 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Fri, 14 Nov 2025 21:30:02 +0100 Subject: [PATCH 2/7] fix: updated upVote and downVote logic --- src/api/ai-workflow/ai-workflow.service.ts | 94 ++++++++++++++++++---- src/dto/aiWorkflow.dto.ts | 15 ++-- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/src/api/ai-workflow/ai-workflow.service.ts b/src/api/ai-workflow/ai-workflow.service.ts index bb98f6f..aa2ddb7 100644 --- a/src/api/ai-workflow/ai-workflow.service.ts +++ b/src/api/ai-workflow/ai-workflow.service.ts @@ -27,6 +27,7 @@ import { UserRole } from 'src/shared/enums/userRole.enum'; import { ChallengeStatus } from 'src/shared/enums/challengeStatus.enum'; import { LoggerService } from 'src/shared/modules/global/logger.service'; import { GiteaService } from 'src/shared/modules/global/gitea.service'; +import { VoteType } from '@prisma/client'; @Injectable() export class AiWorkflowService { @@ -96,7 +97,49 @@ export class AiWorkflowService { ); } - const allowedFields = ['content', 'upVotes', 'downVotes']; + // Handle vote updates + if (patchData.upVote !== undefined || patchData.downVote !== undefined) { + if (!user.userId) { + throw new BadRequestException('User id is not available'); + } + + // Remove existing votes by this user for this comment + await this.prisma.aiWorkflowRunItemCommentVote.deleteMany({ + where: { + workflowRunItemCommentId: commentId, + createdBy: user.userId.toString(), + }, + }); + + // Add new vote if upVote or downVote is true + if (patchData.upVote) { + await this.prisma.aiWorkflowRunItemCommentVote.create({ + data: { + workflowRunItemCommentId: commentId, + voteType: VoteType.UPVOTE, + createdBy: user.userId.toString(), + }, + }); + } else if (patchData.downVote) { + await this.prisma.aiWorkflowRunItemCommentVote.create({ + data: { + workflowRunItemCommentId: commentId, + voteType: VoteType.DOWNVOTE, + createdBy: user.userId.toString(), + }, + }); + } + + delete patchData.downVote; + delete patchData.upVote; + } + + // No other fields to update apart from likes + if (Object.keys(patchData).length === 0) { + return; + } + + const allowedFields = ['content']; const updateData: any = {}; for (const key of allowedFields) { if (key in patchData) { @@ -388,8 +431,6 @@ export class AiWorkflowService { workflowRunId: runId, scorecardQuestionId: item.scorecardQuestionId, content: item.content, - upVotes: item.upVotes ?? 0, - downVotes: item.downVotes ?? 0, questionScore: item.questionScore ?? null, createdAt: new Date(), // TODO: Remove this once prisma middleware implementation is done @@ -819,15 +860,6 @@ export class AiWorkflowService { ); } - const updateData: any = {}; - - if (patchData.upVotes !== undefined) { - updateData.upVotes = patchData.upVotes; - } - if (patchData.downVotes !== undefined) { - updateData.downVotes = patchData.downVotes; - } - if (!user.isMachine) { const keys = Object.keys(patchData); const prohibitedKeys = ['content', 'questionScore']; @@ -838,12 +870,45 @@ export class AiWorkflowService { } } - // Update properties which can be updated only via m2m + if (patchData.upVote !== undefined || patchData.downVote !== undefined) { + // Remove existing votes by this user for this item + if (!user.userId) { + throw new BadRequestException('User id is not available'); + } + + await this.prisma.aiWorkflowRunItemVote.deleteMany({ + where: { + workflowRunItemId: itemId, + createdBy: user.userId.toString(), + }, + }); + + // Add new vote if upVote or downVote is true + if (patchData.upVote) { + await this.prisma.aiWorkflowRunItemVote.create({ + data: { + workflowRunItemId: itemId, + voteType: VoteType.UPVOTE, + createdBy: user.userId.toString(), + }, + }); + } else if (patchData.downVote) { + await this.prisma.aiWorkflowRunItemVote.create({ + data: { + workflowRunItemId: itemId, + voteType: VoteType.DOWNVOTE, + createdBy: user.userId.toString(), + }, + }); + } + } + + // Update other properties only allowed for machine users + const updateData: any = {}; if (user.isMachine) { if (patchData.content) { updateData.content = patchData.content; } - if (patchData.questionScore) { updateData.questionScore = patchData.questionScore; } @@ -853,6 +918,7 @@ export class AiWorkflowService { where: { id: itemId }, include: { comments: true, + votes: true, }, data: updateData, }); diff --git a/src/dto/aiWorkflow.dto.ts b/src/dto/aiWorkflow.dto.ts index 91e5a32..d56a55d 100644 --- a/src/dto/aiWorkflow.dto.ts +++ b/src/dto/aiWorkflow.dto.ts @@ -17,6 +17,7 @@ import { IsUUID, Max, IsEmpty, + IsBoolean, } from 'class-validator'; import { Type, Transform } from 'class-transformer'; @@ -134,15 +135,13 @@ export class CreateAiWorkflowRunItemDto { @ApiProperty({ required: false }) @IsOptional() - @IsInt() - @Min(0) - upVotes?: number; + @IsBoolean() + upVote?: boolean; @ApiProperty({ required: false }) @IsOptional() - @IsInt() - @Min(0) - downVotes?: number; + @IsBoolean() + downVote?: boolean; @ApiProperty({ required: false }) @IsOptional() @@ -204,12 +203,12 @@ export class UpdateRunItemCommentDto { @ApiProperty({ required: false }) @IsInt() @IsOptional() - upVotes?: number; + upVote?: number; @ApiProperty({ required: false }) @IsInt() @IsOptional() - downVotes?: number; + downVote?: number; @ApiHideProperty() @IsEmpty({ message: 'parentId cannot be updated' }) From 16418fc7c3ebb9341d20af4244c0444c17b68c78 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Fri, 14 Nov 2025 22:31:16 +0100 Subject: [PATCH 3/7] fix: updated upVote and downVote logic --- src/api/ai-workflow/ai-workflow.service.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/api/ai-workflow/ai-workflow.service.ts b/src/api/ai-workflow/ai-workflow.service.ts index aa2ddb7..8c943be 100644 --- a/src/api/ai-workflow/ai-workflow.service.ts +++ b/src/api/ai-workflow/ai-workflow.service.ts @@ -901,6 +901,9 @@ export class AiWorkflowService { }, }); } + + delete patchData.downVote; + delete patchData.upVote; } // Update other properties only allowed for machine users @@ -914,6 +917,18 @@ export class AiWorkflowService { } } + // If there are no other fields to update + // just return the run item + if (Object.keys(updateData).length === 0) { + return this.prisma.aiWorkflowRunItem.findUnique({ + where: { id: itemId }, + include: { + comments: true, + votes: true, + }, + }); + } + return this.prisma.aiWorkflowRunItem.update({ where: { id: itemId }, include: { From f24042d15e59507e25fe92460c72e1ac2002ef14 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Fri, 14 Nov 2025 22:34:44 +0100 Subject: [PATCH 4/7] fix: updated upVote and downVote logic --- src/dto/aiWorkflow.dto.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dto/aiWorkflow.dto.ts b/src/dto/aiWorkflow.dto.ts index d56a55d..f82b31b 100644 --- a/src/dto/aiWorkflow.dto.ts +++ b/src/dto/aiWorkflow.dto.ts @@ -201,14 +201,14 @@ export class UpdateRunItemCommentDto { content?: string; @ApiProperty({ required: false }) - @IsInt() + @IsBoolean() @IsOptional() - upVote?: number; + upVote?: boolean; @ApiProperty({ required: false }) - @IsInt() + @IsBoolean() @IsOptional() - downVote?: number; + downVote?: boolean; @ApiHideProperty() @IsEmpty({ message: 'parentId cannot be updated' }) From 2b5ecd52d43a7eec532b891c49e3cd7cf4934277 Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 17 Nov 2025 16:23:07 +0100 Subject: [PATCH 5/7] fix: review comments --- .../migration.sql | 8 ++++---- prisma/schema.prisma | 8 ++++---- src/api/ai-workflow/ai-workflow.service.ts | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) rename prisma/migrations/{20251113212614_add_vote_tracking_to_ai_workflow_run_items => 20251117152041_add_vote_tracking_to_ai_workflow_run_items}/migration.sql (87%) diff --git a/prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql b/prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql similarity index 87% rename from prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql rename to prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql index 7da273d..ad16b08 100644 --- a/prisma/migrations/20251113212614_add_vote_tracking_to_ai_workflow_run_items/migration.sql +++ b/prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql @@ -24,7 +24,7 @@ CREATE TABLE "aiWorkflowRunItemVote" ( "workflowRunItemId" VARCHAR(14) NOT NULL, "voteType" "VoteType" NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdBy" TEXT, + "createdBy" TEXT NOT NULL, CONSTRAINT "aiWorkflowRunItemVote_pkey" PRIMARY KEY ("id") ); @@ -35,16 +35,16 @@ CREATE TABLE "aiWorkflowRunItemCommentVote" ( "workflowRunItemCommentId" VARCHAR(14) NOT NULL, "voteType" "VoteType" NOT NULL, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "createdBy" TEXT, + "createdBy" TEXT NOT NULL, CONSTRAINT "aiWorkflowRunItemCommentVote_pkey" PRIMARY KEY ("id") ); -- CreateIndex -CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId"); +CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_createdBy_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId", "createdBy"); -- CreateIndex -CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId"); +CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_creat_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId", "createdBy"); -- AddForeignKey ALTER TABLE "aiWorkflowRunItemVote" ADD CONSTRAINT "aiWorkflowRunItemVote_workflowRunItemId_fkey" FOREIGN KEY ("workflowRunItemId") REFERENCES "aiWorkflowRunItem"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 033956e..ae3db2e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -648,11 +648,11 @@ model aiWorkflowRunItemVote { workflowRunItemId String @db.VarChar(14) voteType VoteType createdAt DateTime @default(now()) @db.Timestamp(3) - createdBy String? @db.Text + createdBy String @db.Text item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id], onDelete: Cascade) - @@index([workflowRunItemId]) + @@index([workflowRunItemId, createdBy]) } model aiWorkflowRunItemCommentVote { @@ -660,11 +660,11 @@ model aiWorkflowRunItemCommentVote { workflowRunItemCommentId String @db.VarChar(14) voteType VoteType createdAt DateTime @default(now()) @db.Timestamp(3) - createdBy String? @db.Text + createdBy String @db.Text comment aiWorkflowRunItemComment @relation(fields: [workflowRunItemCommentId], references: [id], onDelete: Cascade) - @@index([workflowRunItemCommentId]) + @@index([workflowRunItemCommentId, createdBy]) } enum VoteType { diff --git a/src/api/ai-workflow/ai-workflow.service.ts b/src/api/ai-workflow/ai-workflow.service.ts index 8c943be..41abe6d 100644 --- a/src/api/ai-workflow/ai-workflow.service.ts +++ b/src/api/ai-workflow/ai-workflow.service.ts @@ -812,6 +812,7 @@ export class AiWorkflowService { where: { workflowRunId: runId }, include: { comments: true, + votes: true, }, orderBy: { createdAt: 'asc', From fbe4a61c9d06d0ae5538459da00499bc62246f4a Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 17 Nov 2025 16:26:32 +0100 Subject: [PATCH 6/7] fix: review comments --- .../migration.sql | 10 ++++++++-- prisma/schema.prisma | 6 ++++-- 2 files changed, 12 insertions(+), 4 deletions(-) rename prisma/migrations/{20251117152041_add_vote_tracking_to_ai_workflow_run_items => 20251117152627_add_vote_tracking_to_ai_workflow_run_items}/migration.sql (80%) diff --git a/prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql b/prisma/migrations/20251117152627_add_vote_tracking_to_ai_workflow_run_items/migration.sql similarity index 80% rename from prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql rename to prisma/migrations/20251117152627_add_vote_tracking_to_ai_workflow_run_items/migration.sql index ad16b08..4f3a7fa 100644 --- a/prisma/migrations/20251117152041_add_vote_tracking_to_ai_workflow_run_items/migration.sql +++ b/prisma/migrations/20251117152627_add_vote_tracking_to_ai_workflow_run_items/migration.sql @@ -41,10 +41,16 @@ CREATE TABLE "aiWorkflowRunItemCommentVote" ( ); -- CreateIndex -CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_createdBy_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId", "createdBy"); +CREATE INDEX "aiWorkflowRunItemVote_workflowRunItemId_idx" ON "aiWorkflowRunItemVote"("workflowRunItemId"); -- CreateIndex -CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_creat_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId", "createdBy"); +CREATE UNIQUE INDEX "aiWorkflowRunItemVote_workflowRunItemId_createdBy_key" ON "aiWorkflowRunItemVote"("workflowRunItemId", "createdBy"); + +-- CreateIndex +CREATE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_idx" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId"); + +-- CreateIndex +CREATE UNIQUE INDEX "aiWorkflowRunItemCommentVote_workflowRunItemCommentId_creat_key" ON "aiWorkflowRunItemCommentVote"("workflowRunItemCommentId", "createdBy"); -- AddForeignKey ALTER TABLE "aiWorkflowRunItemVote" ADD CONSTRAINT "aiWorkflowRunItemVote_workflowRunItemId_fkey" FOREIGN KEY ("workflowRunItemId") REFERENCES "aiWorkflowRunItem"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index ae3db2e..8111846 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -652,7 +652,8 @@ model aiWorkflowRunItemVote { item aiWorkflowRunItem @relation(fields: [workflowRunItemId], references: [id], onDelete: Cascade) - @@index([workflowRunItemId, createdBy]) + @@index([workflowRunItemId]) + @@unique([workflowRunItemId, createdBy]) } model aiWorkflowRunItemCommentVote { @@ -664,7 +665,8 @@ model aiWorkflowRunItemCommentVote { comment aiWorkflowRunItemComment @relation(fields: [workflowRunItemCommentId], references: [id], onDelete: Cascade) - @@index([workflowRunItemCommentId, createdBy]) + @@index([workflowRunItemCommentId]) + @@unique([workflowRunItemCommentId, createdBy]) } enum VoteType { From efc93716acad3786c0994124641fec22db47a04c Mon Sep 17 00:00:00 2001 From: Hentry Martin Date: Mon, 17 Nov 2025 16:30:11 +0100 Subject: [PATCH 7/7] fix: review comments --- src/api/ai-workflow/ai-workflow.service.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/ai-workflow/ai-workflow.service.ts b/src/api/ai-workflow/ai-workflow.service.ts index 41abe6d..e05748a 100644 --- a/src/api/ai-workflow/ai-workflow.service.ts +++ b/src/api/ai-workflow/ai-workflow.service.ts @@ -811,7 +811,11 @@ export class AiWorkflowService { const items = await this.prisma.aiWorkflowRunItem.findMany({ where: { workflowRunId: runId }, include: { - comments: true, + comments: { + include: { + votes: true, + } + }, votes: true, }, orderBy: {