Files
task-stream/libs/api/tracker/domain/src/lib/read-models/issue.read-model.ts
Josep Piguillem 93d028e870 feat: ask a teammate to review a ticket
«Pedir revisión» on a ticket asks a member (with an optional note): they
are notified and see it under «Te piden revisión» in my work until they
answer «Todo bien» or «Pedir cambios» (with what to change) from the
ticket's Revisiones box; whoever asked hears the answer and can withdraw
an open request. Events of the ticket (requested, answered, cancelled),
so they show in its history and the activity feed. Viewers can be asked
and answer; not oneself, nor twice the same person with one pending.

API: requestReview / answerReview / cancelReview, Issue.reviews,
myIssues(reviewing); POST /api/issues/{issue}/reviews,
POST …/reviews/{id}/answer, DELETE …/reviews/{id}. MCP: request_review,
answer_review, my_issues reviewing.

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

122 lines
3.5 KiB
TypeScript

import { ReviewVerdict } from '../issue/review';
import { DevLink } from '../issue/dev-link';
import { IssueLinkType, IssuePriority } from '../issue/issue.enums';
import { StatusCategory } from '../project/project-settings';
import { UserRefReadModel } from './user-ref.read-model';
export type LinkDirection = 'OUTWARD' | 'INWARD';
export class IssueLinkReadModel {
type!: IssueLinkType;
/** OUTWARD: this issue → other (e.g. "blocks"). INWARD: other → this ("is blocked by"). */
direction!: LinkDirection;
issueId!: string;
issueKey!: string;
}
export class AttachmentReadModel {
id!: string;
fileName!: string;
mimeType!: string;
size!: number;
uploadedBy!: UserRefReadModel;
uploadedAt!: string;
/** Shown under this comment when set. */
commentId!: string | null;
}
export class ChecklistItemReadModel {
id!: string;
text!: string;
done!: boolean;
}
/** The ticket another one hangs from. */
export class IssueParentReadModel {
id!: string;
key!: string;
title!: string;
}
/** How far the tickets hanging from one have got. */
export class ChildProgressReadModel {
total!: number;
/** Done or cancelled. */
finished!: number;
percent!: number;
storyPoints!: number;
finishedStoryPoints!: number;
}
/** A top-level ticket that groups others, with their progress. */
export class EpicReadModel {
issue!: IssueReadModel;
progress!: ChildProgressReadModel;
}
export class IssueReadModel {
id!: string;
projectId!: string;
projectKey!: string;
number!: number;
key!: string;
/** Ids from the project's settings. */
type!: string;
area!: string | null;
/** A team id of the project's settings. */
team!: string | null;
title!: string;
description!: string | null;
status!: string;
/** Category of `status` (kept in sync when the project's settings change). */
statusCategory!: StatusCategory;
priority!: IssuePriority;
reporter!: UserRefReadModel;
assignee!: UserRefReadModel | null;
release!: { id: string; name: string } | null;
sprint!: { id: string; name: string } | null;
labels!: string[];
figmaUrl!: string | null;
storyPoints!: number | null;
startDate!: string | null;
dueDate!: string | null;
/** The project's custom fields: field id → value (only those with one). */
customFields!: Record<string, string>;
links!: IssueLinkReadModel[];
attachments!: AttachmentReadModel[];
/** People following the ticket. */
watchers!: UserRefReadModel[];
/** Asked reviews, open and answered, oldest first. */
reviews!: IssueReviewReadModel[];
/** How many want it done. */
votes!: number;
/** Who voted: to tell someone whether they did; never shown as a list. */
voterIds!: string[];
parent!: IssueParentReadModel | null;
/** Place in the backlog (and in each board column): ascending. */
rank!: string;
checklist!: ChecklistItemReadModel[];
/** Commits, branches and pull requests that mention it. */
devLinks!: DevLink[];
/** In the trash since then (null: not in it). */
trashedAt!: string | null;
commentCount!: number;
createdAt!: string;
updatedAt!: string;
/** Position of the last projected event. */
version!: number;
}
/** A review asked on a ticket, as the read side shows it. */
export class IssueReviewReadModel {
id!: string;
requester!: UserRefReadModel;
reviewer!: UserRefReadModel;
note!: string | null;
requestedAt!: string;
/** Null while waiting for an answer. */
verdict!: ReviewVerdict | null;
answer!: string | null;
answeredAt!: string | null;
}