import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; import { CommentAddedEvent } from '@task-stream/api/tracker/domain'; import { FindCommentsRepository } from '../ports/find-comments.repository'; import { UpsertMaterializedCommentRepository } from '../ports/upsert-materialized-comment.repository'; import { UpsertMaterializedIssueRepository } from '../ports/upsert-materialized-issue.repository'; import { UserDirectory } from '../ports/user-directory'; import { ReadModelNotifier, versionOf } from './read-model-notifier'; @EventsHandler(CommentAddedEvent) export class CommentAddedEventHandler implements IEventHandler { constructor( private readonly upsertMaterializedCommentRepository: UpsertMaterializedCommentRepository, private readonly upsertMaterializedIssueRepository: UpsertMaterializedIssueRepository, private readonly findComments: FindCommentsRepository, private readonly users: UserDirectory, private readonly notifier: ReadModelNotifier, ) {} async handle(event: CommentAddedEvent) { const { comment } = event; const users = await this.users.refs([comment.authorId]); await this.upsertMaterializedCommentRepository.upsert({ id: comment.id, issueId: comment.issueId, projectId: comment.projectId, author: users.of(comment.authorId), body: comment.body, replyTo: comment.replyTo ?? null, deleted: false, reactions: [], decision: false, decidedBy: null, decidedAt: null, resolved: false, resolvedBy: null, resolvedAt: null, createdAt: comment.createdAt, editedAt: null, version: versionOf(event), }); // Recount instead of incrementing, so redelivery stays idempotent. await this.upsertMaterializedIssueRepository.setCommentCount( comment.issueId, await this.findComments.countByIssue(comment.issueId), ); await this.notifier.comment(comment.id, comment.issueId, event); await this.notifier.issue(comment.issueId, event); } }