Every hour the API reminds whoever has a ticket, and whoever follows it, the day before its due date, on the day and once when it is overdue, in the app and by e-mail for those who asked. Cards on the board flag what is due soon or late. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import {
|
|
IssueReadModel,
|
|
NotificationKind,
|
|
} from '@task-stream/api/tracker/domain';
|
|
import { dueStage, nextDay, remindersFor } from './reminders';
|
|
|
|
const issue = (id: string, dueDate: string, watchers: string[] = []) =>
|
|
({
|
|
id,
|
|
key: `WEB-${id}`,
|
|
title: `T${id}`,
|
|
projectId: 'p',
|
|
projectKey: 'WEB',
|
|
dueDate,
|
|
assignee: { id: 'ana', name: 'Ana' },
|
|
watchers: watchers.map((w) => ({ id: w, name: w })),
|
|
}) as IssueReadModel;
|
|
|
|
describe('due reminders', () => {
|
|
it('tells the stage of a due date', () => {
|
|
expect(nextDay('2026-12-31')).toBe('2027-01-01');
|
|
expect(dueStage('2026-10-09', '2026-10-08')).toBe('tomorrow');
|
|
expect(dueStage('2026-10-08', '2026-10-08')).toBe('today');
|
|
expect(dueStage('2026-10-01', '2026-10-08')).toBe('overdue');
|
|
expect(dueStage('2026-10-20', '2026-10-08')).toBeNull();
|
|
});
|
|
|
|
it('reminds whoever has it and whoever follows it, once per stage', () => {
|
|
const reminders = remindersFor(
|
|
[issue('1', '2026-10-08', ['ana', 'bob']), issue('2', '2026-10-30')],
|
|
'2026-10-08',
|
|
'2026-10-08T07:00:00Z',
|
|
);
|
|
expect(reminders.map((r) => [r.userId, r.summary])).toEqual([
|
|
['ana', 'WEB-1 vence hoy: T1'],
|
|
['bob', 'WEB-1 vence hoy: T1'],
|
|
]);
|
|
expect(reminders[0]).toMatchObject({
|
|
kind: NotificationKind.REMINDER,
|
|
id: 'reminder:1:2026-10-08:today:ana',
|
|
});
|
|
});
|
|
});
|