-- M8 基础设施:站内消息(Inbox)
-- 通知 worker 将 outbox 事件物化为站内消息;管理员可广播;门户/管理员收件箱按行读回执。

-- inbox_messages:一条消息一个收件人(sender 广播时枚举收件人逐行落库)。
-- recipient_kind + recipient_user_id 区分 admin/portal 两个身份表;不设 FK(跨表)。
CREATE TABLE IF NOT EXISTS gateway.inbox_messages (
    id uuid PRIMARY KEY,
    source_event_id uuid,                      -- 来源 outbox 事件;广播无来源事件为 NULL
    recipient_kind text NOT NULL CHECK (recipient_kind IN ('admin', 'portal')),
    recipient_user_id uuid NOT NULL,           -- 具体收件人(admin 或 portal 账号 id)
    sender_type text NOT NULL CHECK (sender_type IN ('system', 'admin', 'portal')),
    category text NOT NULL CHECK (category IN ('system', 'approval', 'task_result', 'resource')),
    title text NOT NULL CHECK (length(title) BETWEEN 1 AND 256),
    body text NOT NULL DEFAULT '' CHECK (length(body) <= 4000),
    link text NOT NULL DEFAULT '' CHECK (length(link) <= 512),
    payload jsonb,
    read_at timestamptz,                       -- 已读回执;NULL=未读
    created_at timestamptz NOT NULL DEFAULT clock_timestamp()
);

-- 幂等:同一来源事件对同一收件人只落一条(重放不重复);NULLS NOT DISTINCT 兜底 NULL 收件人。
CREATE UNIQUE INDEX IF NOT EXISTS inbox_messages_source_event_idx
    ON gateway.inbox_messages (source_event_id, recipient_kind, recipient_user_id)
    NULLS NOT DISTINCT
    WHERE source_event_id IS NOT NULL;

-- 收件箱按收件人倒序 + 未读数
CREATE INDEX IF NOT EXISTS inbox_messages_recipient_idx
    ON gateway.inbox_messages (recipient_kind, recipient_user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS inbox_messages_unread_idx
    ON gateway.inbox_messages (recipient_kind, recipient_user_id)
    WHERE read_at IS NULL;
