CREATE TABLE "app_notification_deliveries" ( "id" text PRIMARY KEY NOT NULL, "organization_id" text NOT NULL, "notification_id" text NOT NULL, "channel" text NOT NULL, "recipient_address" text, "status" text DEFAULT 'pending' NOT NULL, "attempt_count" integer DEFAULT 0 NOT NULL, "last_error" text, "sent_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 CREATE TABLE "app_notification_events" ( "id" text PRIMARY KEY NOT NULL, "organization_id" text NOT NULL, "event_type" text NOT NULL, "entity_type" text NOT NULL, "entity_id" text NOT NULL, "actor_user_id" text, "payload" jsonb, "dedupe_key" text, "status" text DEFAULT 'pending' NOT NULL, "last_error" text, "published_at" timestamp with time zone DEFAULT now() NOT NULL, "processed_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 CREATE TABLE "app_notification_templates" ( "id" text PRIMARY KEY NOT NULL, "organization_id" text NOT NULL, "event_type" text NOT NULL, "channel" text NOT NULL, "title_template" text NOT NULL, "body_template" text NOT NULL, "link_template" text, "is_active" boolean DEFAULT true NOT NULL, "metadata" jsonb, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, "deleted_at" timestamp with time zone, "created_by" text NOT NULL, "updated_by" text NOT NULL ); --> statement-breakpoint CREATE TABLE "app_notifications" ( "id" text PRIMARY KEY NOT NULL, "organization_id" text NOT NULL, "recipient_user_id" text NOT NULL, "event_id" text NOT NULL, "title" text NOT NULL, "body" text NOT NULL, "link_url" text, "severity" text DEFAULT 'info' NOT NULL, "status" text DEFAULT 'unread' NOT NULL, "read_at" timestamp with time zone, "archived_at" timestamp with time zone, "metadata" jsonb, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE UNIQUE INDEX "app_notification_events_org_dedupe_idx" ON "app_notification_events" USING btree ("organization_id", "dedupe_key"); --> statement-breakpoint CREATE UNIQUE INDEX "app_notification_templates_org_event_channel_idx" ON "app_notification_templates" USING btree ("organization_id", "event_type", "channel"); --> statement-breakpoint CREATE UNIQUE INDEX "app_notifications_recipient_event_idx" ON "app_notifications" USING btree ("recipient_user_id", "event_id");