0021_webhook_subscribers.sql 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. -- 0021_webhook_subscribers — outbound (platform → customer) webhooks.
  2. -- briven emits events (abuse.report.opened, deploy.succeeded, ...) and
  3. -- fans them out to every matching subscriber. Deliveries retry on
  4. -- failure with exponential backoff up to 5 attempts; the dispatcher
  5. -- claims rows via the partial index on status='pending'.
  6. CREATE TABLE IF NOT EXISTS "webhook_subscribers" (
  7. "id" text PRIMARY KEY NOT NULL,
  8. "project_id" text NOT NULL,
  9. "name" text NOT NULL,
  10. "target_url" text NOT NULL,
  11. "event_types" text NOT NULL DEFAULT '*',
  12. "signing_secret_encrypted" text NOT NULL,
  13. "enabled" boolean DEFAULT true NOT NULL,
  14. "last_delivery_at" timestamp with time zone,
  15. "last_delivery_status" text,
  16. "created_by" text,
  17. "created_at" timestamp with time zone DEFAULT now() NOT NULL,
  18. "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
  19. "deleted_at" timestamp with time zone,
  20. CONSTRAINT "webhook_subscribers_project_id_fk"
  21. FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE,
  22. CONSTRAINT "webhook_subscribers_created_by_fk"
  23. FOREIGN KEY ("created_by") REFERENCES "users"("id") ON DELETE SET NULL
  24. );
  25. CREATE UNIQUE INDEX IF NOT EXISTS "webhook_subscribers_project_name_idx"
  26. ON "webhook_subscribers" USING btree ("project_id", "name")
  27. WHERE "deleted_at" IS NULL;
  28. CREATE INDEX IF NOT EXISTS "webhook_subscribers_project_idx"
  29. ON "webhook_subscribers" USING btree ("project_id")
  30. WHERE "deleted_at" IS NULL;
  31. CREATE TABLE IF NOT EXISTS "webhook_outbound_deliveries" (
  32. "id" text PRIMARY KEY NOT NULL,
  33. "subscriber_id" text NOT NULL,
  34. "project_id" text NOT NULL,
  35. "event_id" text NOT NULL,
  36. "event_type" text NOT NULL,
  37. "payload" jsonb NOT NULL,
  38. "status" text DEFAULT 'pending' NOT NULL,
  39. "attempt_count" text DEFAULT '0' NOT NULL,
  40. "next_attempt_at" timestamp with time zone NOT NULL,
  41. "last_attempt_at" timestamp with time zone,
  42. "status_code" text,
  43. "duration_ms" text,
  44. "error_message" text,
  45. "created_at" timestamp with time zone DEFAULT now() NOT NULL,
  46. CONSTRAINT "webhook_outbound_deliveries_subscriber_id_fk"
  47. FOREIGN KEY ("subscriber_id") REFERENCES "webhook_subscribers"("id") ON DELETE CASCADE,
  48. CONSTRAINT "webhook_outbound_deliveries_project_id_fk"
  49. FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE CASCADE
  50. );
  51. -- Dispatcher hot path: pending rows only.
  52. CREATE INDEX IF NOT EXISTS "webhook_outbound_deliveries_due_idx"
  53. ON "webhook_outbound_deliveries" USING btree ("next_attempt_at")
  54. WHERE "status" = 'pending';
  55. CREATE INDEX IF NOT EXISTS "webhook_outbound_deliveries_subscriber_idx"
  56. ON "webhook_outbound_deliveries" USING btree ("subscriber_id", "created_at");
  57. CREATE INDEX IF NOT EXISTS "webhook_outbound_deliveries_project_idx"
  58. ON "webhook_outbound_deliveries" USING btree ("project_id", "created_at");
  59. CREATE INDEX IF NOT EXISTS "webhook_outbound_deliveries_event_id_idx"
  60. ON "webhook_outbound_deliveries" USING btree ("event_id");