-- Notifications Engine (Sprint 2-3). NU o notificare per eveniment: motorul -- decide daca merita, cui, ce severitate, daca se agrega si cand se livreaza. DO $$ BEGIN CREATE TYPE "notification_severity" AS ENUM ('CRITICAL','ACTION_REQUIRED','WARNING','INFORMATION','INTELLIGENCE','SYSTEM'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; DO $$ BEGIN CREATE TYPE "notification_status" AS ENUM ('PENDING','SCHEDULED','DELIVERING','DELIVERED','READ','ACKNOWLEDGED', 'DISMISSED','FAILED','EXPIRED','ESCALATED'); EXCEPTION WHEN duplicate_object THEN NULL; END $$; CREATE TABLE IF NOT EXISTS "notifications" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "workspace_id" uuid, "recipient_user_id" uuid NOT NULL, "category" text NOT NULL, "severity" "notification_severity" NOT NULL, "title" text NOT NULL, "body" text, "source_event_id" uuid, "source_entity_type" text, "source_entity_id" text, "action_url" text, "action_type" text, "status" "notification_status" DEFAULT 'PENDING' NOT NULL, "deduplication_key" text NOT NULL, "aggregation_key" text, "aggregated_count" integer DEFAULT 1 NOT NULL, "channels" jsonb DEFAULT '["in_app"]'::jsonb NOT NULL, "scheduled_at" timestamp, "expires_at" timestamp, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL, "read_at" timestamp, "acknowledged_at" timestamp, "snoozed_until" timestamp, "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL ); CREATE INDEX IF NOT EXISTS "notifications_recipient_idx" ON "notifications" ("recipient_user_id","status"); CREATE INDEX IF NOT EXISTS "notifications_tenant_idx" ON "notifications" ("tenant_id","created_at"); CREATE INDEX IF NOT EXISTS "notifications_dedup_idx" ON "notifications" ("deduplication_key","created_at"); CREATE TABLE IF NOT EXISTS "notification_preferences" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "tenant_id" uuid NOT NULL, "user_id" uuid NOT NULL, "category" text, "enabled" integer DEFAULT 1 NOT NULL, "minimum_severity" "notification_severity" DEFAULT 'INFORMATION' NOT NULL, "quiet_hours_start" integer, "quiet_hours_end" integer, "critical_bypasses_quiet_hours" integer DEFAULT 1 NOT NULL, "timezone" text DEFAULT 'Europe/Bucharest' NOT NULL, "created_at" timestamp DEFAULT now() NOT NULL, "updated_at" timestamp DEFAULT now() NOT NULL ); -- NULLS NOT DISTINCT: category NULL inseamna "toate categoriile" si trebuie sa -- fie unic per (user, tenant), altfel ON CONFLICT n-ar prinde randul implicit. CREATE UNIQUE INDEX IF NOT EXISTS "notification_prefs_uq" ON "notification_preferences" ("user_id","tenant_id","category") NULLS NOT DISTINCT; CREATE TABLE IF NOT EXISTS "notification_processed_events" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "rule_id" text NOT NULL, "event_id" uuid NOT NULL, "processed_at" timestamp DEFAULT now() NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS "notification_processed_uq" ON "notification_processed_events" ("rule_id","event_id");