Files
task-stream/libs/api/tracker/application/src/lib/event-handlers/issue-created.event-handler.ts
Josep Piguillem 45a3dc1e16 feat: a roadmap of epics over time
Tickets get a start date next to their due date, both editable on the
ticket page. The Hoja de ruta tab lays the epics out over the months as
bars filled with their progress, with sprints and releases as landmarks
and a line for today.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:14:32 +02:00

67 lines
2.4 KiB
TypeScript

import { EventsHandler, IEventHandler } from '@nestjs/cqrs';
import {
DEFAULT_PROJECT_SETTINGS,
IssueCreatedEvent,
implicitRank,
ProjectWorkflow,
} from '@task-stream/api/tracker/domain';
import { FindProjectsRepository } from '../ports/find-projects.repository';
import { FindReleasesRepository } from '../ports/find-releases.repository';
import { UpsertMaterializedIssueRepository } from '../ports/upsert-materialized-issue.repository';
import { UserDirectory } from '../ports/user-directory';
import { ReadModelNotifier, versionOf } from './read-model-notifier';
@EventsHandler(IssueCreatedEvent)
export class IssueCreatedEventHandler
implements IEventHandler<IssueCreatedEvent>
{
constructor(
private readonly upsertMaterializedIssueRepository: UpsertMaterializedIssueRepository,
private readonly findReleases: FindReleasesRepository,
private readonly findProjects: FindProjectsRepository,
private readonly users: UserDirectory,
private readonly notifier: ReadModelNotifier,
) {}
async handle(event: IssueCreatedEvent) {
const { issue } = event;
const users = await this.users.refs([issue.reporterId, issue.assigneeId]);
const project = await this.findProjects.findById(issue.projectId);
const workflow = new ProjectWorkflow(
project?.settings ?? DEFAULT_PROJECT_SETTINGS,
);
const release = issue.releaseId
? await this.findReleases.findById(issue.releaseId)
: null;
await this.upsertMaterializedIssueRepository.upsert({
id: issue.id,
projectId: issue.projectId,
projectKey: issue.key.slice(0, issue.key.lastIndexOf('-')),
number: issue.number,
key: issue.key,
type: issue.type,
area: issue.area,
title: issue.title,
description: issue.description,
status: issue.status,
statusCategory: workflow.categoryOf(issue.status),
priority: issue.priority,
reporter: users.of(issue.reporterId),
assignee: users.ofNullable(issue.assigneeId),
release: release ? { id: release.id, name: release.name } : null,
parent: null,
sprint: null,
rank: implicitRank(issue.number),
labels: issue.labels,
figmaUrl: issue.figmaUrl,
storyPoints: issue.storyPoints,
startDate: issue.startDate ?? null,
dueDate: issue.dueDate,
createdAt: issue.createdAt,
updatedAt: issue.updatedAt,
version: versionOf(event),
});
await this.notifier.issue(issue.id, event);
}
}