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

@@ -25,6 +25,7 @@
"0020_silver_payments.sql": "9686235c75453f1eaa016f2f4ab7fce8fe964c76a4e3515987a2b9f90bd7b1ad",
"0021_sharp_payer.sql": "973596e154382984ba7769979ea58298b6d93c5139540854be01e8b283ddb4f1",
"0022_carry_purchase_history.sql": "f031c9736e43e71eec3263a323332c29de9324c6409db034b0760051c8a9f074",
"0023_huge_vision.sql": "9a682e8b62fc6c54711ccd7bb912dd7192e278f546d5853670bea6a0a4585c1c"
"0023_huge_vision.sql": "9a682e8b62fc6c54711ccd7bb912dd7192e278f546d5853670bea6a0a4585c1c",
"0024_lush_lucky_pierre.sql": "35d111486df774fde5add5cc98f2bf8bcb16d5bae8c4dd4df01fedb661a297d6"
}
}

View File

@@ -0,0 +1,22 @@
CREATE TABLE "scheduled_dispatches" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"household_id" uuid NOT NULL,
"kind" text NOT NULL,
"due_at" timestamp with time zone NOT NULL,
"timezone" text NOT NULL,
"status" text DEFAULT 'scheduled' NOT NULL,
"provider" text NOT NULL,
"provider_dispatch_id" text,
"ad_hoc_notification_id" uuid,
"period" text,
"sent_at" timestamp with time zone,
"cancelled_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "scheduled_dispatches" ADD CONSTRAINT "scheduled_dispatches_household_id_households_id_fk" FOREIGN KEY ("household_id") REFERENCES "public"."households"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "scheduled_dispatches" ADD CONSTRAINT "scheduled_dispatches_ad_hoc_notification_id_ad_hoc_notifications_id_fk" FOREIGN KEY ("ad_hoc_notification_id") REFERENCES "public"."ad_hoc_notifications"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "scheduled_dispatches_due_idx" ON "scheduled_dispatches" USING btree ("status","due_at");--> statement-breakpoint
CREATE INDEX "scheduled_dispatches_household_kind_idx" ON "scheduled_dispatches" USING btree ("household_id","kind","status");--> statement-breakpoint
CREATE UNIQUE INDEX "scheduled_dispatches_ad_hoc_notification_unique" ON "scheduled_dispatches" USING btree ("ad_hoc_notification_id");

File diff suppressed because it is too large Load Diff

View File

@@ -169,6 +169,13 @@
"when": 1774294611532,
"tag": "0023_huge_vision",
"breakpoints": true
},
{
"idx": 24,
"version": "7",
"when": 1774367260609,
"tag": "0024_lush_lucky_pierre",
"breakpoints": true
}
]
}

View File

@@ -553,6 +553,41 @@ export const adHocNotifications = pgTable(
})
)
export const scheduledDispatches = pgTable(
'scheduled_dispatches',
{
id: uuid('id').defaultRandom().primaryKey(),
householdId: uuid('household_id')
.notNull()
.references(() => households.id, { onDelete: 'cascade' }),
kind: text('kind').notNull(),
dueAt: timestamp('due_at', { withTimezone: true }).notNull(),
timezone: text('timezone').notNull(),
status: text('status').default('scheduled').notNull(),
provider: text('provider').notNull(),
providerDispatchId: text('provider_dispatch_id'),
adHocNotificationId: uuid('ad_hoc_notification_id').references(() => adHocNotifications.id, {
onDelete: 'cascade'
}),
period: text('period'),
sentAt: timestamp('sent_at', { withTimezone: true }),
cancelledAt: timestamp('cancelled_at', { withTimezone: true }),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
},
(table) => ({
dueIdx: index('scheduled_dispatches_due_idx').on(table.status, table.dueAt),
householdKindIdx: index('scheduled_dispatches_household_kind_idx').on(
table.householdId,
table.kind,
table.status
),
adHocNotificationUnique: uniqueIndex('scheduled_dispatches_ad_hoc_notification_unique').on(
table.adHocNotificationId
)
})
)
export const topicMessages = pgTable(
'topic_messages',
{