← 返回文档中心

B2B2B 酒店分销平台 - 数据模型设计

版本: v1.0
来源: 从系统架构总纲文档提取
包含模块: 6.1-6.12 + 11.x 补充能力模块 + 12.x AI Agent 智能运营层


目录


6.1 酒店房型基础

-- 酒店主表
CREATE TABLE hotels (
    id              BIGSERIAL PRIMARY KEY,
    hotel_code      VARCHAR(32) NOT NULL UNIQUE,     -- 平台统一编码 HPT-XXXXX
    name_en         VARCHAR(255) NOT NULL,            -- 英文名
    name_local      VARCHAR(255),                     -- 当地语言名
    country_code    VARCHAR(3) NOT NULL,              -- ISO 3166-1 alpha-3
    city_code       VARCHAR(8) NOT NULL,              -- 城市编码
    address         TEXT,
    latitude        DECIMAL(10, 7),
    longitude       DECIMAL(10, 7),
    star_rating     SMALLINT CHECK (star_rating BETWEEN 1 AND 5),
    chain_code      VARCHAR(16),                      -- 酒店集团编码
    geo_info        JSONB,                            -- 扩展地理信息
    facilities      JSONB,                            -- {"wifi":true,"pool":true,"parking":false}
    images          JSONB,                            -- 图片URL列表
    check_in_time   TIME DEFAULT '14:00:00',
    check_out_time  TIME DEFAULT '12:00:00',
    contact_info    JSONB,                            -- 电话、邮箱、网站
    status          VARCHAR(20) DEFAULT 'active',     -- active/inactive/pending
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),
    source          VARCHAR(32) DEFAULT 'manual'      -- manual/api/import
);

CREATE INDEX idx_hotels_geo ON hotels USING GIST (
    ll_to_earth(latitude, longitude)
);
CREATE INDEX idx_hotels_city ON hotels (city_code);
CREATE INDEX idx_hotels_status ON hotels (status);
CREATE INDEX idx_hotels_facilities ON hotels USING GIN (facilities);
CREATE INDEX idx_hotels_chain ON hotels (chain_code);

