From f86cc446a3c7f3f003d3aae0f70e51661ad83a60 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Thu, 10 Apr 2025 01:50:56 +0000 Subject: [PATCH] Add webhook delivery log tracking Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/119179b7-2f0c-4f11-8282-85c8176fc124.jpg --- server/storage.ts | 5 +++++ shared/schema.ts | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/server/storage.ts b/server/storage.ts index c9c264d..f10cb49 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -70,6 +70,11 @@ export interface IStorage { deleteWebhook(id: string): Promise; triggerWebhook(webhookId: string, payload: any): Promise; + // Webhook Delivery Logs + addWebhookDeliveryLog(log: InsertWebhookDeliveryLog): Promise; + getWebhookDeliveryLog(id: string): Promise; + getWebhookDeliveryLogsByWebhook(webhookId: string): Promise; + // Session store sessionStore: any; } diff --git a/shared/schema.ts b/shared/schema.ts index 68aa604..4e59206 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -103,6 +103,21 @@ export const webhooks = pgTable("webhooks", { createdAt: timestamp("created_at").defaultNow().notNull(), }); +// Webhook delivery logs for tracking delivery status and history +export const webhookDeliveryLogs = pgTable("webhook_delivery_logs", { + id: uuid("id").defaultRandom().primaryKey(), + webhookId: uuid("webhook_id").notNull().references(() => webhooks.id, { onDelete: "cascade" }), + event: text("event").notNull(), + payload: jsonb("payload").notNull(), + signature: text("signature"), + status: boolean("status").notNull(), + statusCode: integer("status_code"), + message: text("message").notNull(), + responseBody: text("response_body"), + retryCount: integer("retry_count").notNull().default(0), + createdAt: timestamp("created_at").defaultNow().notNull(), +}); + // Custom roles table for user-defined roles beyond system defaults export const customRoles = pgTable("custom_roles", { id: uuid("id").defaultRandom().primaryKey(), @@ -240,6 +255,18 @@ export const insertWebhookSchema = createInsertSchema(webhooks).pick({ createdBy: true, }); +export const insertWebhookDeliveryLogSchema = createInsertSchema(webhookDeliveryLogs).pick({ + webhookId: true, + event: true, + payload: true, + signature: true, + status: true, + statusCode: true, + message: true, + responseBody: true, + retryCount: true, +}); + // Types export type InsertUser = z.infer; @@ -272,6 +299,8 @@ export type InsertGroupMember = z.infer; export type InsertGroupRole = z.infer; export type InsertWebhook = z.infer; export type Webhook = typeof webhooks.$inferSelect; +export type InsertWebhookDeliveryLog = z.infer; +export type WebhookDeliveryLog = typeof webhookDeliveryLogs.$inferSelect; // Role Types // System default roles - these will still be available alongside custom roles @@ -347,7 +376,7 @@ export const apiTokensRelations = relations(apiTokens, ({ one }) => ({ }), })); -export const webhooksRelations = relations(webhooks, ({ one }) => ({ +export const webhooksRelations = relations(webhooks, ({ one, many }) => ({ organization: one(organizations, { fields: [webhooks.organizationId], references: [organizations.id], @@ -356,6 +385,14 @@ export const webhooksRelations = relations(webhooks, ({ one }) => ({ fields: [webhooks.createdBy], references: [users.id], }), + deliveryLogs: many(webhookDeliveryLogs), +})); + +export const webhookDeliveryLogsRelations = relations(webhookDeliveryLogs, ({ one }) => ({ + webhook: one(webhooks, { + fields: [webhookDeliveryLogs.webhookId], + references: [webhooks.id], + }), }));