Files
task-stream/libs/api/tracker/domain/src/lib/read-models/comment.read-model.ts
Josep Piguillem 3a46a236e4 feat: quick polls in comments that end in a decision
«📊 Añadir una encuesta» adds 2 to 6 options to a new comment. Members,
viewers too, vote by clicking an option (one vote each, which they can
change or take back) and see each option's votes as a bar. Whoever
started it, or an admin, closes it with «Cerrar y decidir»: the most
voted wins (none on a tie) and a «Decidido: …» reply marked as a
decision shows above the ticket. Events of the comment (voted, closed).

API: addComment(…, poll), votePoll, closePoll, Comment.poll;
POST /api/comments/{id}/poll/vote and …/poll/close. MCP: add_comment
poll, vote_poll, close_poll.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:48:12 +02:00

54 lines
1.7 KiB
TypeScript

import { UserRefReadModel } from './user-ref.read-model';
/** One emoji on a comment and who chose it. */
export class CommentReactionReadModel {
emoji!: string;
users!: UserRefReadModel[];
}
/** A quick poll: each option with who voted it. */
export class CommentPollReadModel {
options!: { text: string; voters: UserRefReadModel[] }[];
closed!: boolean;
/** Index of the winning option once closed (null on a tie). */
winner!: number | null;
}
export class CommentReadModel {
id!: string;
issueId!: string;
projectId!: string;
author!: UserRefReadModel;
body!: string;
/** Top-level comment it answers; null for a top-level one. */
replyTo!: string | null;
/**
* Deleted while it had replies: kept, without its text, so the
* conversation under it still makes sense. Gone with its last reply.
*/
deleted!: boolean;
/** In the order they are offered; only the ones somebody chose. */
reactions!: CommentReactionReadModel[];
/** Marked as a decision of the ticket. */
decision!: boolean;
/** Who marked it and when (null when it is not a decision). */
decidedBy!: UserRefReadModel | null;
decidedAt!: string | null;
/** A quick poll in the comment, if any. */
poll!: CommentPollReadModel | null;
/** A top-level comment whose conversation was settled. */
resolved!: boolean;
/** Who settled it and when (null while open). */
resolvedBy!: UserRefReadModel | null;
resolvedAt!: string | null;
createdAt!: string;
editedAt!: string | null;
version!: number;
}
/** A decision with the ticket it belongs to, for searching across tickets. */
export class DecisionReadModel {
comment!: CommentReadModel;
issue!: { id: string; key: string; title: string };
}