-- 标准房型表
CREATE TABLE room_types (
    id              BIGSERIAL PRIMARY KEY,
    room_code       VARCHAR(32) NOT NULL UNIQUE,     -- 平台统一编码
    hotel_id        BIGINT REFERENCES hotels(id) ON DELETE CASCADE,
    name_en         VARCHAR(128) NOT NULL,
    name_local      VARCHAR(128),
    bed_type        VARCHAR(64),                     -- Double/Twin/King/Sofa
    max_adults      SMALLINT DEFAULT 2,
    max_children    SMALLINT DEFAULT 0,
    room_size_sqm   DECIMAL(6, 1),
    floor           VARCHAR(32),
    bed_count       SMALLINT DEFAULT 1,
    facilities      JSONB,                            -- 房间设施
    description     TEXT,
    images          JSONB,
    status          VARCHAR(20) DEFAULT 'active',
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_room_types_hotel ON room_types (hotel_id);

-- 供应商酒店映射源数据表
CREATE TABLE supplier_hotels (
    id              BIGSERIAL PRIMARY KEY,
    supplier_code   VARCHAR(32) NOT NULL,             -- 供应商编码
    supplier_hotel_id VARCHAR(64) NOT NULL,           -- 供应商侧酒店ID
    hotel_id        BIGINT REFERENCES hotels(id),     -- 映射到平台酒店(可为空=待匹配)
    raw_data        JSONB NOT NULL,                   -- 原始数据快照
    name            VARCHAR(255),                     -- 供应商侧名称
    city_code       VARCHAR(8),
    star_rating     SMALLINT,
    latitude        DECIMAL(10, 7),
    longitude       DECIMAL(10, 7),
    last_synced_at  TIMESTAMPTZ,
    connection_mode         VARCHAR(32) DEFAULT 'direct_connect', -- direct_connect/direct_procure(供应商-酒店级别)
    sync_interval_minutes   INT DEFAULT 120,                     -- 直采拉取间隔
    sync_validity_minutes   INT DEFAULT 120,                     -- 直采价格有效期
    sync_max_failures       INT DEFAULT 3,                       -- 降级阈值
    sync_suspend_threshold  INT DEFAULT 10,                      -- 暂停阈值
    sync_status             VARCHAR(20) DEFAULT 'normal',        -- normal/degraded/suspended
    sync_fail_count         INT DEFAULT 0,
    match_status    VARCHAR(20) DEFAULT 'pending',    -- pending/matched/unmatched/manual_review
    match_confidence DECIMAL(5, 2),                   -- 匹配置信度 0-100
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(supplier_code, supplier_hotel_id)
);

CREATE INDEX idx_supplier_hotels_match ON supplier_hotels (match_status);
CREATE INDEX idx_supplier_hotels_supplier ON supplier_hotels (supplier_code);

-- 供应商房型映射源数据表
CREATE TABLE supplier_room_types (
    id                  BIGSERIAL PRIMARY KEY,
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_room_code  VARCHAR(64) NOT NULL,
    supplier_hotel_id   VARCHAR(64) NOT NULL,
    room_type_id        BIGINT REFERENCES room_types(id),  -- 映射到平台房型
    raw_data            JSONB NOT NULL,
    name                VARCHAR(255),
    match_status        VARCHAR(20) DEFAULT 'pending',
    match_confidence    DECIMAL(5, 2),
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(supplier_code, supplier_room_code, supplier_hotel_id)
);

-- 城市字典表
CREATE TABLE cities (
    code            VARCHAR(8) PRIMARY KEY,
    name_en         VARCHAR(128) NOT NULL,
    name_local      VARCHAR(128),
    country_code    VARCHAR(3) NOT NULL,
    latitude        DECIMAL(10, 7),
    longitude       DECIMAL(10, 7),
    timezone        VARCHAR(32),
    status          VARCHAR(20) DEFAULT 'active'
);

-- 设施字典表
CREATE TABLE facility_dict (
    id              SERIAL PRIMARY KEY,
    category        VARCHAR(32) NOT NULL,             -- general/room/dining/sports/business
    code            VARCHAR(32) NOT NULL UNIQUE,      -- wifi/pool/gym/spa/parking
    name_en         VARCHAR(64) NOT NULL,
    name_local      VARCHAR(128),
    icon            VARCHAR(64)
);

6.2 匹配管理

-- 匹配规则表
CREATE TABLE match_rules (
    id              SERIAL PRIMARY KEY,
    supplier_code   VARCHAR(32) NOT NULL,
    rule_type       VARCHAR(32) NOT NULL,     -- hotel/room_type
    field_name      VARCHAR(64) NOT NULL,     -- name/lat_lng/address/star
    algorithm       VARCHAR(64) NOT NULL,     -- levenshtein/haversine/exact/regex
    weight          DECIMAL(3, 2) NOT NULL,   -- 权重 0.00-1.00
    threshold       DECIMAL(5, 2),            -- 单字段阈值
    params          JSONB,                    -- 算法参数
    priority        SMALLINT DEFAULT 0,
    enabled         BOOLEAN DEFAULT true,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 匹配任务表
CREATE TABLE match_tasks (
    id              BIGSERIAL PRIMARY KEY,
    task_type       VARCHAR(32) NOT NULL,     -- hotel/room_type
    supplier_code   VARCHAR(32) NOT NULL,
    total_count     INT DEFAULT 0,
    matched_count   INT DEFAULT 0,
    pending_count   INT DEFAULT 0,
    failed_count    INT DEFAULT 0,
    status          VARCHAR(20) DEFAULT 'pending',  -- pending/running/completed/failed
    started_at      TIMESTAMPTZ,
    completed_at    TIMESTAMPTZ,
    created_by      VARCHAR(64),
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 匹配历史表(审计)
CREATE TABLE match_history (
    id              BIGSERIAL PRIMARY KEY,
    task_id         BIGINT REFERENCES match_tasks(id),
    supplier_code   VARCHAR(32),
    match_type      VARCHAR(32),             -- hotel/room_type
    supplier_id     VARCHAR(64) NOT NULL,
    platform_id     BIGINT,                  -- 匹配到的平台ID
    confidence      DECIMAL(5, 2),
    match_method    VARCHAR(32),             -- auto/manual/unmatched
    old_platform_id BIGINT,                  -- 变更前的映射(如重新匹配)
    details         JSONB,                   -- 各维度得分明细
    operator        VARCHAR(64),             -- 操作人(auto/manual)
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_match_history_task ON match_history (task_id);
CREATE INDEX idx_match_history_supplier ON match_history (supplier_code);

6.3 查价引擎

-- 查价请求日志表(写入 ClickHouse 用于分析,PG 做短期热数据)
CREATE TABLE price_search_logs (
    id              BIGSERIAL PRIMARY KEY,
    trace_id        VARCHAR(64) NOT NULL,          -- 链路追踪ID
    agent_code      VARCHAR(32) NOT NULL,          -- 代理商编码
    channel_code    VARCHAR(32),                   -- 渠道编码
    hotel_id        BIGINT,                        -- 平台酒店ID
    check_in        DATE NOT NULL,
    check_out       DATE NOT NULL,
    adults          SMALLINT DEFAULT 2,
    children        SMALLINT DEFAULT 0,
    room_count      SMALLINT DEFAULT 1,
    currency        VARCHAR(3) DEFAULT 'CNY',
    supplier_codes  VARCHAR(255),                  -- 查询了哪些供应商
    result_count    INT DEFAULT 0,                 -- 返回结果数量
    min_price       DECIMAL(12, 2),                -- 最低价
    cache_hit       BOOLEAN DEFAULT false,         -- 是否命中缓存
    response_ms     INT,                           -- 响应耗时
    error_code      VARCHAR(32),                   -- 错误码
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_search_logs_hotel_date ON price_search_logs (hotel_id, check_in, check_out);
CREATE INDEX idx_search_logs_agent ON price_search_logs (agent_code, created_at);

-- Redis 缓存 Key 设计
-- 查价缓存: price:search:{hotel_id}:{check_in}:{check_out}:{adults}:{children}:{room_count}:{currency}
-- TTL: 300s (5min)
-- Value: JSON数组,每个元素包含供应商、房型、价格、库存等

6.4 订单管理

-- 订单主表
CREATE TABLE orders (
    id                  BIGSERIAL PRIMARY KEY,
    order_no            VARCHAR(32) NOT NULL UNIQUE,     -- 平台订单号 PLT-YYYYMMDD-XXXXXX
    agent_code          VARCHAR(32) NOT NULL,            -- 代理商编码
    channel_code        VARCHAR(32),                     -- 渠道编码
    supplier_code       VARCHAR(32) NOT NULL,            -- 供应商编码
    supplier_order_no   VARCHAR(64),                     -- 供应商侧订单号

    -- 酒店信息快照
    hotel_id            BIGINT NOT NULL,
    hotel_name          VARCHAR(255) NOT NULL,            -- 下单时快照
    hotel_code          VARCHAR(32),                     -- 供应商侧酒店编码

    -- 房型信息快照
    room_type_code      VARCHAR(32) NOT NULL,
    room_type_name      VARCHAR(128) NOT NULL,
    meal_plan           VARCHAR(16) DEFAULT 'BB',

    -- 入住信息
    check_in            DATE NOT NULL,
    check_out           DATE NOT NULL,
    nights              SMALLINT GENERATED ALWAYS AS (check_out - check_in) STORED,
    adults              SMALLINT DEFAULT 2,
    children            SMALLINT DEFAULT 0,
    room_count          SMALLINT DEFAULT 1,

    -- 住客信息
    guest_name          VARCHAR(128),
    guest_email         VARCHAR(128),
    guest_phone         VARCHAR(32),
    special_requests    TEXT,

    -- 价格信息快照
    gross_price         DECIMAL(12, 2) NOT NULL,         -- 售价
    net_price           DECIMAL(12, 2) NOT NULL,         -- 采购价
    commission          DECIMAL(12, 2),                  -- 佣金
    currency            VARCHAR(3) DEFAULT 'CNY',

    -- 取消政策
    cancellation_policy JSONB,
    cancellation_deadline TIMESTAMPTZ,

    -- 状态
    status              VARCHAR(32) NOT NULL DEFAULT 'CREATED',

    -- 代理商侧引用号
    client_ref          VARCHAR(64),

    -- 内部信息
    internal_remarks    TEXT,
    operator            VARCHAR(64),

    -- 时间戳
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW(),
    confirmed_at        TIMESTAMPTZ,
    cancelled_at        TIMESTAMPTZ,
    completed_at        TIMESTAMPTZ,
    expired_at          TIMESTAMPTZ
);

CREATE INDEX idx_orders_agent ON orders (agent_code, created_at DESC);
CREATE INDEX idx_orders_supplier ON orders (supplier_code, status);
CREATE INDEX idx_orders_hotel_date ON orders (hotel_id, check_in);
CREATE INDEX idx_orders_status ON orders (status, created_at DESC);
CREATE INDEX idx_orders_no ON orders (order_no);

-- 订单状态变更历史表
CREATE TABLE order_status_logs (
    id              BIGSERIAL PRIMARY KEY,
    order_id        BIGINT NOT NULL REFERENCES orders(id),
    from_status     VARCHAR(32),
    to_status       VARCHAR(32) NOT NULL,
    reason          TEXT,
    operator        VARCHAR(64),             -- system/agent_name/manual
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_order_status_logs_order ON order_status_logs (order_id);

-- 订单备注表
CREATE TABLE order_remarks (
    id              BIGSERIAL PRIMARY KEY,
    order_id        BIGINT NOT NULL REFERENCES orders(id),
    content         TEXT NOT NULL,
    remark_type     VARCHAR(16) DEFAULT 'internal',  -- internal/agent/supplier
    creator         VARCHAR(64),
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 供应商订单关联表(一笔平台订单可能对应多笔供应商订单)
CREATE TABLE supplier_orders (
    id                  BIGSERIAL PRIMARY KEY,
    platform_order_id   BIGINT NOT NULL REFERENCES orders(id),
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_order_no   VARCHAR(64),
    supplier_status     VARCHAR(32),                     -- 供应商侧状态
    raw_response        JSONB,                           -- 供应商原始响应
    error_message       TEXT,
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW()
);

6.5 销售管理

6.5 基础表

-- 代理商表
CREATE TABLE agents (
    id              BIGSERIAL PRIMARY KEY,
    agent_code      VARCHAR(32) NOT NULL UNIQUE,     -- AGT-XXXXX
    company_name    VARCHAR(255) NOT NULL,
    contact_name    VARCHAR(64),
    contact_email   VARCHAR(64) NOT NULL UNIQUE,
    contact_phone   VARCHAR(32),
    country_code    VARCHAR(3) DEFAULT 'CN',
    city            VARCHAR(64),
    address         TEXT,
    business_license VARCHAR(128),                   -- 营业执照号
    credit_limit    DECIMAL(12, 2) DEFAULT 0,        -- 信用额度
    credit_used     DECIMAL(12, 2) DEFAULT 0,        -- 已用额度
    level           VARCHAR(16) DEFAULT 'standard',  -- standard/silver/gold/platinum
    status          VARCHAR(20) DEFAULT 'pending',   -- pending/active/suspended/closed
    api_key_hash    VARCHAR(128),                    -- API Key 哈希
    api_secret_hash VARCHAR(128),
    webhook_url     VARCHAR(512),
    contract_id     BIGINT,                          -- 关联合同
    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 供应商表
CREATE TABLE suppliers (
    id              BIGSERIAL PRIMARY KEY,
    supplier_code   VARCHAR(32) NOT NULL UNIQUE,     -- SUP-XXXXX
    company_name    VARCHAR(255) NOT NULL,
    supplier_type   VARCHAR(32) NOT NULL,            -- wholesaler/chain_hotel/independent_hotel
    contact_name    VARCHAR(64),
    contact_email   VARCHAR(64) NOT NULL,
    contact_phone   VARCHAR(32),
    country_code    VARCHAR(3),
    api_endpoint    VARCHAR(512),                    -- 供应商API地址
    api_auth_type   VARCHAR(32),                     -- api_key/oauth2/basic
    api_credentials JSONB,                           -- 加密存储
    webhook_url     VARCHAR(512),                    -- 回调地址
    status          VARCHAR(20) DEFAULT 'pending',   -- pending/active/suspended/closed
    connection_mode VARCHAR(32) NOT NULL DEFAULT 'direct_connect',  -- direct_connect(直连:实时查价,有价即有房) / direct_procure(直采:预采购库存,平台持有)
    priority        SMALLINT DEFAULT 0,              -- 查价优先级
    avg_response_ms INT,                             -- 平均响应时间
    availability    DECIMAL(5, 2),                   -- 可用率百分比
    contract_id     BIGINT,
    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 渠道表
CREATE TABLE channels (
    id              SERIAL PRIMARY KEY,
    channel_code    VARCHAR(32) NOT NULL UNIQUE,     -- CHN-XXXXX
    channel_name    VARCHAR(128) NOT NULL,
    channel_type    VARCHAR(32) NOT NULL,            -- direct/ota/wholesale/corporate
    description     TEXT,
    commission_rate DECIMAL(5, 2) DEFAULT 0,        -- 默认佣金率 %
    markup_type     VARCHAR(16) DEFAULT 'percentage',-- percentage/fixed
    markup_value    DECIMAL(8, 2) DEFAULT 0,        -- 加价值
    status          VARCHAR(20) DEFAULT 'active',
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 合同表
CREATE TABLE contracts (
    id              BIGSERIAL PRIMARY KEY,
    contract_no     VARCHAR(32) NOT NULL UNIQUE,
    contract_type   VARCHAR(32) NOT NULL,            -- supplier/agent/channel
    party_code      VARCHAR(32) NOT NULL,            -- 对方编码(供应商/代理商)
    party_name      VARCHAR(255) NOT NULL,
    start_date      DATE NOT NULL,
    end_date        DATE,
    status          VARCHAR(20) DEFAULT 'draft',     -- draft/active/expired/terminated

    -- 商务条款
    payment_terms   VARCHAR(64) DEFAULT 'prepaid',   -- prepaid/postpaid/credit
    credit_days     SMALLINT DEFAULT 0,              -- 账期天数
    commission_rate DECIMAL(5, 2) DEFAULT 0,
    cancellation_policy JSONB,
    special_terms   JSONB,

    -- 合同文件
    file_url        VARCHAR(512),

    -- SLA
    sla_response_time_ms INT DEFAULT 3000,
    sla_availability   DECIMAL(5, 2) DEFAULT 99.5,

    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

6.5.1 精细化管控表

-- 渠道可见性规则表
CREATE TABLE channel_visibility (
    id              BIGSERIAL PRIMARY KEY,
    agent_id        BIGINT NOT NULL REFERENCES agents(id),
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT REFERENCES hotels(id),             -- NULL = 该供应商下所有酒店
    country_code    VARCHAR(3),                               -- NULL = 不限国家
    visibility_type VARCHAR(16) NOT NULL DEFAULT 'whitelist', -- whitelist/blacklist
    priority        SMALLINT DEFAULT 0,                      -- 规则优先级,数值越大优先级越高
    effective_date  DATE DEFAULT CURRENT_DATE,
    expire_date     DATE,                                    -- NULL = 永久有效
    created_by      VARCHAR(64) NOT NULL,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_visibility_agent ON channel_visibility (agent_id, visibility_type, effective_date, expire_date);
CREATE INDEX idx_visibility_supplier ON channel_visibility (supplier_id, visibility_type);

-- 熔断记录表
CREATE TABLE circuit_breaker (
    id              BIGSERIAL PRIMARY KEY,
    party_type      VARCHAR(16) NOT NULL,       -- agent/supplier
    party_id        BIGINT NOT NULL,            -- agents.id 或 suppliers.id
    reason          VARCHAR(128) NOT NULL,      -- 触发原因
    status          VARCHAR(16) NOT NULL DEFAULT 'open',  -- open(熔断中)/ half_open(半开)/ closed(正常)
    triggered_at    TIMESTAMPTZ NOT NULL,       -- 熔断触发时间
    recovered_at    TIMESTAMPTZ,               -- 恢复时间
    config          JSONB NOT NULL DEFAULT '{}', -- 熔断配置(阈值、恢复策略等)
    operated_by     VARCHAR(64) NOT NULL,       -- 操作人(system/manual)
    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_cb_party ON circuit_breaker (party_type, party_id, status);
CREATE INDEX idx_cb_status ON circuit_breaker (status, triggered_at);

-- 准入审核记录表
CREATE TABLE onboarding_reviews (
    id              BIGSERIAL PRIMARY KEY,
    party_type      VARCHAR(16) NOT NULL,        -- agent/supplier
    party_id        BIGINT NOT NULL,
    review_type     VARCHAR(32) NOT NULL,         -- tech_verify/commercial_review/trial_upgrade
    reviewer        VARCHAR(64) NOT NULL,
    result          VARCHAR(16) NOT NULL,         -- approved/rejected/pending
    comments        TEXT,
    metadata        JSONB DEFAULT '{}',           -- 审核元数据
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 信用额度变更记录表
CREATE TABLE credit_ledger (
    id              BIGSERIAL PRIMARY KEY,
    agent_id        BIGINT NOT NULL REFERENCES agents(id),
    amount          DECIMAL(12, 2) NOT NULL,     -- 正数=充值/释放,负数=扣减/冻结
    balance_after   DECIMAL(12, 2) NOT NULL,     -- 变更后余额
    transaction_type VARCHAR(32) NOT NULL,       -- recharge/freeze/unfreeze/deduct/refund/adjust
    reference_id    BIGINT,                       -- 关联单据(订单号/充值单号等)
    reference_type  VARCHAR(32),                  -- order/recharge/adjustment
    description     TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_credit_ledger_agent ON credit_ledger (agent_id, created_at DESC);

-- 额度预警记录表
CREATE TABLE credit_alerts (
    id              BIGSERIAL PRIMARY KEY,
    agent_id        BIGINT NOT NULL REFERENCES agents(id),
    alert_level     VARCHAR(8) NOT NULL,          -- warning(80%)/critical(90%)/exhausted(100%)
    usage_rate      DECIMAL(5, 2) NOT NULL,       -- 使用率百分比
    credit_limit    DECIMAL(12, 2) NOT NULL,
    credit_used     DECIMAL(12, 2) NOT NULL,
    is_resolved     BOOLEAN DEFAULT FALSE,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_credit_alerts_agent ON credit_alerts (agent_id, is_resolved);

6.6 价格管理

-- 币种与汇率表
CREATE TABLE currencies (
    code            VARCHAR(3) PRIMARY KEY,          -- ISO 4217
    name            VARCHAR(64) NOT NULL,
    symbol          VARCHAR(8),
    exchange_rate   DECIMAL(12, 6) NOT NULL,         -- 相对基准货币(CNY)
    base_currency   VARCHAR(3) DEFAULT 'CNY',
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 汇率历史表
CREATE TABLE exchange_rate_history (
    id              BIGSERIAL PRIMARY KEY,
    from_currency   VARCHAR(3) NOT NULL,
    to_currency     VARCHAR(3) NOT NULL,
    rate            DECIMAL(12, 6) NOT NULL,
    source          VARCHAR(32) DEFAULT 'manual',    -- manual/api/exchangerate
    effective_at    TIMESTAMPTZ NOT NULL,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 加价策略表
CREATE TABLE markup_rules (
    id              BIGSERIAL PRIMARY KEY,
    rule_name       VARCHAR(128) NOT NULL,
    priority        SMALLINT NOT NULL DEFAULT 0,     -- 数字越大优先级越高

    -- 匹配条件 (可为空,表示不限制)
    agent_code      VARCHAR(32),                     -- 限定代理商
    channel_code    VARCHAR(32),                     -- 限定渠道
    supplier_code   VARCHAR(32),                     -- 限定供应商
    hotel_id        BIGINT,                          -- 限定酒店
    country_code    VARCHAR(3),                      -- 限定国家
    city_code       VARCHAR(8),                      -- 限定城市
    date_from       DATE,                            -- 有效期起
    date_to         DATE,                            -- 有效期止
    meal_plan       VARCHAR(16),                     -- 限定餐型
    rate_plan       VARCHAR(32),                     -- 限定价格计划

    -- 加价规则
    markup_type     VARCHAR(16) NOT NULL,            -- percentage/fixed/mixed
    markup_value    DECIMAL(8, 4) NOT NULL,          -- 百分比(如 0.15=15%) 或固定金额
    min_markup      DECIMAL(8, 2) DEFAULT 0,        -- 最低加价
    max_markup      DECIMAL(8, 2),                   -- 最高加价

    -- 含税/不含税处理
    tax_inclusive   BOOLEAN DEFAULT false,

    status          VARCHAR(20) DEFAULT 'active',
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_markup_rules_priority ON markup_rules (priority DESC);

-- 价格合规规则表 (最低售价限制)
CREATE TABLE price_compliance_rules (
    id              BIGSERIAL PRIMARY KEY,
    supplier_code   VARCHAR(32) NOT NULL,
    hotel_id        BIGINT,
    room_type_code  VARCHAR(32),
    rate_plan       VARCHAR(32),
    min_gross_rate  DECIMAL(12, 2),                 -- 最低售价要求
    map_policy      VARCHAR(32) DEFAULT 'soft',      -- soft(警告)/hard(拦截)
    date_from       DATE,
    date_to         DATE,
    status          VARCHAR(20) DEFAULT 'active',
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 特殊日期价格调整表
CREATE TABLE special_dates (
    id              BIGSERIAL PRIMARY KEY,
    date            DATE NOT NULL,
    date_type       VARCHAR(32) NOT NULL,            -- holiday/event/low_season
    name            VARCHAR(128),
    country_code    VARCHAR(3),
    city_code       VARCHAR(8),
    markup_adjust   DECIMAL(8, 4) DEFAULT 0,        -- 额外加价(正数=加价)
    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(date, country_code, city_code)
);

6.7 结算管理

-- 结算单表
CREATE TABLE settlement_bills (
    id                  BIGSERIAL PRIMARY KEY,
    bill_no             VARCHAR(32) NOT NULL UNIQUE,  -- SET-YYYYMMDD-XXXXX
    bill_type           VARCHAR(32) NOT NULL,          -- payable(应付)/receivable(应收)
    party_code          VARCHAR(32) NOT NULL,          -- 供应商/代理商编码
    party_name          VARCHAR(255) NOT NULL,

    period_start        DATE NOT NULL,
    period_end          DATE NOT NULL,

    order_count         INT DEFAULT 0,
    total_amount        DECIMAL(14, 2) DEFAULT 0,
    commission          DECIMAL(14, 2) DEFAULT 0,
    net_amount          DECIMAL(14, 2) DEFAULT 0,     -- 实际结算金额
    currency            VARCHAR(3) DEFAULT 'CNY',

    status              VARCHAR(20) DEFAULT 'draft',  -- draft/pending_approval/approved/paid/cancelled
    approved_by         VARCHAR(64),
    approved_at         TIMESTAMPTZ,
    paid_at             TIMESTAMPTZ,

    notes               TEXT,
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW()
);

-- 结算明细表(每笔订单的结算记录)
CREATE TABLE settlement_items (
    id                  BIGSERIAL PRIMARY KEY,
    bill_id             BIGINT REFERENCES settlement_bills(id),
    order_id            BIGINT NOT NULL REFERENCES orders(id),
    order_no            VARCHAR(32) NOT NULL,
    hotel_name          VARCHAR(255),
    check_in            DATE,
    check_out           DATE,
    nights              SMALLINT,

    gross_amount        DECIMAL(12, 2) NOT NULL,     -- 应收金额
    net_amount          DECIMAL(12, 2) NOT NULL,     -- 应付金额
    commission          DECIMAL(12, 2),              -- 佣金
    currency            VARCHAR(3) DEFAULT 'CNY',

    reconciliation_status VARCHAR(20) DEFAULT 'matched', -- matched/unmatched/disputed
    dispute_reason      TEXT,

    created_at          TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_settlement_items_bill ON settlement_items (bill_id);
CREATE INDEX idx_settlement_items_order ON settlement_items (order_id);

-- 发票表
CREATE TABLE invoices (
    id              BIGSERIAL PRIMARY KEY,
    invoice_no      VARCHAR(32) NOT NULL UNIQUE,     -- INV-YYYYMMDD-XXXXX
    bill_id         BIGINT REFERENCES settlement_bills(id),
    party_code      VARCHAR(32) NOT NULL,
    party_name      VARCHAR(255) NOT NULL,

    invoice_type    VARCHAR(32) NOT NULL,            -- sales(销售发票)/purchase(采购发票)
    amount          DECIMAL(14, 2) NOT NULL,
    tax_amount      DECIMAL(14, 2) DEFAULT 0,
    total_amount    DECIMAL(14, 2) NOT NULL,
    currency        VARCHAR(3) DEFAULT 'CNY',

    -- 发票信息
    invoice_title   VARCHAR(255),                   -- 发票抬头
    tax_number      VARCHAR(32),                    -- 税号
    status          VARCHAR(20) DEFAULT 'pending',  -- pending/issued/cancelled

    file_url        VARCHAR(512),                   -- 发票文件URL

    issued_at       TIMESTAMPTZ,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 付款记录表
CREATE TABLE payments (
    id              BIGSERIAL PRIMARY KEY,
    payment_no      VARCHAR(32) NOT NULL UNIQUE,     -- PAY-YYYYMMDD-XXXXX
    bill_id         BIGINT REFERENCES settlement_bills(id),
    party_code      VARCHAR(32) NOT NULL,

    amount          DECIMAL(14, 2) NOT NULL,
    currency        VARCHAR(3) DEFAULT 'CNY',
    payment_method  VARCHAR(32),                     -- bank_transfer/credit/alipay
    payment_ref     VARCHAR(128),                    -- 付款参考号/银行流水号

    status          VARCHAR(20) DEFAULT 'pending',  -- pending/processing/completed/failed
    paid_at         TIMESTAMPTZ,
    confirmed_by    VARCHAR(64),

    notes           TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

6.8 库存管理

6.8 基础表

-- 实时库存表(热数据,频繁更新)
CREATE TABLE inventory_snapshots (
    id                  BIGSERIAL PRIMARY KEY,
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_hotel_id   VARCHAR(64) NOT NULL,
    room_type_code      VARCHAR(32) NOT NULL,

    stay_date           DATE NOT NULL,             -- 入住日期

    total_rooms         INT DEFAULT 0,             -- 总房量
    sold_rooms          INT DEFAULT 0,             -- 已售
    blocked_rooms       INT DEFAULT 0,             -- 关停房
    available_rooms     INT,                       -- 可用房量(NULL=有价即有房不限量;有值=真实库存数售完为止)

    last_synced_at      TIMESTAMPTZ,
    sync_source         VARCHAR(32) DEFAULT 'pull', -- pull/push/manual

    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(supplier_code, supplier_hotel_id, room_type_code, stay_date)
);

CREATE INDEX idx_inventory_date ON inventory_snapshots (supplier_code, stay_date);

-- 库存预占记录表
CREATE TABLE inventory_holds (
    id                  BIGSERIAL PRIMARY KEY,
    order_id            BIGINT NOT NULL REFERENCES orders(id),
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_hotel_id   VARCHAR(64) NOT NULL,
    room_type_code      VARCHAR(32) NOT NULL,

    stay_date           DATE NOT NULL,
    room_count          SMALLINT NOT NULL DEFAULT 1,

    status              VARCHAR(20) DEFAULT 'active', -- active/confirmed/released/expired
    expires_at          TIMESTAMPTZ NOT NULL,          -- 预占过期时间
    released_at         TIMESTAMPTZ,

    created_at          TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_inventory_holds_order ON inventory_holds (order_id);
CREATE INDEX idx_inventory_holds_status ON inventory_holds (status, expires_at);
CREATE INDEX idx_inventory_holds_expire ON inventory_holds (status, expires_at)
    WHERE status = 'active';

-- 关停房日期表
CREATE TABLE stop_sells (
    id                  BIGSERIAL PRIMARY KEY,
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_hotel_id   VARCHAR(64) NOT NULL,
    room_type_code      VARCHAR(32),                -- 空=整个酒店
    start_date          DATE NOT NULL,
    end_date            DATE NOT NULL,
    reason              VARCHAR(128),
    source              VARCHAR(32) DEFAULT 'supplier', -- supplier/manual
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    created_by          VARCHAR(64)
);

-- 房量配额分配表
CREATE TABLE inventory_allocations (
    id                  BIGSERIAL PRIMARY KEY,
    supplier_code       VARCHAR(32) NOT NULL,
    supplier_hotel_id   VARCHAR(64) NOT NULL,
    room_type_code      VARCHAR(32) NOT NULL,
    stay_date           DATE NOT NULL,

    agent_code          VARCHAR(32),                 -- 分配给特定代理商
    channel_code        VARCHAR(32),                 -- 或分配给渠道

    allocated_rooms     INT NOT NULL DEFAULT 0,      -- 分配房量
    used_rooms          INT NOT NULL DEFAULT 0,      -- 已用房量

    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(supplier_code, supplier_hotel_id, room_type_code, stay_date, 
           COALESCE(agent_code, ''), COALESCE(channel_code, ''))
);

6.8.1 可售日期范围

CREATE TABLE sell_date_range (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT NOT NULL,
    room_type_id    BIGINT,                         -- NULL = 该酒店所有房型
    channel_id      BIGINT REFERENCES channels(id),  -- NULL = 全局默认
    agent_id        BIGINT REFERENCES agents(id),    -- NULL = 不限代理商(配合 channel_id 使用)
    sell_from       DATE NOT NULL,                   -- 可售开始日期
    sell_to         DATE NOT NULL,                   -- 可售结束日期
    overwrite_global BOOLEAN DEFAULT FALSE,          -- true = 覆盖全局设置
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_sdr_supplier_hotel ON sell_date_range (supplier_id, hotel_id, room_type_id);
CREATE INDEX idx_sdr_channel ON sell_date_range (channel_id, sell_from, sell_to);

6.8.2 预定窗口

CREATE TABLE booking_window (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT NOT NULL,
    room_type_id    BIGINT,                         -- NULL = 该酒店所有房型
    channel_id      BIGINT REFERENCES channels(id),  -- NULL = 全局默认
    agent_id        BIGINT REFERENCES agents(id),    -- NULL = 不限代理商
    min_advance     SMALLINT NOT NULL DEFAULT 1,     -- 最少提前天数(如 1 = 当天不能订)
    max_advance     SMALLINT NOT NULL DEFAULT 365,   -- 最远可订天数
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_bw_supplier_hotel ON booking_window (supplier_id, hotel_id, room_type_id);
CREATE INDEX idx_bw_channel ON booking_window (channel_id);

6.8.3 连住规则

CREATE TABLE los_rule (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT NOT NULL,
    room_type_id    BIGINT,                         -- NULL = 该酒店所有房型
    channel_id      BIGINT REFERENCES channels(id),  -- NULL = 全局默认
    agent_id        BIGINT REFERENCES agents(id),    -- NULL = 不限代理商
    min_los         SMALLINT NOT NULL DEFAULT 1,     -- 最少入住天数
    max_los         SMALLINT,                        -- NULL = 不限最多天数
    discount_type   VARCHAR(16),                     -- percentage/fixed/none
    discount_value  DECIMAL(8, 2) DEFAULT 0,        -- 折扣值(百分比或固定金额)
    effective_from  DATE NOT NULL DEFAULT CURRENT_DATE,
    effective_to    DATE,                            -- NULL = 长期有效
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_los_supplier_hotel ON los_rule (supplier_id, hotel_id, room_type_id);
CREATE INDEX idx_los_channel ON los_rule (channel_id, effective_from, effective_to);

6.8.4 房量分配

CREATE TABLE allocation (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT NOT NULL,
    room_type_id    BIGINT NOT NULL,
    date            DATE NOT NULL,
    channel_id      BIGINT,                         -- NULL = 共用池(overbooking)
    agent_id        BIGINT REFERENCES agents(id),    -- NULL = 不限代理商(配合 channel_id)
    allocated_qty   INT NOT NULL DEFAULT 0,         -- 分配房量
    sold_qty        INT NOT NULL DEFAULT 0,         -- 已售房量
    released_at     TIMESTAMPTZ,                     -- 释放时间(售罄时间)
    status          VARCHAR(16) DEFAULT 'active',   -- active/exhausted/released
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW(),

    UNIQUE(supplier_id, hotel_id, room_type_id, date, COALESCE(channel_id, 0))
);

CREATE INDEX idx_alloc_date ON allocation (supplier_id, hotel_id, room_type_id, date);
CREATE INDEX idx_alloc_channel ON allocation (channel_id, date, status);

6.8.5 增强版关停房

CREATE TABLE stop_sell_v2 (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT NOT NULL REFERENCES suppliers(id),
    hotel_id        BIGINT NOT NULL,
    room_type_id    BIGINT,                         -- NULL = 整个酒店关停
    channel_id      BIGINT REFERENCES channels(id),  -- NULL = 所有渠道关停
    stop_from       DATE NOT NULL,                   -- 关停开始日期
    stop_to         DATE NOT NULL,                   -- 关停结束日期
    reason          VARCHAR(128) NOT NULL,           -- maintenance/full/event/seasonal/other
    reason_detail   TEXT,                            -- 详细说明
    status          VARCHAR(16) DEFAULT 'active',   -- active/cancelled/expired
    created_by      VARCHAR(64) NOT NULL,            -- 创建人
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_ss_v2_hotel_date ON stop_sell_v2 (supplier_id, hotel_id, room_type_id, stop_from, stop_to);
CREATE INDEX idx_ss_v2_channel ON stop_sell_v2 (channel_id, status, stop_from, stop_to);
CREATE INDEX idx_ss_v2_status ON stop_sell_v2 (status, stop_from, stop_to);

6.9 风控体系

-- 风控规则表
CREATE TABLE risk_rules (
    id              SERIAL PRIMARY KEY,
    rule_name       VARCHAR(128) NOT NULL,
    rule_type       VARCHAR(32) NOT NULL,     -- price_anomaly/traffic/credit/blacklist
    condition       JSONB NOT NULL,           -- 规则条件配置
    action          VARCHAR(32) NOT NULL,     -- block/alert/log/verify
    severity        VARCHAR(16) DEFAULT 'medium', -- low/medium/high/critical
    enabled         BOOLEAN DEFAULT true,
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 风控事件日志表
CREATE TABLE risk_events (
    id              BIGSERIAL PRIMARY KEY,
    event_type      VARCHAR(32) NOT NULL,
    rule_id         INT REFERENCES risk_rules(id),

    agent_code      VARCHAR(32),
    ip_address      VARCHAR(45),
    request_path    VARCHAR(256),

    detail          JSONB,                   -- 详细信息
    action_taken    VARCHAR(32),              -- block/alert/passed

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_risk_events_type ON risk_events (event_type, created_at DESC);
CREATE INDEX idx_risk_events_agent ON risk_events (agent_code);

-- IP 黑名单表
CREATE TABLE ip_blacklist (
    id              SERIAL PRIMARY KEY,
    ip_address      VARCHAR(45) NOT NULL UNIQUE,
    reason          VARCHAR(255),
    blocked_by      VARCHAR(64),
    expires_at      TIMESTAMPTZ,              -- 空=永久
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 风险告警记录表
CREATE TABLE risk_alerts (
    id              BIGSERIAL PRIMARY KEY,
    alert_type      VARCHAR(64) NOT NULL,
    severity        VARCHAR(16) NOT NULL,
    title           VARCHAR(255) NOT NULL,
    detail          JSONB,
    status          VARCHAR(20) DEFAULT 'open', -- open/acknowledged/resolved
    acknowledged_by VARCHAR(64),
    resolved_at     TIMESTAMPTZ,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_risk_alerts_status ON risk_alerts (status, created_at DESC);

-- 信用额度变更记录
CREATE TABLE credit_log (
    id              BIGSERIAL PRIMARY KEY,
    agent_code      VARCHAR(32) NOT NULL,
    change_type     VARCHAR(32) NOT NULL,     -- order_hold/order_release/settlement/adjust
    amount          DECIMAL(12, 2) NOT NULL,  -- 正=增加使用,负=释放
    balance_before  DECIMAL(12, 2),
    balance_after   DECIMAL(12, 2),
    reference_no    VARCHAR(64),              -- 关联订单号或结算单号
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_credit_log_agent ON credit_log (agent_code, created_at DESC);

6.10 数据智能

-- 以下表主要在 ClickHouse 中创建,PG 中保留简化版本

-- ClickHouse: 每日聚合统计表
-- CREATE TABLE daily_stats (date Date, metric String, dimension String, value Int64, amount Float64) 
-- ENGINE = SummingMergeTree() ORDER BY (date, metric, dimension)

-- 供应商评分表 (PG)
CREATE TABLE supplier_scores (
    id              BIGSERIAL PRIMARY KEY,
    supplier_code   VARCHAR(32) NOT NULL,
    period_date     DATE NOT NULL,

    availability_score  DECIMAL(5, 2),       -- 可用率评分
    price_score         DECIMAL(5, 2),       -- 价格竞争力评分
    response_score      DECIMAL(5, 2),       -- 响应速度评分
    quality_score       DECIMAL(5, 2),       -- 综合质量评分
    booking_rate        DECIMAL(5, 2),       -- 预订成功率
    cancellation_rate   DECIMAL(5, 2),       -- 取消率

    total_bookings      INT DEFAULT 0,
    total_revenue       DECIMAL(14, 2) DEFAULT 0,

    rank                INT,                     -- 排名

    calculated_at       TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(supplier_code, period_date)
);

-- 代理商评分表
CREATE TABLE agent_scores (
    id              BIGSERIAL PRIMARY KEY,
    agent_code      VARCHAR(32) NOT NULL,
    period_date     DATE NOT NULL,

    booking_score       DECIMAL(5, 2),       -- 预订量评分
    revenue_score       DECIMAL(5, 2),       -- 营收贡献评分
    payment_score       DECIMAL(5, 2),       -- 付款及时性评分
    cancellation_score  DECIMAL(5, 2),       -- 取消率评分(低好)
    overall_score       DECIMAL(5, 2),       -- 综合评分

    total_bookings      INT DEFAULT 0,
    total_revenue       DECIMAL(14, 2) DEFAULT 0,
    avg_booking_value   DECIMAL(10, 2),

    calculated_at       TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(agent_code, period_date)
);

-- 需求预测表
CREATE TABLE demand_forecasts (
    id              BIGSERIAL PRIMARY KEY,
    hotel_id        BIGINT NOT NULL,
    stay_date       DATE NOT NULL,

    predicted_demand INT,                     -- 预测需求热度 1-100
    confidence      DECIMAL(5, 2),           -- 预测置信度
    model_version   VARCHAR(16),

    actual_demand   INT,                     -- 实际值(事后回填)

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(hotel_id, stay_date)
);

-- 报表配置表
CREATE TABLE report_configs (
    id              SERIAL PRIMARY KEY,
    report_name     VARCHAR(128) NOT NULL,
    report_type     VARCHAR(32) NOT NULL,     -- daily/weekly/monthly/custom
    schedule_cron   VARCHAR(64),             -- 定时表达式
    recipients      JSONB,                   -- 接收人列表
    config          JSONB,                   -- 报表参数
    enabled         BOOLEAN DEFAULT true,
    last_run_at     TIMESTAMPTZ,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

6.11 API 网关

-- API 密钥表 (关联 agents 表)
CREATE TABLE api_keys (
    id              BIGSERIAL PRIMARY KEY,
    agent_code      VARCHAR(32) NOT NULL REFERENCES agents(agent_code),
    key_id          VARCHAR(32) NOT NULL UNIQUE,     -- 可公开的 Key ID
    key_secret_hash VARCHAR(128) NOT NULL,            -- 密钥哈希(不可逆)

    rate_limit_rpm  INT DEFAULT 60,                   -- 每分钟请求限制
    rate_limit_rpd  INT DEFAULT 10000,                -- 每天请求限制

    allowed_apis    JSONB DEFAULT '["*"]',             -- 允许访问的 API 列表
    ip_whitelist    JSONB,                            -- IP 白名单

    status          VARCHAR(20) DEFAULT 'active',     -- active/suspended/revoked
    last_used_at    TIMESTAMPTZ,
    expires_at      TIMESTAMPTZ,

    created_at      TIMESTAMPTZ DEFAULT NOW(),
    revoked_at      TIMESTAMPTZ
);

-- 请求日志表 (ClickHouse 或 PG)
CREATE TABLE request_logs (
    id              BIGSERIAL PRIMARY KEY,
    trace_id        VARCHAR(64) NOT NULL,

    request_method  VARCHAR(16) NOT NULL,
    request_path    VARCHAR(512) NOT NULL,
    query_params    TEXT,
    request_body    TEXT,                             -- 脱敏后
    client_ip       VARCHAR(45),
    user_agent      VARCHAR(512),

    agent_code      VARCHAR(32),
    api_key_id      VARCHAR(32),

    response_status SMALLINT NOT NULL,
    response_ms     INT NOT NULL,

    error_message   TEXT,

    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- 限流配置表
CREATE TABLE rate_limits (
    id              SERIAL PRIMARY KEY,
    limit_type      VARCHAR(32) NOT NULL,     -- global/ip/agent/api
    limit_key       VARCHAR(64) NOT NULL,     -- 具体限流对象
    requests_per_minute INT NOT NULL,
    requests_per_day INT,
    burst_size      INT DEFAULT 10,           -- 突发容量
    enabled         BOOLEAN DEFAULT true,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

6.12 管理后台

管理后台为前端模块,无独立数据表,调用后端各模块 API 进行操作。 请参见 6.5-6.11 各模块数据表


11.x 补充能力模块

11.1 动态定价规则

CREATE TABLE dynamic_pricing_rule (
    id                SERIAL PRIMARY KEY,
    supplier_id       BIGINT,
    hotel_id          BIGINT,
    room_type_id      BIGINT,
    channel_id        BIGINT,
    rule_type         VARCHAR(32) NOT NULL,      -- holiday/advance/last_minute/custom
    trigger_condition JSONB NOT NULL,             -- 触发条件,如 {"advance_days_gte": 30}
    adjustment_type   VARCHAR(16) NOT NULL,       -- percentage / fixed
    adjustment_value  DECIMAL(10, 2) NOT NULL,    -- 百分比值或固定金额
    effective_from    DATE NOT NULL,
    effective_to      DATE NOT NULL,
    priority          SMALLINT DEFAULT 0,
    status            VARCHAR(16) DEFAULT 'active',
    created_at        TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_dpr_hotel ON dynamic_pricing_rule (hotel_id, room_type_id, status, effective_from);

11.2 价格一致性监控

CREATE TABLE rate_parity_alert (
    id             SERIAL PRIMARY KEY,
    hotel_id       BIGINT NOT NULL,
    room_type_id   BIGINT,
    check_in_date  DATE NOT NULL,
    channel_a      VARCHAR(64) NOT NULL,
    channel_b      VARCHAR(64) NOT NULL,
    price_a        DECIMAL(10, 2) NOT NULL,
    price_b        DECIMAL(10, 2) NOT NULL,
    deviation_pct  DECIMAL(5, 2) NOT NULL,       -- 偏差百分比
    alert_level    VARCHAR(16) DEFAULT 'warning', -- warning / critical
    status         VARCHAR(16) DEFAULT 'open',   -- open / acknowledged / resolved
    created_at     TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_rpa_hotel_date ON rate_parity_alert (hotel_id, check_in_date, status);

11.3 促销活动管理

CREATE TABLE promotion (
    id              SERIAL PRIMARY KEY,
    name            VARCHAR(128) NOT NULL,
    type            VARCHAR(32) NOT NULL,       -- flash / early_bird / package / custom
    supplier_id     BIGINT,
    hotel_ids       INT[] DEFAULT '{}',
    channel_ids     INT[] DEFAULT '{}',
    discount_type   VARCHAR(16) NOT NULL,       -- percentage / fixed / free_night
    discount_value  DECIMAL(10, 2) NOT NULL,
    start_time      TIMESTAMPTZ NOT NULL,
    end_time        TIMESTAMPTZ NOT NULL,
    quota           INT DEFAULT 0,              -- 0=不限量
    used_quota      INT DEFAULT 0,
    conditions      JSONB,                       -- 如 {"min_stay": 3, "min_amount": 1000}
    status          VARCHAR(16) DEFAULT 'draft',
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_promotion_time ON promotion (start_time, end_time, status);

11.4 汇率自动换算

CREATE TABLE exchange_rate (
    id            SERIAL PRIMARY KEY,
    currency_from VARCHAR(3) NOT NULL,          -- ISO 4217
    currency_to   VARCHAR(3) NOT NULL,
    rate          DECIMAL(18, 8) NOT NULL,       -- 1 unit of currency_from = ? currency_to
    effective_at  TIMESTAMPTZ NOT NULL,
    source        VARCHAR(32) NOT NULL,          -- ecb / open_exchange_rates / manual
    created_at    TIMESTAMPTZ DEFAULT NOW()
);

CREATE UNIQUE INDEX idx_er_pair_time ON exchange_rate (currency_from, currency_to, effective_at DESC);

11.5 拆单/并单

-- orders 表新增字段
ALTER TABLE orders ADD COLUMN parent_order_id BIGINT REFERENCES orders(id);
ALTER TABLE orders ADD COLUMN split_sequence  SMALLINT DEFAULT 0;

CREATE TABLE consolidation (
    id            SERIAL PRIMARY KEY,
    agent_id      BIGINT NOT NULL,
    period_start  DATE NOT NULL,
    period_end    DATE NOT NULL,
    order_ids     BIGINT[] NOT NULL,
    total_amount  DECIMAL(12, 2) NOT NULL,
    currency      VARCHAR(3) DEFAULT 'CNY',
    status        VARCHAR(16) DEFAULT 'pending',  -- pending / confirmed / settled
    created_at    TIMESTAMPTZ DEFAULT NOW()
);

11.7 担保/预付

CREATE TABLE payment_rule (
    id               SERIAL PRIMARY KEY,
    supplier_id      BIGINT NOT NULL,
    channel_id       BIGINT,
    hotel_id         BIGINT,
    payment_type     VARCHAR(16) NOT NULL,      -- guarantee / prepay / postpay
    guarantee_amount DECIMAL(10, 2),             -- 担保金额(NULL=全额担保)
    prepay_days      INT,                        -- 提前 N 天预付(NULL=立即预付)
    payment_methods  JSONB,                      -- 支持的支付方式,如 ["credit_card", "bank_transfer"]
    effective_from   DATE NOT NULL,
    effective_to     DATE NOT NULL,
    created_at       TIMESTAMPTZ DEFAULT NOW()
);

11.8 订单超时自动取消

-- orders 表新增字段
ALTER TABLE orders ADD COLUMN confirmed_at TIMESTAMPTZ;
ALTER TABLE orders ADD COLUMN paid_at      TIMESTAMPTZ;

CREATE TABLE order_timeout_config (
    id                  SERIAL PRIMARY KEY,
    channel_id          BIGINT,
    supplier_id         BIGINT,
    confirm_timeout_min INT NOT NULL DEFAULT 30,   -- 确认超时(分钟)
    payment_timeout_min INT NOT NULL DEFAULT 60,   -- 支付超时(分钟)
    created_at          TIMESTAMPTZ DEFAULT NOW()
);

11.9 多语言内容管理

CREATE TABLE hotel_content_i18n (
    hotel_id   BIGINT NOT NULL REFERENCES hotels(id),
    language   VARCHAR(5) NOT NULL,           -- zh-CN / en / ja
    name       VARCHAR(256),
    description TEXT,
    address    VARCHAR(512),
    amenities  JSONB,
    PRIMARY KEY (hotel_id, language)
);

CREATE TABLE room_type_content_i18n (
    room_type_id BIGINT NOT NULL REFERENCES room_types(id),
    language     VARCHAR(5) NOT NULL,
    name         VARCHAR(256),
    description  TEXT,
    bed_type     VARCHAR(64),
    PRIMARY KEY (room_type_id, language)
);

11.10 图片管理

CREATE TABLE media (
    id           SERIAL PRIMARY KEY,
    entity_type  VARCHAR(16) NOT NULL,         -- hotel / room_type / facility
    entity_id    BIGINT NOT NULL,
    url          VARCHAR(512) NOT NULL,         -- 原图 CDN 地址
    thumbnail_url VARCHAR(512),                 -- 缩略图 CDN 地址
    category     VARCHAR(32),                   -- exterior / room / amenity / facility
    sort_order   SMALLINT DEFAULT 0,
    uploaded_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_media_entity ON media (entity_type, entity_id, sort_order);

11.11 政策管理

CREATE TABLE hotel_policy (
    id              SERIAL PRIMARY KEY,
    hotel_id        BIGINT NOT NULL REFERENCES hotels(id),
    policy_type     VARCHAR(32) NOT NULL,       -- check_in / children / pet / payment / general
    content         JSONB NOT NULL,             -- 政策内容,如 {"check_in_from": "14:00", "check_out_by": "12:00"}
    language        VARCHAR(5) DEFAULT 'zh-CN',
    effective_from  DATE NOT NULL,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_hp_hotel_type ON hotel_policy (hotel_id, policy_type, language);

11.13 对账差异自动处理

CREATE TABLE reconciliation (
    id             SERIAL PRIMARY KEY,
    period         VARCHAR(7) NOT NULL,        -- 对账周期,如 2024-01
    agent_id       BIGINT NOT NULL,
    supplier_id    BIGINT NOT NULL,
    our_amount     DECIMAL(12, 2) NOT NULL,    -- 我方金额
    their_amount   DECIMAL(12, 2) NOT NULL,    -- 对方金额
    diff_amount    DECIMAL(12, 2) NOT NULL,    -- 差异金额
    status         VARCHAR(16) DEFAULT 'pending', -- pending / auto_resolved / resolved / disputed
    resolution     JSONB,                       -- 解决方案,如 {"type": "adjustment", "note": "..."}
    resolved_by    VARCHAR(64),
    resolved_at    TIMESTAMPTZ,
    created_at     TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_recon_period ON reconciliation (period, status);

11.14 供应商评级体系

CREATE TABLE supplier_rating (
    id                      SERIAL PRIMARY KEY,
    supplier_id             BIGINT NOT NULL REFERENCES suppliers(id),
    period                  VARCHAR(7) NOT NULL,       -- 评分周期,如 2024-01
    score_overall           DECIMAL(4, 2) NOT NULL,    -- 综合评分 0-100
    score_response_time     DECIMAL(4, 2),
    score_price             DECIMAL(4, 2),
    score_inventory_accuracy DECIMAL(4, 2),
    score_cancel_rate       DECIMAL(4, 2),
    calc_details            JSONB,                     -- 各指标原始值和计算过程
    created_at              TIMESTAMPTZ DEFAULT NOW()
);

CREATE UNIQUE INDEX idx_sr_supplier_period ON supplier_rating (supplier_id, period);

11.15 代理商分层权益

CREATE TABLE agent_tier (
    id                  SERIAL PRIMARY KEY,
    tier_name           VARCHAR(32) NOT NULL UNIQUE, -- bronze / silver / gold / platinum
    min_monthly_volume  INT NOT NULL,                -- 最低月交易单数
    price_discount_pct  DECIMAL(4, 2) DEFAULT 0,     -- 价格折扣百分比
    inventory_priority  SMALLINT DEFAULT 0,          -- 库存优先级,越高越优先
    settlement_days     INT DEFAULT 30,              -- 结算天数
    support_level       VARCHAR(16) DEFAULT 'standard',
    benefits            JSONB,                       -- 其他权益描述
    created_at          TIMESTAMPTZ DEFAULT NOW()
);

-- agents 表新增字段
ALTER TABLE agents ADD COLUMN tier_id BIGINT REFERENCES agent_tier(id);
ALTER TABLE agents ADD COLUMN tier_evaluated_at TIMESTAMPTZ;

11.16 消息通知中心

CREATE TABLE notification (
    id           SERIAL PRIMARY KEY,
    party_type   VARCHAR(16) NOT NULL,          -- agent / supplier / admin
    party_id     BIGINT NOT NULL,
    type         VARCHAR(32) NOT NULL,          -- order_status / inventory_alert / price_change / ...
    title        VARCHAR(256) NOT NULL,
    content      JSONB NOT NULL,                 -- 通知内容,结构因 type 而异
    channel      VARCHAR(16) NOT NULL,           -- email / webhook / in_app
    status       VARCHAR(16) DEFAULT 'pending',  -- pending / sent / failed
    sent_at      TIMESTAMPTZ,
    created_at   TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_notif_party ON notification (party_type, party_id, status, created_at DESC);

11.17 审计日志

CREATE TABLE audit_log (
    id           BIGSERIAL PRIMARY KEY,
    operator_type VARCHAR(16) NOT NULL,         -- admin / agent / supplier / system
    operator_id  BIGINT,
    action       VARCHAR(32) NOT NULL,          -- create / update / delete / login / ...
    entity_type  VARCHAR(32) NOT NULL,          -- hotel / order / supplier / ...
    entity_id    BIGINT,
    detail       JSONB,                          -- 变更详情,如 {"before": {...}, "after": {...}}
    ip           VARCHAR(45),
    user_agent   VARCHAR(256),
    created_at   TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_audit_entity ON audit_log (entity_type, entity_id, created_at DESC);
CREATE INDEX idx_audit_operator ON audit_log (operator_type, operator_id, created_at DESC);

11.18 多租户隔离

CREATE TABLE tenants (
    id          SERIAL PRIMARY KEY,
    name        VARCHAR(128) NOT NULL,
    domain      VARCHAR(128) UNIQUE,            -- 租户域名,如 hotel.example.com
    config      JSONB DEFAULT '{}',             -- 租户自定义配置
    status      VARCHAR(16) DEFAULT 'active',
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

-- 所有业务表新增租户字段(示例)
ALTER TABLE hotels ADD COLUMN tenant_id BIGINT REFERENCES tenants(id);
ALTER TABLE agents ADD COLUMN tenant_id BIGINT REFERENCES tenants(id);
ALTER TABLE suppliers ADD COLUMN tenant_id BIGINT REFERENCES tenants(id);

12.x AI Agent 智能运营层

12.1 决策支持引擎(Insight Engine)

CREATE TABLE insight_rules (
    id              BIGSERIAL PRIMARY KEY,
    name            VARCHAR(128) NOT NULL,
    description     TEXT,
    metric_source   VARCHAR(64) NOT NULL,      -- 指标来源(如 supplier_price_competitiveness)
    condition       JSONB NOT NULL,             -- 触发条件(如 {"change_pct": -10, "window_days": 3})
    suggestion      TEXT NOT NULL,              -- 建议方案模板
    severity        VARCHAR(16) DEFAULT 'info',  -- info/warning/critical
    action_type     VARCHAR(32),                -- recommend/auto_execute/notify_only
    enabled         BOOLEAN DEFAULT true,
    created_at      TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE insight_events (
    id              BIGSERIAL PRIMARY KEY,
    rule_id         BIGINT REFERENCES insight_rules(id),
    triggered_at    TIMESTAMPTZ NOT NULL,
    metric_data     JSONB NOT NULL,             -- 触发时的指标快照
    suggestion_text TEXT NOT NULL,
    channel         VARCHAR(32) DEFAULT 'feishu',
    status          VARCHAR(16) DEFAULT 'pending',  -- pending/accepted/ignored/executed
    user_feedback   VARCHAR(16),                -- 用户的反馈
    processed_at    TIMESTAMPTZ
);

12.2 自主执行权限管理

CREATE TABLE permission_policy (
    id              BIGSERIAL PRIMARY KEY,
    action_category VARCHAR(64) NOT NULL,        -- restart_service/cleanup_logs/supplier_circuit_break/...
    action_name     VARCHAR(128) NOT NULL,
    level           VARCHAR(8) NOT NULL,          -- L1/L2/L3
    description     TEXT,
    conditions      JSONB,                        -- 额外条件(如 L2 级操作在非工作时间升级为 L3)
    created_at      TIMESTAMPTZ DEFAULT now(),
    updated_at      TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE execution_log (
    id              BIGSERIAL PRIMARY KEY,
    action_category VARCHAR(64) NOT NULL,
    action_name     VARCHAR(128) NOT NULL,
    level           VARCHAR(8) NOT NULL,
    status          VARCHAR(16) NOT NULL,         -- approved/executed/rejected/timeout
    approval_status VARCHAR(16),                  -- null(L1)/auto(L2)/pending/manual(L3)
    result          JSONB,
    executed_at     TIMESTAMPTZ,
    approved_by     VARCHAR(64),
    created_at      TIMESTAMPTZ DEFAULT now()
);

12.3 供应商自动接入流水线

CREATE TABLE supplier_onboarding (
    id              BIGSERIAL PRIMARY KEY,
    supplier_id     BIGINT REFERENCES suppliers(id),
    status          VARCHAR(32) DEFAULT 'pending',
    -- pending/adapter_dev/mock_test/integration_test/staging/production/failed
    api_doc_url     VARCHAR(512),
    test_credentials JSONB,
    adapter_code    TEXT,
    test_results    JSONB,
    staging_config  JSONB,
    production_config JSONB,
    health_score    DECIMAL(5,2),
    started_at      TIMESTAMPTZ,
    completed_at    TIMESTAMPTZ,
    notes           TEXT
);

CREATE TABLE supplier_test_suite (
    id              BIGSERIAL PRIMARY KEY,
    onboarding_id   BIGINT REFERENCES supplier_onboarding(id),
    test_type       VARCHAR(32) NOT NULL,  -- mock/integration/regression
    test_name       VARCHAR(128) NOT NULL,
    status          VARCHAR(16),           -- passed/failed/skipped
    duration_ms     INT,
    error_detail    TEXT,
    executed_at     TIMESTAMPTZ DEFAULT now()
);

12.4 工单系统(Ticket System)

CREATE TABLE tickets (
    id              BIGSERIAL PRIMARY KEY,
    ticket_no       VARCHAR(32) NOT NULL UNIQUE,  -- TK-20260415-001
    title           VARCHAR(256) NOT NULL,
    description     TEXT NOT NULL,
    source          VARCHAR(32) NOT NULL,  -- agent/manual/monitor
    priority        VARCHAR(8) NOT NULL,    -- P0/P1/P2/P3
    status          VARCHAR(32) DEFAULT 'open',
    -- open/diagnosing/pending_approval/resolved/closed
    related_type    VARCHAR(32),            -- order/hotel/supplier/agent
    related_id      VARCHAR(64),
    diagnosis       JSONB,                   -- AI 自动诊断结果
    suggestion      TEXT,                    -- AI 建议
    resolution      TEXT,
    assigned_to     VARCHAR(64),
    created_by      VARCHAR(64),
    created_at      TIMESTAMPTZ DEFAULT now(),
    resolved_at     TIMESTAMPTZ,
    closed_at       TIMESTAMPTZ
);

CREATE TABLE ticket_timeline (
    id              BIGSERIAL PRIMARY KEY,
    ticket_id       BIGINT REFERENCES tickets(id),
    action          VARCHAR(64) NOT NULL,    -- created/diagnosed/suggested/replied/resolved
    operator_type   VARCHAR(16),             -- ai/human/system
    operator_id     VARCHAR(64),
    content         JSONB NOT NULL,
    created_at      TIMESTAMPTZ DEFAULT now()
);

12.5 结构化知识库

CREATE TABLE knowledge_base (
    id              BIGSERIAL PRIMARY KEY,
    category        VARCHAR(32) NOT NULL,    -- supplier/operation/technical
    title           VARCHAR(256) NOT NULL,
    content         TEXT NOT NULL,
    tags            VARCHAR(256)[],          -- 数组标签
    related_type    VARCHAR(32),             -- supplier_id/agent_id/incident_id
    related_id      VARCHAR(64),
    source          VARCHAR(32) NOT NULL,    -- manual/auto_decision/auto_incident/auto_config
    confidence      DECIMAL(3,2) DEFAULT 1.0,
    reference_count INT DEFAULT 0,
    created_at      TIMESTAMPTZ DEFAULT now(),
    updated_at      TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE knowledge_references (
    id              BIGSERIAL PRIMARY KEY,
    knowledge_id    BIGINT REFERENCES knowledge_base(id),
    ref_type        VARCHAR(32),             -- ticket/incident/decision/config_change
    ref_id          VARCHAR(64),
    context         TEXT,
    created_at      TIMESTAMPTZ DEFAULT now()
);

12.6 财务感知与预警

CREATE TABLE financial_metrics (
    id              BIGSERIAL PRIMARY KEY,
    metric_date     DATE NOT NULL,
    metric_type     VARCHAR(64) NOT NULL,    -- daily_commission/supplier_contribution/agent_revenue
    dimension_key   VARCHAR(128),            -- supplier_id/agent_id
    dimension_value VARCHAR(128),
    amount          DECIMAL(14,2) NOT NULL,
    change_pct      DECIMAL(5,2),
    change_reason   TEXT,
    calculated_at   TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE financial_alerts (
    id              BIGSERIAL PRIMARY KEY,
    alert_type      VARCHAR(64) NOT NULL,    -- revenue_drop/overdue_payment/credit_limit
    entity_type     VARCHAR(32),             -- supplier/agent
    entity_id       VARCHAR(64),
    current_value   DECIMAL(14,2),
    threshold_value DECIMAL(14,2),
    suggestion      TEXT,
    status          VARCHAR(16) DEFAULT 'pending',
    created_at      TIMESTAMPTZ DEFAULT now()
);

12.7 指标采集与全链路 Trace

CREATE TABLE trace_events (
    id              BIGSERIAL PRIMARY KEY,
    trace_id        VARCHAR(64) NOT NULL,     -- 链路追踪 ID
    span_id         VARCHAR(64) NOT NULL,     -- 当前环节 ID
    parent_span_id  VARCHAR(64),              -- 父环节 ID
    event_type      VARCHAR(64) NOT NULL,     -- search/cache_hit/supplier_query/trial/book/confirm/settle
    service         VARCHAR(32) NOT NULL,     -- api_gateway/query_engine/supplier_adapter/...
    related_type    VARCHAR(32),              -- order/supplier/agent/hotel
    related_id      VARCHAR(64),
    request_data    JSONB,
    response_data   JSONB,
    duration_ms     INT,
    status          VARCHAR(16) NOT NULL,     -- success/error/timeout
    error_detail    TEXT,
    created_at      TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_trace_trace_id ON trace_events(trace_id);
CREATE INDEX idx_trace_related ON trace_events(related_type, related_id);
CREATE INDEX idx_trace_created ON trace_events(created_at);

文档结束
本文档为 B2B2B 酒店分销平台完整数据模型设计,共计 75+ 张数据表(含 3 张 ClickHouse 表),覆盖所有业务模块。