-- ============================================
-- Outbox 事件表 (可靠事件发布)
-- [2026-01-07] 新增：实现 Outbox Pattern 确保事件发布的原子性
--
-- 用途：
-- 1. 业务操作和事件写入在同一个事务中完成
-- 2. 后台任务轮询此表发布事件到 Kafka
-- 3. 保证事件不丢失，即使 Kafka 暂时不可用
-- ============================================

CREATE TABLE IF NOT EXISTS "outbox_events" (
    "outbox_id" BIGSERIAL PRIMARY KEY,

    -- 事件信息
    "event_type" VARCHAR(100) NOT NULL,      -- 事件类型 (如 wallet.system-withdrawal.requested)
    "topic" VARCHAR(100) NOT NULL,           -- Kafka topic
    "key" VARCHAR(200) NOT NULL,             -- Kafka message key (通常是 orderNo 或 aggregateId)
    "payload" JSONB NOT NULL,                -- 事件载荷 (JSON 格式)

    -- 聚合根信息 (用于幂等性检查和事件确认)
    "aggregate_id" VARCHAR(100) NOT NULL,    -- 聚合根ID (如 orderNo)
    "aggregate_type" VARCHAR(50) NOT NULL,   -- 聚合根类型 (如 SystemWithdrawalOrder)

    -- 发布状态
    "status" VARCHAR(20) NOT NULL DEFAULT 'PENDING',  -- PENDING, SENT, CONFIRMED, FAILED
    "retry_count" INT NOT NULL DEFAULT 0,             -- 重试次数
    "max_retries" INT NOT NULL DEFAULT 5,             -- 最大重试次数
    "last_error" TEXT,                                -- 最后一次错误信息

    -- 时间戳
    "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,  -- 创建时间
    "published_at" TIMESTAMP,                                    -- 发布到 Kafka 的时间
    "next_retry_at" TIMESTAMP                                    -- 下次重试时间 (失败时设置)
);

-- 索引
-- 1. 状态+创建时间：用于轮询待发布事件
CREATE INDEX "idx_outbox_status_created" ON "outbox_events" ("status", "created_at");

-- 2. 状态+下次重试时间：用于查找需要重试的事件
CREATE INDEX "idx_outbox_status_next_retry" ON "outbox_events" ("status", "next_retry_at");

-- 3. 聚合根类型+ID：用于按聚合根查找事件（确认时使用）
CREATE INDEX "idx_outbox_aggregate" ON "outbox_events" ("aggregate_type", "aggregate_id");

-- 4. Topic：用于按主题统计
CREATE INDEX "idx_outbox_topic" ON "outbox_events" ("topic");

-- 添加注释
COMMENT ON TABLE "outbox_events" IS 'Outbox 事件表 - 实现可靠的事件发布机制';
COMMENT ON COLUMN "outbox_events"."status" IS 'PENDING=待发送, SENT=已发送待确认, CONFIRMED=已确认, FAILED=失败';
COMMENT ON COLUMN "outbox_events"."retry_count" IS '当前重试次数，达到 max_retries 后停止重试';
COMMENT ON COLUMN "outbox_events"."next_retry_at" IS '使用指数退避策略计算的下次重试时间';
