yumeng 1 месяц назад
Родитель
Сommit
9a6355938e

+ 112 - 7
src/main/java/com/adx/tencent/conversionsync/ConversionSyncService.java

@@ -24,6 +24,7 @@ import com.adx.tencent.storage.model.BidRecord;
 import com.adx.tencent.storage.model.ConversionRecord;
 import com.adx.tencent.storage.model.MediaCallbackRecord;
 import com.adx.tencent.storage.model.AccountTagEventRecord;
+import com.adx.tencent.storage.model.TencentTagEventProfileRecord;
 import com.adx.tencent.tagsync.AccountTagEventResolver;
 import com.adx.tencent.tagsync.TagEventResolver;
 import com.adx.tencent.tencent.TencentClient;
@@ -448,6 +449,38 @@ public class ConversionSyncService {
     }
 
     private CallbackTask buildTencentCallbackTask(PaymentInfo payment, BidRecord bid) {
+        String callbackProfile = callbackProfile(bid.getMediaParams());
+        if (callbackProfile != null) {
+            if (coldStore == null) {
+                log.warn("[ConversionSync] 腾讯 profile 回传配置不可用, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            TencentTagEventProfileRecord profileMapping = coldStore.getTagEventProfile(
+                    bid.getTagId(), callbackProfile, payment.getAct());
+            if (profileMapping == null
+                    || profileMapping.getTencentActionType() == null
+                    || profileMapping.getTencentActionType().isBlank()) {
+                log.info("[ConversionSync] 腾讯 profile 未配置该 act, 严格跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            String actionType = profileMapping.getTencentActionType();
+            String customAction = profileMapping.getTencentCustomAction();
+            if ("CUSTOM".equals(actionType) && (customAction == null || customAction.isBlank())) {
+                log.warn("[ConversionSync] 腾讯 profile CUSTOM 缺少 custom_action, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            return CallbackTask.tencent(
+                    payment,
+                    bid,
+                    callbackDedupeKey(payment, bid, actionType),
+                    actionType,
+                    customAction
+            );
+        }
+
         String actionType = null;
         String customAction = null;
         if (accountTagEventResolver != null) {
@@ -497,9 +530,27 @@ public class ConversionSyncService {
             return null;
         }
 
-        Integer conversionId = honorTagEventResolver != null
-                ? honorTagEventResolver.resolveConversionId(bid.getTagId(), payment.getAct())
-                : resolveHonorConversionIdFromDb(bid.getTagId(), payment.getAct());
+        String callbackProfile = callbackProfile(bid.getMediaParams());
+        Integer conversionId;
+        if (callbackProfile != null) {
+            if (honorColdStore == null) {
+                log.warn("[ConversionSync] 荣耀 profile 回传配置不可用, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            com.adx.tencent.honor.model.HonorTagEventRecord profileEvent =
+                    honorColdStore.getTagEventProfile(bid.getTagId(), callbackProfile, payment.getAct());
+            if (profileEvent == null) {
+                log.info("[ConversionSync] 荣耀 profile 未配置该 act, 严格跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            conversionId = profileEvent.getConversionId();
+        } else {
+            conversionId = honorTagEventResolver != null
+                    ? honorTagEventResolver.resolveConversionId(bid.getTagId(), payment.getAct())
+                    : resolveHonorConversionIdFromDb(bid.getTagId(), payment.getAct());
+        }
         if (conversionId == null) {
             conversionId = fallbackHonorConversionId(payment.getAct());
             if (conversionId == null) {
@@ -537,7 +588,23 @@ public class ConversionSyncService {
             return List.of();
         }
 
-        List<KuaishouTagEventRecord> tagEvents = resolveKuaishouTagEvents(bid.getTagId(), payment.getAct());
+        String callbackProfile = callbackProfile(bid.getMediaParams());
+        List<KuaishouTagEventRecord> tagEvents;
+        if (callbackProfile != null) {
+            if (kuaishouColdStore == null) {
+                log.warn("[ConversionSync] 快手 profile 回传配置不可用, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return List.of();
+            }
+            tagEvents = kuaishouColdStore.getTagEventProfiles(bid.getTagId(), callbackProfile, payment.getAct());
+            if (tagEvents.isEmpty()) {
+                log.info("[ConversionSync] 快手 profile 未配置该 act, 严格跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return List.of();
+            }
+        } else {
+            tagEvents = resolveKuaishouTagEvents(bid.getTagId(), payment.getAct());
+        }
         if (tagEvents.isEmpty()) {
             log.warn("[ConversionSync] 快手 eventType 未配置且无兜底映射 | qk={} | tagId={} | act={}",
                     payment.getQk(), bid.getTagId(), payment.getAct());
@@ -561,7 +628,23 @@ public class ConversionSyncService {
             return List.of();
         }
 
-        List<VivoTagEventRecord> tagEvents = resolveVivoTagEvents(bid.getTagId(), payment.getAct());
+        String callbackProfile = callbackProfile(bid.getMediaParams());
+        List<VivoTagEventRecord> tagEvents;
+        if (callbackProfile != null) {
+            if (vivoColdStore == null) {
+                log.warn("[ConversionSync] vivo profile 回传配置不可用, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return List.of();
+            }
+            tagEvents = vivoColdStore.getTagEventProfiles(bid.getTagId(), callbackProfile, payment.getAct());
+            if (tagEvents.isEmpty()) {
+                log.info("[ConversionSync] vivo profile 未配置该 act, 严格跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return List.of();
+            }
+        } else {
+            tagEvents = resolveVivoTagEvents(bid.getTagId(), payment.getAct());
+        }
         if (tagEvents.isEmpty()) {
             log.warn("[ConversionSync] vivo eventType 未配置且无兜底映射 | qk={} | tagId={} | act={}",
                     payment.getQk(), bid.getTagId(), payment.getAct());
@@ -581,8 +664,26 @@ public class ConversionSyncService {
     }
 
     private CallbackTask buildOppoCallbackTask(PaymentInfo payment, OppoBidRecord bid) {
-        Integer dataType = oppoTagEventResolver == null ? null
-                : oppoTagEventResolver.resolveDataType(bid.getTagId(), payment.getAct());
+        String callbackProfile = callbackProfile(bid.getMediaParams());
+        Integer dataType;
+        if (callbackProfile != null) {
+            if (oppoColdStore == null) {
+                log.warn("[ConversionSync] OPPO profile 回传配置不可用, 跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            OppoTagEventRecord profileEvent = oppoColdStore.getTagEventProfile(
+                    bid.getTagId(), callbackProfile, payment.getAct());
+            if (profileEvent == null) {
+                log.info("[ConversionSync] OPPO profile 未配置该 act, 严格跳过回传 | qk={} | tagId={} | profile={} | act={}",
+                        payment.getQk(), bid.getTagId(), callbackProfile, payment.getAct());
+                return null;
+            }
+            dataType = profileEvent.getDataType();
+        } else {
+            dataType = oppoTagEventResolver == null ? null
+                    : oppoTagEventResolver.resolveDataType(bid.getTagId(), payment.getAct());
+        }
         if (dataType == null) {
             dataType = resolveOppoFallbackDataType(payment.getAct());
             if (dataType != null) {
@@ -614,6 +715,10 @@ public class ConversionSyncService {
         };
     }
 
+    private static String callbackProfile(Map<String, String> mediaParams) {
+        return firstParam(mediaParams, "callback_profile", "callbackProfile", "eventProfile", "mappingProfile");
+    }
+
     private Integer resolveHonorConversionIdFromDb(String tagId, int baiduAct) {
         if (honorColdStore == null) {
             return null;

+ 1 - 0
src/main/java/com/adx/tencent/honor/model/HonorBidRecord.java

@@ -133,6 +133,7 @@ public class HonorBidRecord {
                 "oaid", "oaidMd5", "oaid_md5", "hash_oaid",
                 "dpid", "dpidMd5", "dpid_md5", "hash_android_id",
                 "muid",
+                "callback_profile", "callbackProfile", "eventProfile", "mappingProfile",
                 DEDUCTION_RATE_KEY,
                 ACT_2001_DEDUCTION_RATE_KEY,
                 "rta_tu",

+ 54 - 0
src/main/java/com/adx/tencent/honor/store/HonorColdStore.java

@@ -106,6 +106,19 @@ public class HonorColdStore {
                     conversion_id INT NOT NULL,
                     PRIMARY KEY (tag_id, baidu_act)
                 )
+                """,
+                """
+                CREATE TABLE IF NOT EXISTS honor_tag_event_profile (
+                    tag_id VARCHAR(128) NOT NULL,
+                    callback_profile VARCHAR(64) NOT NULL,
+                    baidu_act INT NOT NULL,
+                    conversion_id INT NOT NULL,
+                    enabled TINYINT(1) NOT NULL DEFAULT 1,
+                    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+                    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
+                    PRIMARY KEY (tag_id, callback_profile, baidu_act),
+                    KEY idx_honor_tag_event_profile_profile_act (callback_profile, baidu_act)
+                )
                 """
         };
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
@@ -131,6 +144,22 @@ public class HonorColdStore {
                 stmt.execute("ALTER TABLE honor_media_callbacks ADD COLUMN dispatch_status VARCHAR(32) NOT NULL DEFAULT 'SENT' COMMENT '回传处理状态(SENT/DEDUCTED)' AFTER deduction_rate");
             } catch (Exception ignored) {
             }
+            try {
+                stmt.execute("""
+                        CREATE TABLE IF NOT EXISTS honor_tag_event_profile (
+                            tag_id VARCHAR(128) NOT NULL,
+                            callback_profile VARCHAR(64) NOT NULL,
+                            baidu_act INT NOT NULL,
+                            conversion_id INT NOT NULL,
+                            enabled TINYINT(1) NOT NULL DEFAULT 1,
+                            created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+                            updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
+                            PRIMARY KEY (tag_id, callback_profile, baidu_act),
+                            KEY idx_honor_tag_event_profile_profile_act (callback_profile, baidu_act)
+                        )
+                        """);
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("honor migrate failed", e);
@@ -218,6 +247,31 @@ public class HonorColdStore {
         }
     }
 
+    public HonorTagEventRecord getTagEventProfile(String tagId, String callbackProfile, int baiduAct) {
+        if (tagId == null || tagId.isBlank() || callbackProfile == null || callbackProfile.isBlank()) return null;
+        String sql = """
+                SELECT tag_id, baidu_act, conversion_id
+                FROM honor_tag_event_profile
+                WHERE tag_id = ? AND callback_profile = ? AND baidu_act = ? AND enabled = 1
+                """;
+        try (SqlSession session = sqlSessionFactory.openSession(true);
+             var ps = session.getConnection().prepareStatement(sql)) {
+            ps.setString(1, tagId);
+            ps.setString(2, callbackProfile);
+            ps.setInt(3, baiduAct);
+            try (var rs = ps.executeQuery()) {
+                if (!rs.next()) return null;
+                HonorTagEventRecord record = new HonorTagEventRecord();
+                record.setTagId(rs.getString(1));
+                record.setBaiduAct(rs.getInt(2));
+                record.setConversionId(rs.getInt(3));
+                return record;
+            }
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
     public List<HonorTagEventRecord> listAllTagEvents() {
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
             HonorTagEventMapper mapper = session.getMapper(HonorTagEventMapper.class);

+ 1 - 0
src/main/java/com/adx/tencent/kuaishou/model/KuaishouBidRecord.java

@@ -123,6 +123,7 @@ public class KuaishouBidRecord {
         if (params == null || params.isEmpty()) return null;
         List<String> keepKeys = List.of(
                 "callback", "ts",
+                "callback_profile", "callbackProfile", "eventProfile", "mappingProfile",
                 DEDUCTION_RATE_KEY
         );
         Map<String, String> slim = new LinkedHashMap<>();

+ 58 - 0
src/main/java/com/adx/tencent/kuaishou/store/KuaishouColdStore.java

@@ -97,6 +97,19 @@ public class KuaishouColdStore {
                     event_type INT NOT NULL COMMENT '快手回传事件类型',
                     PRIMARY KEY (tag_id, baidu_act, event_type)
                 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手广告位回传事件配置'
+                """,
+                """
+                CREATE TABLE IF NOT EXISTS kuaishou_tag_event_profile (
+                    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                    baidu_act INT NOT NULL COMMENT '百度转化行为',
+                    event_type INT NOT NULL COMMENT '快手回传事件类型',
+                    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                    PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+                    KEY idx_kuaishou_tag_event_profile_profile_act (callback_profile, baidu_act)
+                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手profile级广告位回传事件配置'
                 """
         };
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
@@ -118,6 +131,22 @@ public class KuaishouColdStore {
                 stmt.execute("ALTER TABLE kuaishou_tracking_reports ADD KEY idx_kuaishou_tracking_reports_created_at_id (created_at, id)");
             } catch (Exception ignored) {
             }
+            try {
+                stmt.execute("""
+                        CREATE TABLE IF NOT EXISTS kuaishou_tag_event_profile (
+                            tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                            callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                            baidu_act INT NOT NULL COMMENT '百度转化行为',
+                            event_type INT NOT NULL COMMENT '快手回传事件类型',
+                            enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                            created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                            updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                            PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+                            KEY idx_kuaishou_tag_event_profile_profile_act (callback_profile, baidu_act)
+                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手profile级广告位回传事件配置'
+                        """);
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("kuaishou migrate failed", e);
@@ -190,6 +219,35 @@ public class KuaishouColdStore {
         }
     }
 
+    public List<KuaishouTagEventRecord> getTagEventProfiles(String tagId, String callbackProfile, int baiduAct) {
+        if (tagId == null || tagId.isBlank() || callbackProfile == null || callbackProfile.isBlank()) return List.of();
+        String sql = """
+                SELECT tag_id, baidu_act, event_type
+                FROM kuaishou_tag_event_profile
+                WHERE tag_id = ? AND callback_profile = ? AND baidu_act = ? AND enabled = 1
+                ORDER BY event_type ASC
+                """;
+        try (SqlSession session = sqlSessionFactory.openSession(true);
+             var ps = session.getConnection().prepareStatement(sql)) {
+            ps.setString(1, tagId);
+            ps.setString(2, callbackProfile);
+            ps.setInt(3, baiduAct);
+            try (var rs = ps.executeQuery()) {
+                List<KuaishouTagEventRecord> records = new ArrayList<>();
+                while (rs.next()) {
+                    KuaishouTagEventRecord record = new KuaishouTagEventRecord();
+                    record.setTagId(rs.getString(1));
+                    record.setBaiduAct(rs.getInt(2));
+                    record.setEventType(rs.getInt(3));
+                    records.add(record);
+                }
+                return records;
+            }
+        } catch (Exception e) {
+            return List.of();
+        }
+    }
+
     public List<KuaishouTagEventRecord> listAllTagEvents() {
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
             return session.getMapper(KuaishouTagEventMapper.class).selectAll();

+ 1 - 0
src/main/java/com/adx/tencent/oppo/model/OppoBidRecord.java

@@ -53,6 +53,7 @@ public class OppoBidRecord {
         if (mediaParams != null) {
             Map<String, String> params = new LinkedHashMap<>();
             for (String key : List.of("oaid", "imei", "androidId", "mac", "ip", "adId", "deduction_rate",
+                    "callback_profile", "callbackProfile", "eventProfile", "mappingProfile",
                     "rta_tu", "rta_order_id", "rta_request_order_id", "rta_qk", "rta_request_id", "rta_code")) {
                 String value = mediaParams.get(key);
                 if (value != null && !value.isBlank()) params.put(key, value);

+ 37 - 0
src/main/java/com/adx/tencent/oppo/store/OppoColdStore.java

@@ -36,6 +36,24 @@ public class OppoColdStore {
     public List<OppoTagEventRecord> getTagEvents(String tagId, int act) {
         return jdbc.query("SELECT tag_id,baidu_act,data_type FROM oppo_tag_event WHERE tag_id=? AND baidu_act IN (?,0) ORDER BY baidu_act DESC", (rs,n)-> { OppoTagEventRecord r=new OppoTagEventRecord(); r.setTagId(rs.getString(1)); r.setBaiduAct(rs.getInt(2)); r.setDataType(rs.getInt(3)); return r; }, tagId, act);
     }
+    public OppoTagEventRecord getTagEventProfile(String tagId, String profile, int act) {
+        if (tagId == null || tagId.isBlank() || profile == null || profile.isBlank()) {
+            return null;
+        }
+        List<OppoTagEventRecord> rows = jdbc.query("""
+                        SELECT tag_id,baidu_act,data_type
+                        FROM oppo_tag_event_profile
+                        WHERE tag_id=? AND callback_profile=? AND baidu_act=? AND enabled=1
+                        """,
+                (rs, n) -> {
+                    OppoTagEventRecord r = new OppoTagEventRecord();
+                    r.setTagId(rs.getString(1));
+                    r.setBaiduAct(rs.getInt(2));
+                    r.setDataType(rs.getInt(3));
+                    return r;
+                }, tagId, profile, act);
+        return rows.isEmpty() ? null : rows.get(0);
+    }
     public List<OppoTagEventRecord> listAllTagEvents() {
         return jdbc.query("SELECT tag_id,baidu_act,data_type FROM oppo_tag_event", (rs,n)-> { OppoTagEventRecord r=new OppoTagEventRecord(); r.setTagId(rs.getString(1)); r.setBaiduAct(rs.getInt(2)); r.setDataType(rs.getInt(3)); return r; });
     }
@@ -70,6 +88,7 @@ public class OppoColdStore {
         populator.setContinueOnError(false);
         populator.execute(dataSource);
         ensureCallbackOwnerColumn();
+        ensureTagEventProfileTable();
     }
 
     private void ensureCallbackOwnerColumn() {
@@ -78,4 +97,22 @@ public class OppoColdStore {
             if (count != null && count == 0) jdbc.execute("ALTER TABLE oppo_media_callbacks ADD COLUMN owner_id VARCHAR(128) NULL COMMENT 'OPPO广告主ownerId,用于重试授权' AFTER tag_id");
         } catch (Exception e) { throw new RuntimeException("ensure oppo callback owner_id failed", e); }
     }
+
+    private void ensureTagEventProfileTable() {
+        try {
+            jdbc.execute("""
+                    CREATE TABLE IF NOT EXISTS oppo_tag_event_profile (
+                        tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                        callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                        baidu_act INT NOT NULL COMMENT '百度转化行为',
+                        data_type INT NOT NULL COMMENT 'OPPO dataType',
+                        enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                        created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                        updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                        PRIMARY KEY (tag_id, callback_profile, baidu_act),
+                        KEY idx_oppo_tag_event_profile_profile_act (callback_profile, baidu_act)
+                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OPPO profile级广告位回传事件配置'
+                    """);
+        } catch (Exception e) { throw new RuntimeException("ensure oppo tag event profile failed", e); }
+    }
 }

+ 63 - 0
src/main/java/com/adx/tencent/storage/TiDBColdStore.java

@@ -146,6 +146,20 @@ public class TiDBColdStore {
                 PRIMARY KEY (tag_id, account_id, baidu_act),
                 KEY idx_tencent_account_tag_event_account_act (account_id, baidu_act)
             ) COMMENT '腾讯账户级广告位回传方式配置'
+            """,
+            """
+            CREATE TABLE IF NOT EXISTS tencent_tag_event_profile (
+                tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                baidu_act INT NOT NULL COMMENT '百度转化行为',
+                tencent_action_type VARCHAR(128) NOT NULL COMMENT '腾讯回传行为',
+                tencent_custom_action VARCHAR(128) COMMENT '腾讯自定义行为(action_type=CUSTOM时使用)',
+                enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                PRIMARY KEY (tag_id, callback_profile, baidu_act),
+                KEY idx_tencent_tag_event_profile_profile_act (callback_profile, baidu_act)
+            ) COMMENT '腾讯profile级广告位回传方式配置'
             """
         };
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
@@ -212,6 +226,22 @@ public class TiDBColdStore {
             try {
                 stmt.execute("ALTER TABLE tencent_account_tag_event ADD COLUMN tencent_custom_action VARCHAR(128) COMMENT '腾讯自定义行为(action_type=CUSTOM时使用)' AFTER tencent_action_type");
             } catch (Exception ignored) {}
+            try {
+                stmt.execute("""
+                        CREATE TABLE IF NOT EXISTS tencent_tag_event_profile (
+                            tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                            callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                            baidu_act INT NOT NULL COMMENT '百度转化行为',
+                            tencent_action_type VARCHAR(128) NOT NULL COMMENT '腾讯回传行为',
+                            tencent_custom_action VARCHAR(128) COMMENT '腾讯自定义行为(action_type=CUSTOM时使用)',
+                            enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                            created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                            updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                            PRIMARY KEY (tag_id, callback_profile, baidu_act),
+                            KEY idx_tencent_tag_event_profile_profile_act (callback_profile, baidu_act)
+                        ) COMMENT '腾讯profile级广告位回传方式配置'
+                        """);
+            } catch (Exception ignored) {}
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("migrate failed", e);
@@ -449,6 +479,39 @@ public class TiDBColdStore {
         }
     }
 
+    public TencentTagEventProfileRecord getTagEventProfile(String tagId, String callbackProfile, int baiduAct) {
+        if (tagId == null || tagId.isBlank() || callbackProfile == null || callbackProfile.isBlank()) {
+            return null;
+        }
+        String sql = """
+                SELECT tag_id, callback_profile, baidu_act, tencent_action_type, tencent_custom_action
+                FROM tencent_tag_event_profile
+                WHERE tag_id = ? AND callback_profile = ? AND baidu_act = ? AND enabled = 1
+                """;
+        try (SqlSession session = sqlSessionFactory.openSession(true);
+             var ps = session.getConnection().prepareStatement(sql)) {
+            ps.setString(1, tagId);
+            ps.setString(2, callbackProfile);
+            ps.setInt(3, baiduAct);
+            try (var rs = ps.executeQuery()) {
+                if (!rs.next()) {
+                    return null;
+                }
+                TencentTagEventProfileRecord record = new TencentTagEventProfileRecord();
+                record.setTagId(rs.getString(1));
+                record.setCallbackProfile(rs.getString(2));
+                record.setBaiduAct(rs.getInt(3));
+                record.setTencentActionType(rs.getString(4));
+                record.setTencentCustomAction(rs.getString(5));
+                return record;
+            }
+        } catch (Exception e) {
+            log.warn("[TiDBColdStore] 查询 tencent_tag_event_profile 失败 | tagId={} | profile={} | act={} | error={}",
+                    tagId, callbackProfile, baiduAct, e.getMessage());
+            return null;
+        }
+    }
+
     // ─── 查询:腾讯账户级广告位回传方式配置 ───────────────────────────────────
 
     public List<AccountTagEventRecord> listAllAccountTagEvents() {

+ 1 - 0
src/main/java/com/adx/tencent/storage/model/BidRecord.java

@@ -145,6 +145,7 @@ public class BidRecord {
                 "hash_oaid", "hash_android_id",
                 "ip", "ua", "user_agent",
                 "callback", "click_id", "account_id",
+                "callback_profile", "callbackProfile", "eventProfile", "mappingProfile",
                 NEW_LINK_FLAG_KEY, TRACKING_VERSION_KEY, DEDUCTION_RATE_KEY,
                 ACT_2001_DEDUCTION_RATE_KEY
         );

+ 23 - 0
src/main/java/com/adx/tencent/storage/model/TencentTagEventProfileRecord.java

@@ -0,0 +1,23 @@
+package com.adx.tencent.storage.model;
+
+/**
+ * 腾讯 profile 级广告位回传方式记录,对应 tencent_tag_event_profile 表。
+ */
+public class TencentTagEventProfileRecord {
+    private String tagId;
+    private String callbackProfile;
+    private int baiduAct;
+    private String tencentActionType;
+    private String tencentCustomAction;
+
+    public String getTagId() { return tagId; }
+    public void setTagId(String tagId) { this.tagId = tagId; }
+    public String getCallbackProfile() { return callbackProfile; }
+    public void setCallbackProfile(String callbackProfile) { this.callbackProfile = callbackProfile; }
+    public int getBaiduAct() { return baiduAct; }
+    public void setBaiduAct(int baiduAct) { this.baiduAct = baiduAct; }
+    public String getTencentActionType() { return tencentActionType; }
+    public void setTencentActionType(String tencentActionType) { this.tencentActionType = tencentActionType; }
+    public String getTencentCustomAction() { return tencentCustomAction; }
+    public void setTencentCustomAction(String tencentCustomAction) { this.tencentCustomAction = tencentCustomAction; }
+}

+ 1 - 0
src/main/java/com/adx/tencent/vivo/model/VivoBidRecord.java

@@ -144,6 +144,7 @@ public class VivoBidRecord {
                 "androidId",
                 "androidIdMD5",
                 "platform",
+                "callback_profile", "callbackProfile", "eventProfile", "mappingProfile",
                 DEDUCTION_RATE_KEY,
                 "rta_tu",
                 "rta_order_id",

+ 58 - 0
src/main/java/com/adx/tencent/vivo/store/VivoColdStore.java

@@ -107,6 +107,19 @@ public class VivoColdStore {
                 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo广告位回传事件配置'
                 """,
                 """
+                CREATE TABLE IF NOT EXISTS vivo_tag_event_profile (
+                    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                    baidu_act INT NOT NULL COMMENT '百度转化行为',
+                    event_type VARCHAR(64) NOT NULL COMMENT 'vivo 回传事件类型',
+                    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                    PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+                    KEY idx_vivo_tag_event_profile_profile_act (callback_profile, baidu_act)
+                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo profile级广告位回传事件配置'
+                """,
+                """
                 CREATE TABLE IF NOT EXISTS vivo_account_tokens (
                     account_id VARCHAR(128) NOT NULL COMMENT 'vivo 二代账户ID',
                     account_name VARCHAR(255) COMMENT 'vivo 二代账户名称',
@@ -201,6 +214,22 @@ public class VivoColdStore {
                 stmt.execute("ALTER TABLE vivo_tracking_reports ADD KEY idx_vivo_tracking_reports_created_at_id (created_at, id)");
             } catch (Exception ignored) {
             }
+            try {
+                stmt.execute("""
+                        CREATE TABLE IF NOT EXISTS vivo_tag_event_profile (
+                            tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+                            callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+                            baidu_act INT NOT NULL COMMENT '百度转化行为',
+                            event_type VARCHAR(64) NOT NULL COMMENT 'vivo 回传事件类型',
+                            enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+                            created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+                            updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+                            PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+                            KEY idx_vivo_tag_event_profile_profile_act (callback_profile, baidu_act)
+                        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo profile级广告位回传事件配置'
+                        """);
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("vivo migrate failed", e);
@@ -268,6 +297,35 @@ public class VivoColdStore {
         }
     }
 
+    public List<VivoTagEventRecord> getTagEventProfiles(String tagId, String callbackProfile, int baiduAct) {
+        if (tagId == null || tagId.isBlank() || callbackProfile == null || callbackProfile.isBlank()) return List.of();
+        String sql = """
+                SELECT tag_id, baidu_act, event_type
+                FROM vivo_tag_event_profile
+                WHERE tag_id = ? AND callback_profile = ? AND baidu_act = ? AND enabled = 1
+                ORDER BY event_type ASC
+                """;
+        try (SqlSession session = sqlSessionFactory.openSession(true);
+             var ps = session.getConnection().prepareStatement(sql)) {
+            ps.setString(1, tagId);
+            ps.setString(2, callbackProfile);
+            ps.setInt(3, baiduAct);
+            try (var rs = ps.executeQuery()) {
+                List<VivoTagEventRecord> records = new ArrayList<>();
+                while (rs.next()) {
+                    VivoTagEventRecord record = new VivoTagEventRecord();
+                    record.setTagId(rs.getString(1));
+                    record.setBaiduAct(rs.getInt(2));
+                    record.setEventType(rs.getString(3));
+                    records.add(record);
+                }
+                return records;
+            }
+        } catch (Exception e) {
+            return List.of();
+        }
+    }
+
     public List<VivoTagEventRecord> listAllTagEvents() {
         try (SqlSession session = sqlSessionFactory.openSession(true)) {
             return session.getMapper(VivoTagEventMapper.class).selectAll();

+ 16 - 0
src/main/resources/schema-honor.sql

@@ -83,7 +83,22 @@ CREATE TABLE IF NOT EXISTS honor_tag_event (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='荣耀广告位转化事件映射';
 
 -- ------------------------------------------------------------
+-- 5. 荣耀 profile 级广告位回传事件映射表
+-- ------------------------------------------------------------
+CREATE TABLE IF NOT EXISTS honor_tag_event_profile (
+    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+    baidu_act INT NOT NULL COMMENT '百度转化行为',
+    conversion_id INT NOT NULL COMMENT '荣耀 conversionId',
+    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+    PRIMARY KEY (tag_id, callback_profile, baidu_act),
+    KEY idx_honor_tag_event_profile_profile_act (callback_profile, baidu_act)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='荣耀profile级广告位转化事件映射';
+
+-- ------------------------------------------------------------
+-- 6. RTA 广告位 order_id 配置表
 -- ------------------------------------------------------------
 CREATE TABLE IF NOT EXISTS rta_tag_orders (
     tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',

+ 12 - 0
src/main/resources/schema-kuaishou.sql

@@ -61,3 +61,15 @@ CREATE TABLE IF NOT EXISTS kuaishou_tag_event (
     event_type INT NOT NULL COMMENT '快手回传事件类型',
     PRIMARY KEY (tag_id, baidu_act, event_type)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手广告位回传事件配置';
+
+CREATE TABLE IF NOT EXISTS kuaishou_tag_event_profile (
+    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+    baidu_act INT NOT NULL COMMENT '百度转化行为',
+    event_type INT NOT NULL COMMENT '快手回传事件类型',
+    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+    PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+    KEY idx_kuaishou_tag_event_profile_profile_act (callback_profile, baidu_act)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手profile级广告位回传事件配置';

+ 12 - 0
src/main/resources/schema-oppo.sql

@@ -68,3 +68,15 @@ CREATE TABLE IF NOT EXISTS oppo_tag_event (
     data_type INT NOT NULL COMMENT 'OPPO dataType',
     PRIMARY KEY (tag_id, baidu_act, data_type)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OPPO广告位转化事件映射';
+
+CREATE TABLE IF NOT EXISTS oppo_tag_event_profile (
+    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+    baidu_act INT NOT NULL COMMENT '百度转化行为',
+    data_type INT NOT NULL COMMENT 'OPPO dataType',
+    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+    PRIMARY KEY (tag_id, callback_profile, baidu_act),
+    KEY idx_oppo_tag_event_profile_profile_act (callback_profile, baidu_act)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='OPPO profile级广告位转化事件映射';

+ 12 - 0
src/main/resources/schema-vivo.sql

@@ -64,6 +64,18 @@ CREATE TABLE IF NOT EXISTS vivo_tag_event (
     PRIMARY KEY (tag_id, baidu_act, event_type)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo广告位回传事件配置';
 
+CREATE TABLE IF NOT EXISTS vivo_tag_event_profile (
+    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+    baidu_act INT NOT NULL COMMENT '百度转化行为',
+    event_type VARCHAR(64) NOT NULL COMMENT 'vivo 回传事件类型',
+    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+    PRIMARY KEY (tag_id, callback_profile, baidu_act, event_type),
+    KEY idx_vivo_tag_event_profile_profile_act (callback_profile, baidu_act)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo profile级广告位回传事件配置';
+
 CREATE TABLE IF NOT EXISTS rta_tag_orders (
     tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
     order_id VARCHAR(255) NOT NULL COMMENT 'RTA order_id',

+ 17 - 0
src/main/resources/schema.sql

@@ -121,7 +121,23 @@ CREATE TABLE IF NOT EXISTS tencent_account_tag_event (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='腾讯账户级广告位回传方式配置';
 
 -- ------------------------------------------------------------
+-- 7. 腾讯 profile 级广告位回传方式配置表
+-- ------------------------------------------------------------
+CREATE TABLE IF NOT EXISTS tencent_tag_event_profile (
+    tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',
+    callback_profile VARCHAR(64) NOT NULL COMMENT '回传方案',
+    baidu_act INT NOT NULL COMMENT '百度转化行为',
+    tencent_action_type VARCHAR(128) NOT NULL COMMENT '腾讯回传行为',
+    tencent_custom_action VARCHAR(128) COMMENT '腾讯自定义行为(action_type=CUSTOM时使用)',
+    enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
+    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
+    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
+    PRIMARY KEY (tag_id, callback_profile, baidu_act),
+    KEY idx_tencent_tag_event_profile_profile_act (callback_profile, baidu_act)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='腾讯profile级广告位回传方式配置';
+
+-- ------------------------------------------------------------
+-- 8. RTA 广告位 order_id 配置表(荣耀/vivo 共用)
 -- ------------------------------------------------------------
 CREATE TABLE IF NOT EXISTS rta_tag_orders (
     tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',