refactor(bot): replace reminder polling with scheduled dispatches

This commit is contained in:
2026-03-24 20:51:54 +04:00
parent a1acec5e60
commit 7f836eeee2
48 changed files with 6425 additions and 1557 deletions

View File

@@ -1,11 +1,4 @@
export {
REMINDER_TYPES,
type ClaimReminderDispatchInput,
type ClaimReminderDispatchResult,
type ReminderDispatchRepository,
type ReminderTarget,
type ReminderType
} from './reminders'
export { REMINDER_TYPES, type ReminderTarget, type ReminderType } from './reminders'
export {
AD_HOC_NOTIFICATION_DELIVERY_MODES,
AD_HOC_NOTIFICATION_STATUSES,
@@ -20,6 +13,22 @@ export {
type CreateAdHocNotificationInput,
type UpdateAdHocNotificationInput
} from './notifications'
export {
SCHEDULED_DISPATCH_KINDS,
SCHEDULED_DISPATCH_PROVIDERS,
SCHEDULED_DISPATCH_STATUSES,
type ClaimScheduledDispatchDeliveryResult,
type CreateScheduledDispatchInput,
type ScheduleOneShotDispatchInput,
type ScheduleOneShotDispatchResult,
type ScheduledDispatchKind,
type ScheduledDispatchProvider,
type ScheduledDispatchRecord,
type ScheduledDispatchRepository,
type ScheduledDispatchScheduler,
type ScheduledDispatchStatus,
type UpdateScheduledDispatchInput
} from './scheduled-dispatches'
export type {
ClaimProcessedBotMessageInput,
ClaimProcessedBotMessageResult,

View File

@@ -16,24 +16,3 @@ export interface ReminderTarget {
utilitiesDueDay: number
utilitiesReminderDay: number
}
export interface ClaimReminderDispatchInput {
householdId: string
period: string
reminderType: ReminderType
payloadHash: string
}
export interface ClaimReminderDispatchResult {
dedupeKey: string
claimed: boolean
}
export interface ReminderDispatchRepository {
claimReminderDispatch(input: ClaimReminderDispatchInput): Promise<ClaimReminderDispatchResult>
releaseReminderDispatch(input: {
householdId: string
period: string
reminderType: ReminderType
}): Promise<void>
}

View File

@@ -0,0 +1,97 @@
import type { Instant } from '@household/domain'
export const SCHEDULED_DISPATCH_KINDS = [
'ad_hoc_notification',
'utilities',
'rent_warning',
'rent_due'
] as const
export const SCHEDULED_DISPATCH_STATUSES = ['scheduled', 'sent', 'cancelled'] as const
export const SCHEDULED_DISPATCH_PROVIDERS = ['gcp-cloud-tasks', 'aws-eventbridge'] as const
export type ScheduledDispatchKind = (typeof SCHEDULED_DISPATCH_KINDS)[number]
export type ScheduledDispatchStatus = (typeof SCHEDULED_DISPATCH_STATUSES)[number]
export type ScheduledDispatchProvider = (typeof SCHEDULED_DISPATCH_PROVIDERS)[number]
export interface ScheduledDispatchRecord {
id: string
householdId: string
kind: ScheduledDispatchKind
dueAt: Instant
timezone: string
status: ScheduledDispatchStatus
provider: ScheduledDispatchProvider
providerDispatchId: string | null
adHocNotificationId: string | null
period: string | null
sentAt: Instant | null
cancelledAt: Instant | null
createdAt: Instant
updatedAt: Instant
}
export interface CreateScheduledDispatchInput {
householdId: string
kind: ScheduledDispatchKind
dueAt: Instant
timezone: string
provider: ScheduledDispatchProvider
providerDispatchId?: string | null
adHocNotificationId?: string | null
period?: string | null
}
export interface UpdateScheduledDispatchInput {
dispatchId: string
dueAt?: Instant
timezone?: string
providerDispatchId?: string | null
period?: string | null
updatedAt: Instant
}
export interface ClaimScheduledDispatchDeliveryResult {
dispatchId: string
claimed: boolean
}
export interface ScheduledDispatchRepository {
createScheduledDispatch(input: CreateScheduledDispatchInput): Promise<ScheduledDispatchRecord>
getScheduledDispatchById(dispatchId: string): Promise<ScheduledDispatchRecord | null>
getScheduledDispatchByAdHocNotificationId(
notificationId: string
): Promise<ScheduledDispatchRecord | null>
listScheduledDispatchesForHousehold(
householdId: string
): Promise<readonly ScheduledDispatchRecord[]>
updateScheduledDispatch(
input: UpdateScheduledDispatchInput
): Promise<ScheduledDispatchRecord | null>
cancelScheduledDispatch(
dispatchId: string,
cancelledAt: Instant
): Promise<ScheduledDispatchRecord | null>
markScheduledDispatchSent(
dispatchId: string,
sentAt: Instant
): Promise<ScheduledDispatchRecord | null>
claimScheduledDispatchDelivery(dispatchId: string): Promise<ClaimScheduledDispatchDeliveryResult>
releaseScheduledDispatchDelivery(dispatchId: string): Promise<void>
}
export interface ScheduleOneShotDispatchInput {
dispatchId: string
dueAt: Instant
}
export interface ScheduleOneShotDispatchResult {
providerDispatchId: string
}
export interface ScheduledDispatchScheduler {
readonly provider: ScheduledDispatchProvider
scheduleOneShotDispatch(
input: ScheduleOneShotDispatchInput
): Promise<ScheduleOneShotDispatchResult>
cancelDispatch(providerDispatchId: string): Promise<void>
}