TDD-10 数据埋点与分析设计\n\n> 文档类型:技术设计文档(Technical Design Document)\n> 版本:1.0\n> 日期:2026-07-02\n> 关联文档:TDD-04《数据库表结构设计》、TDD-05《API接口设计》、TDD-06《离线挂机结算系统设计》、TDD-07《反作弊与安全设计》、TDD-08《GM与运营后台设计》、PRD-01《核心玩法与系统需求文档》、PRD-03《热更新与活动系统需求文档》、GDD-06《经济系统设计》、GDD-22《开放世界随机事件与玩家可交互内容层》\n\n---\n\n## 1. 文档信息\n\n| 项目 | 说明 |\n|------|------|\n| 目标 | 为《洪荒大陆》挂机手游定义数据埋点事件规范、数据管道架构、核心分析指标、A/B测试框架、数据看板及数据安全合规方案。 |\n| 读者 | 数据工程师、服务端开发(Nakama/Go)、客户端开发(Cocos Creator 3.x)、数值策划、运营 |\n| 技术栈 | 客户端 Cocos Creator 3.x;服务端 Nakama 3.x + Go 插件 + PostgreSQL 16 + Valkey + Nacos 2.x;数据管道 Kafka + Flink + ClickHouse + Hive/Spark |\n| 核心约束 | 无任务系统、无赛季重置、概率/机遇驱动、全自动ATB即时制战斗 |\n| 境界体系 | 9大境界(炼气/筑基/金丹/元婴/化神/合体/大乘/渡劫/飞升),5层世界 |\n| 种族 | 19个可创角种族,3大阵营(天道/洪荒/幽冥)+ 混沌中立 |\n| 游戏时间 | 现实:游戏 = 1:3 |\n\n---\n\n## 2. 埋点事件 Schema 设计\n\n### 2.1 通用字段定义\n\n所有埋点事件(客户端 + 服务端)共享以下通用字段:\n\n| 字段名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| event_id | string(uuid) | 是 | 事件唯一标识,用于幂等去重 |\n| event_name | string | 是 | 事件名称,格式:{module}.{action},如 combat.battle_end |\n| event_category | string | 是 | 事件分类:client / server |\n| timestamp | int64 | 是 | 事件发生时间戳(毫秒级,UTC) |\n| event_date | string | 是 | 事件日期分区键,格式 YYYY-MM-DD(UTC) |\n| player_id | string(uuid) | 是 | 玩家账户 ID(对应 players.id) |\n| character_id | string(uuid) | 否 | 角色 ID(对应 characters.id),创角前事件为空 |\n| device_id | string | 是 | 设备指纹哈希(对应 players.device_id_hash) |\n| session_id | string(uuid) | 是 | 会话 ID,一次登录周期内不变 |\n| client_version | string | 是 | 客户端版本号,格式 主.次.热更.资源(如 1.2.3.4) |\n| server_id | string | 是 | 服务实例标识(如 nakama-prod-01) |\n| platform | string | 是 | 平台:ios / android / pc / web |\n| channel | string | 否 | 渠道包标识(如 official / huawei / xiaomi) |\n| network_type | string | 否 | 网络类型:wifi / 4g / 5g / offline |\n| world_tier | int | 否 | 当前世界层级(1~5),创角前为空 |\n| realm_tier | int | 否 | 当前大境界(1~9),创角前为空 |\n| race_id | string | 否 | 当前种族 ID,创角前为空 |\n| config_version | string | 否 | 服务端配置版本号(Nacos server.config.version) |\n| ab_group | string | 否 | A/B 实验分组标识,多个实验用逗号分隔 |\n| extra | jsonb | 否 | 扩展字段,存放事件特有数据 |\n\n命名规范:\n- event_name 采用 {module}.{action} 两段式命名\n- module 枚举值:account / character / cultivation / combat / economy / social / explore / event / ui / system / hotupdate / push\n- action 使用 snake_case,动词在前(如 battle_start、realm_breakthrough、item_trade)\n\n### 2.2 客户端埋点事件 Schema\n\n客户端埋点由 Cocos Creator 3.x SDK 在本地采集,通过批量上报服务发送。\n\n#### 2.2.1 UI 曝光事件\n\njson\n{\n \"event_name\": \"ui.impression\",\n \"extra\": {\n \"page_id\": \"main_hall\",\n \"component_id\": \"event_panel_world_pulse\",\n \"component_type\": \"panel\",\n \"position\": 0,\n \"duration_ms\": 3200,\n \"is_first_impression\": true\n }\n}\n\n\n| extra 字段 | 类型 | 说明 |\n|------------|------|------|\n| page_id | string | 页面/场景标识 |\n| component_id | string | 组件标识 |\n| component_type | string | 组件类型:panel / button / banner / popup / tab / list_item |\n| position | int | 列表中的位置索引(非列表组件为 0) |\n| duration_ms | int | 曝光停留时长(毫秒),阈值 >= 500ms 计为有效曝光 |\n| is_first_impression | bool | 是否为本次会话首次曝光 |\n\n#### 2.2.2 UI 点击事件\n\njson\n{\n \"event_name\": \"ui.click\",\n \"extra\": {\n \"page_id\": \"main_hall\",\n \"component_id\": \"btn_enter_combat\",\n \"component_type\": \"button\",\n \"click_position\": {\"x\": 360, \"y\": 640},\n \"target_action\": \"navigate_combat_scene\"\n }\n}\n\n\n| extra 字段 | 类型 | 说明 |\n|------------|------|------|\n| page_id | string | 所在页面标识 |\n| component_id | string | 被点击组件标识 |\n| component_type | string | 组件类型 |\n| click_position | object | 点击坐标 {x, y}(相对屏幕) |\n| target_action | string | 点击触发的目标行为 |\n\n#### 2.2.3 页面停留事件\n\njson\n{\n \"event_name\": \"ui.page_stay\",\n \"extra\": {\n \"page_id\": \"market_trade_hall\",\n \"stay_duration_ms\": 45000,\n \"enter_source\": \"main_hall_btn\",\n \"exit_action\": \"back_button\",\n \"scroll_depth_pct\": 80,\n \"interaction_count\": 12\n }\n}\n\n\n| extra 字段 | 类型 | 说明 |\n|------------|------|------|\n| page_id | string | 页面标识 |\n| stay_duration_ms | int | 停留时长(毫秒) |\n| enter_source | string | 进入来源 |\n| exit_action | string | 离开方式:back_button / navigate / background / session_end |\n| scroll_depth_pct | int | 页面滚动深度百分比 |\n| interaction_count | int | 页面内交互次数 |\n\n#### 2.2.4 异常崩溃事件\n\njson\n{\n \"event_name\": \"system.crash\",\n \"extra\": {\n \"crash_type\": \"js_exception\",\n \"error_message\": \"TypeError: Cannot read property 'id' of undefined\",\n \"stack_trace\": \"at CombatScene.update (combat.js:128:15)...\",\n \"memory_usage_mb\": 512,\n \"fps_avg\": 28,\n \"scene_id\": \"combat_scene\",\n \"hotupdate_version\": \"1.2.3.4\",\n \"is_after_hotupdate\": true\n }\n}\n\n\n| extra 字段 | 类型 | 说明 |\n|------------|------|------|\n| crash_type | string | 崩溃类型:js_exception / native_crash / oom / anr / webgl_lost |\n| error_message | string | 错误信息 |\n| stack_trace | string | 堆栈(截取前 2000 字符) |\n| memory_usage_mb | int | 崩溃时内存占用 |\n| fps_avg | int | 崩溃前 10 秒平均帧率 |\n| scene_id | string | 崩溃时所在场景 |\n| hotupdate_version | string | 当前热更版本 |\n| is_after_hotupdate | bool | 是否在热更后首次启动时崩溃 |\n\n#### 2.2.5 客户端性能事件\n\njson\n{\n \"event_name\": \"system.performance\",\n \"extra\": {\n \"scene_id\": \"main_hall\",\n \"fps_avg\": 58,\n \"fps_p5\": 45,\n \"load_time_ms\": 2300,\n \"draw_calls\": 120,\n \"memory_used_mb\": 380,\n \"battery_level\": 72,\n \"device_temp_celsius\": 38\n }\n}\n\n\n#### 2.2.6 热更事件\n\njson\n{\n \"event_name\": \"hotupdate.check\",\n \"extra\": {\n \"current_version\": \"1.2.2.3\",\n \"target_version\": \"1.2.3.4\",\n \"manifest_fetch_ms\": 450,\n \"manifest_fetch_result\": \"success\",\n \"diff_bundle_count\": 3,\n \"diff_total_bytes\": 2048000,\n \"download_duration_ms\": 8500,\n \"download_result\": \"success\",\n \"verify_result\": \"success\",\n \"apply_result\": \"success\",\n \"cdn_host\": \"cdn01.example.com\",\n \"gray_group\": \"5pct\"\n }\n}\n\n\n### 2.3 服务端埋点事件 Schema\n\n服务端埋点由 Nakama Go Plugin 在业务逻辑执行后异步写入,保证与业务事务的最终一致性。\n\n#### 2.3.1 通用服务端事件结构\n\n服务端事件在通用字段基础上,extra 字段承载业务上下文。服务端事件不经过客户端上报通道,而是直接写入 Kafka topic game_events_server。\n\n#### 2.3.2 服务端事件可靠性保证\n\n| 机制 | 说明 |\n|------|------|\n| 事务内写入 | 事件与业务数据在同一个 DB 事务中写入 event_outbox 表,保证不丢失 |\n| 异步投递 | 后台协程从 event_outbox 批量读取并投递到 Kafka,成功后标记 delivered = true |\n| 幂等消费 | event_id 全局唯一,ClickHouse 使用 ReplacingMergeTree 按 event_id 去重 |\n| 重试与死信 | Kafka 投递失败指数退避重试 3 次,仍失败则写入死信 topic game_events_dead_letter |\n\n---\n\n## 3. 核心业务埋点清单\n\n### 3.1 角色生命周期\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| account.register | 新账号注册完成 | platform, channel, referral_code | 服务端 |\n| account.login | 登录成功 | login_type(password/token/auto), offline_duration_hours, last_login_at, device_model | 服务端 |\n| account.logout | 登出/断线 | session_duration_ms, logout_type(active/timeout/crash/kick) | 服务端 |\n| character.create | 创角完成 | race_id, birth_world_tier, gender, appearance_config(jsonb), name_generation_method(random/manual) | 服务端 |\n| character.delete | 角色删除 | race_id, realm_tier, play_duration_total_hours, delete_reason | 服务端 |\n| account.churn_7d | 7日未登录(定时任务标记) | last_active_realm_tier, total_play_hours, last_session_duration_ms, last_active_race_id | 服务端 |\n| account.return | 流失后回归 | churn_days, last_active_realm_tier, return_source(push/ad/organic/friend), offline_settlement_value(jsonb) | 服务端 |\n\n### 3.2 修炼系统\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| cultivation.exp_gain | 修为/内力增长 | exp_amount, exp_source(afk/explore/event/manual_buff/quest), total_exp_after, world_tier | 服务端 |\n| cultivation.realm_breakthrough | 小境界突破 | from_realm_tier, to_realm_tier, from_minor, to_minor, is_success, success_rate, materials_consumed(jsonb), helper_count, random_seed | 服务端 |\n| cultivation.tribulation | 渡劫 | realm_tier, tribulation_type(normal/heart_devil/qi_deviation/chaos), base_rate, modified_rate, result(success/fail/backlash/death), helper_ids(array), san_before, san_after, penalties(jsonb), drops(jsonb) | 服务端 |\n| cultivation.world_break | 破界(进入新世界) | from_world_tier, to_world_tier, from_realm_tier, race_id, key_item_consumed, event_chain_id | 服务端 |\n| cultivation.manual_upgrade | 功法升层 | manual_id, from_layer, to_layer, is_success, material_cost(jsonb), domain, element | 服务端 |\n| cultivation.skill_learn | 技能顿悟/学习 | skill_id, skill_template_id, source(manual_buff/event/jade_slip/teaching), is_unique, rarity, domain, element | 服务端 |\n| cultivation.buff_set | 设置/切换加持功法 | manual_id, buff_slot, previous_manual_id | 服务端 |\n\n### 3.3 战斗系统\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| combat.battle_start | 战斗发起 | battle_type(expedition_pve/dungeon_pve/pvp/gvg/bounty/manhunt), world_tier, realm_tier, attacker_count, defender_count, trigger_source(afk/explore/event/bounty/duel) | 服务端 |\n| combat.battle_end | 战斗结束 | battle_id, battle_type, result(win/lose/draw/escape), duration_rounds, duration_ms, total_damage_dealt, total_damage_taken, skills_used(jsonb: [{skill_id, use_count, crit_count, element}]), element_reactions_triggered(jsonb), drops(jsonb), exp_gained, world_tier | 服务端 |\n| combat.skill_use | 战斗中使用技能 | battle_id, skill_id, skill_domain, skill_element, target_type(single/aoe/self), damage_dealt, is_crit, is_dodge, element_applied, atb_cost | 服务端 |\n| combat.element_reaction | 元素反应触发 | battle_id, reaction_type(如 water_fire / fire_wood / thunder_water), triggering_elements(array), bonus_damage, effect_type(damage/shield/control/dot) | 服务端 |\n| combat.escape | 逃跑 | battle_id, battle_type, is_success, escape_rate, attacker_realm_tier, defender_realm_tier, world_tier | 服务端 |\n| combat.quick_complete | 一键完成(挂机战斗) | battle_type, battle_count, total_drops(jsonb), total_exp, total_duration_ms, world_tier, death_count | 服务端 |\n| combat.pvp_duel | PVP 切磋发起 | attacker_id, defender_id, duel_type(formal/friendly/bounty), realm_tier_diff, world_tier | 服务端 |\n| combat.death | 角色死亡 | battle_id, death_type(pve/pvp/boss/tribulation), killer_id(nullable), equipment_durability_loss(jsonb), item_dropped(jsonb), currency_lost(jsonb), world_tier | 服务端 |\n\n### 3.4 经济系统\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| economy.currency_change | 任何货币变动(镜像 economy_audit_logs) | currency_code, flow_type(faucet/sink/transfer), reason_code, amount, balance_after, related_id, world_tier, entity_type(character/guild/system) | 服务端 |\n| economy.market_list | 交易行挂单 | order_id, item_id, item_category, currency_code, unit_price, quantity, total_price, world_tier | 服务端 |\n| economy.market_buy | 交易行购买 | order_id, item_id, item_category, currency_code, unit_price, quantity, total_price, tax_paid, buyer_realm_tier, seller_realm_tier, world_tier | 服务端 |\n| economy.auction_create | 创建拍卖 | auction_id, item_id, item_category, auction_type(official/organization), start_price, reserve_price, is_anonymous, risk_type, world_tier | 服务端 |\n| economy.auction_bid | 拍卖出价 | auction_id, bid_amount, is_auto_bid, bidder_count, current_highest, item_category, world_tier | 服务端 |\n| economy.auction_settle | 拍卖结算 | auction_id, result(sold/expired/robbed), final_price, seller_revenue, tax_collected, bid_count, item_category, is_blacklist_exposed, world_tier | 服务端 |\n| economy.recharge | 充值成功 | order_id, amount_rmb, currency_code, currency_amount, product_id, is_first_recharge, payment_channel, channel | 服务端 |\n| economy.item_trade | 玩家间直接交易 | trade_id, items_given(jsonb), items_received(jsonb), currency_exchanged(jsonb), trade_type(face_to_face/mail), world_tier | 服务端 |\n| economy.intelligence_order | 天机阁情报交易 | order_id, intel_type, price, currency_code, purchase_count, world_tier | 服务端 |\n\n### 3.5 社交系统\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| social.guild_create | 创建帮派/门派/家族 | guild_type(sect/clan/family/player_sect), guild_name, creator_realm_tier, creator_race_id, initial_member_count, world_tier | 服务端 |\n| social.guild_join | 加入组织 | guild_id, guild_type, join_method(apply/invite/recruit), member_count_after, player_realm_tier, world_tier | 服务端 |\n| social.guild_leave | 退出组织 | guild_id, guild_type, leave_reason(voluntary/kick/disband), membership_duration_days, world_tier | 服务端 |\n| social.team_form | 组队 | team_id, member_count, purpose(dungeon/explore/event/bounty), realm_tier_range(jsonb: {min, max}), world_tier | 服务端 |\n| social.relation_request | 社交关系请求 | relation_type(master_disciple/lover/sworn), requester_id, target_id, requester_realm_tier, target_realm_tier | 服务端 |\n| social.relation_establish | 关系确立 | relation_type, relation_id, player_a_id, player_b_id, world_tier | 服务端 |\n| social.relation_dissolve | 关系解除 | relation_type, relation_id, initiator_id, relation_duration_days, dissolve_reason(voluntary/conflict/system) | 服务端 |\n| social.mercenary_post | 佣兵委托发布 | contract_id, contract_type(bounty/guard/explore/craft), reward_currency, reward_amount, difficulty_tier, world_tier | 服务端 |\n| social.mercenary_accept | 佣兵委托接受 | contract_id, contract_type, acceptor_realm_tier, acceptor_mercenary_score, world_tier | 服务端 |\n| social.chat_message | 聊天消息 | channel_type(world/area/guild/team/private/system), message_length, has_link, has_image, world_tier | 服务端 |\n\n### 3.6 探索系统\n\n| event_name | 触发时机 | extra 关键字段 | 来源 |\n|------------|----------|---------------|------|\n| explore.map_unlock | 解锁新区域/地图 | map_id, map_name, world_tier, unlock_method(breakthrough/event/exploration/quest), race_id | 服务端 |\n| explore.region_enter | 进入区域 | region_id, region_name, from_region_id, world_tier, enter_method(walk/teleport/portal/event) | 服务端 |\n| explore.instance_enter | 进入副本 | instance_id, instance_type, difficulty_tier, party_size, world_tier, enter_cost(jsonb) | 服务端 |\n| explore.instance_complete | 副本完成 | instance_id, instance_type, result(complete/fail/abandon), duration_ms, death_count, drops(jsonb), exp_gained, party_size, world_tier | 服务端 |\n| explore.ruin_discover | 发现遗迹 | ruin_id, ruin_type, discovery_method(explore/event/intelligence), world_tier, realm_tier | 服务端 |\n| explore.random_event_trigger | 随机事件触发 | event_id, event_type(personal/regional/world/player_initiated), event_name, trigger_condition(afk/explore/breakthrough/trade/pvp), world_tier, player_realm_tier | 服务端 |\n| explore.random_event_choice | 随机事件分支选择 | event_id, event_type, branch_id, branch_option, outcome(success/fail/partial), rewards(jsonb), world_tier | 服务端 |\n| explore.random_event_complete | 随机事件完成 | event_id, event_type, result, total_participants, completion_rate, rewards(jsonb), duration_ms, world_tier | 服务端 |\n| explore.player_event_create | 玩家发起事件 | event_type(summon_secret/boss/ritual/bounty), cost(jsonb), target_world_tier, creator_realm_tier, guild_id(nullable) | 服务端 |\n\n---\n\n## 4. 数据管道架构\n\n### 4.1 整体架构\n\n\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 数据源层 │\n│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │\n│ │ Cocos Creator │ │ Nakama Go │ │ Gin 后台 │ │ Nacos 配置 │ │\n│ │ 客户端 SDK │ │ Plugin │ │ (GM/运营) │ │ 变更事件 │ │\n│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │\n└─────────┼─────────────────┼─────────────────┼─────────────────┼─────────────┘\n │ │ │ │\n ▼ ▼ ▼ ▼\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 采集与传输层 │\n│ ┌──────────────────────────────────────┐ ┌────────────────────────────┐ │\n│ │ 上报服务(HTTP/gRPC Gateway) │ │ event_outbox → Producer │ │\n│ │ - 批量接收客户端埋点 │ │ - 服务端事件可靠投递 │ │\n│ │ - 格式校验 + 转发 │ │ - 事务内写入,异步投递 │ │\n│ │ - 限流/鉴权 │ │ │ │\n│ └──────────────────┬───────────────────┘ └──────────────┬─────────────┘ │\n└─────────────────────┼────────────────────────────────────┼─────────────────┘\n │ │\n ▼ ▼\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 消息队列层(Kafka) │\n│ ┌───────────────────────────────────────────────────────────────────────┐ │\n│ │ Topic: game_events_client (客户端事件) │ │\n│ │ Topic: game_events_server (服务端事件) │ │\n│ │ Topic: game_events_dead_letter (死信队列) │ │\n│ │ Topic: game_metrics_realtime (实时指标聚合结果) │ │\n│ │ 分区策略: 按 player_id hash 分区,保证单用户事件有序 │ │\n│ └───────────────────────────────┬───────────────────────────────────────┘ │\n└──────────────────────────────────┼──────────────────────────────────────────┘\n │\n ┌──────────────┼──────────────┐\n ▼ ▼ ▼\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 计算层 │\n│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │\n│ │ Flink 实时计算 │ │ Flink 实时计算 │ │ 离线批处理 │ │\n│ │ Job-1: 事件清洗 │ │ Job-2: 实时指标 │ │ Hive/Spark │ │\n│ │ - 格式标准化 │ │ - DAU 在线 │ │ - T+1 报表 │ │\n│ │ - 异常过滤 │ │ - 战斗/经济 │ │ - 留存/LTV 计算 │ │\n│ │ - 字段补全 │ │ 实时聚合 │ │ - 经济健康度 │ │\n│ │ - 去重(event_id) │ │ - 告警阈值检测 │ │ - A/B 实验分析 │ │\n│ └────────┬─────────┘ └────────┬─────────┘ └──────────┬───────────────┘ │\n└───────────┼──────────────────────┼───────────────────────┼──────────────────┘\n │ │ │\n ▼ ▼ ▼\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 存储层 │\n│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │\n│ │ ClickHouse │ │ ClickHouse │ │ Hive / 数据湖 │ │\n│ │ (明细事件) │ │ (聚合指标) │ │ (离线宽表/报表) │ │\n│ │ MergeTree │ │ SummingMergeTree │ │ Parquet 格式 │ │\n│ │ TTL: 90 天 │ │ TTL: 180 天 │ │ 永久归档 │ │\n│ └──────────────────┘ └──────────────────┘ └──────────────────────────┘ │\n│ ┌──────────────────┐ ┌──────────────────┐ │\n│ │ PostgreSQL 16 │ │ Valkey │ │\n│ │ (业务数据/审计) │ │ (实时缓存/排行) │ │\n│ └──────────────────┘ └──────────────────┘ │\n└─────────────────────────────────────────────────────────────────────────────┘\n │\n ▼\n┌─────────────────────────────────────────────────────────────────────────────┐\n│ 应用层 │\n│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────────┐ │\n│ │ Grafana 实时大盘 │ │ 运营报表后台 │ │ 告警系统 │ │\n│ │ (Prometheus + │ │ (Superset/Metabase│ │ (AlertManager + │ │\n│ │ ClickHouse DS) │ │ + ClickHouse) │ │ 钉钉/飞书/邮件) │ │\n│ └──────────────────┘ └──────────────────┘ └──────────────────────────┘ │\n└─────────────────────────────────────────────────────────────────────────────┘\n\n\n### 4.2 Kafka Topic 设计\n\n| Topic | 分区数 | 副本数 | Key | 保留策略 | 说明 |\n|-------|--------|--------|-----|----------|------|\n| game_events_client | 32 | 3 | player_id | 7 天 | 客户端原始事件 |\n| game_events_server | 32 | 3 | player_id | 7 天 | 服务端原始事件 |\n| game_events_cleaned | 32 | 3 | player_id | 3 天 | Flink 清洗后事件 |\n| game_events_dead_letter | 8 | 3 | event_id | 30 天 | 处理失败的事件 |\n| game_metrics_realtime | 16 | 3 | metric_name | 1 天 | 实时聚合指标 |\n| game_alerts | 4 | 3 | alert_type | 7 天 | 告警事件 |\n\n### 4.3 ClickHouse 表设计\n\n#### 4.3.1 明细事件表\n\nsql\nCREATE TABLE IF NOT EXISTS game_events ON CLUSTER honghuang_cluster\n(\n event_id String,\n event_name LowCardinality(String),\n event_category LowCardinality(String), -- client / server\n event_date Date,\n timestamp DateTime64(3, 'UTC'),\n \n -- 玩家维度\n player_id String,\n character_id String DEFAULT '',\n device_id String DEFAULT '',\n session_id String DEFAULT '',\n \n -- 客户端维度\n client_version LowCardinality(String) DEFAULT '',\n server_id LowCardinality(String) DEFAULT '',\n platform LowCardinality(String) DEFAULT '',\n channel LowCardinality(String) DEFAULT '',\n network_type LowCardinality(String) DEFAULT '',\n \n -- 游戏维度\n world_tier UInt8 DEFAULT 0,\n realm_tier UInt8 DEFAULT 0,\n race_id LowCardinality(String) DEFAULT '',\n \n -- 实验与配置\n config_version LowCardinality(String) DEFAULT '',\n ab_group String DEFAULT '',\n \n -- 扩展数据\n extra String DEFAULT '{}', -- JSON 字符串\n \n -- 管道元数据\n _ingested_at DateTime DEFAULT now(),\n _source LowCardinality(String) DEFAULT '' -- client_sdk / server_plugin / gm_backend\n)\nENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/game_events', '{replica}')\nPARTITION BY toYYYYMMDD(event_date)\nORDER BY (event_name, event_date, cityHash64(player_id))\nTTL event_date + INTERVAL 90 DAY\nSETTINGS index_granularity = 8192;\n\n-- 物化视图:按 event_name 自动聚合\nCREATE MATERIALIZED VIEW game_events_by_name_mv ON CLUSTER honghuang_cluster\nTO game_events_by_name\nAS SELECT\n event_name,\n event_date,\n count() AS event_count,\n uniq(player_id) AS unique_players\nFROM game_events\nGROUP BY event_name, event_date;\n\n\n#### 4.3.2 实时指标聚合表\n\nsql\nCREATE TABLE IF NOT EXISTS realtime_metrics ON CLUSTER honghuang_cluster\n(\n metric_date Date,\n metric_hour UInt8,\n metric_name LowCardinality(String),\n dimension_key String, -- 如 world_tier=1, race_id=human 等\n metric_value Float64,\n sample_count UInt64\n)\nENGINE = SummingMergeTree((metric_value, sample_count))\nPARTITION BY toYYYYMMDD(metric_date)\nORDER BY (metric_name, metric_date, metric_hour, dimension_key)\nTTL metric_date + INTERVAL 180 DAY;\n\n\n### 4.4 Flink 实时计算 Job 设计\n\n| Job | 输入 Topic | 输出 | 职责 |\n|-----|-----------|------|------|\n| EventCleaningJob | game_events_client, game_events_server | game_events_cleaned, ClickHouse | 字段标准化、JSON 解析、异常值过滤、event_id 去重、字段补全(如从 Valkey 补全 realm_tier) |\n| RealtimeMetricsJob | game_events_cleaned | game_metrics_realtime, ClickHouse realtime_metrics | 实时计算 DAU、在线人数、战斗次数、经济流水等核心指标,1 分钟窗口聚合 |\n| AlertDetectionJob | game_metrics_realtime, game_events_cleaned | game_alerts, 告警通道 | 检测异常:崩溃率突增、经济异常波动、战斗胜率异常、在线人数骤降 |\n| EconomyMonitorJob | game_events_cleaned | ClickHouse, Grafana | 实时追踪各货币 faucet/sink 流量、净增发量、通胀率 |\n\n### 4.5 离线批处理\n\n| 任务 | 调度频率 | 计算引擎 | 输出 | 说明 |\n|------|----------|----------|------|------|\n| RetentionCalcJob | 每日 02:00 | Spark | Hive 留存宽表 | 次日/7日/30日留存,按 race_id/world_tier/channel 分维度 |\n| LTVCalcJob | 每日 03:00 | Spark | Hive LTV 表 | 按注册日期队列计算 LTV,分渠道/种族 |\n| EconomyHealthJob | 每日 04:00 | Spark | Hive 经济报表 | 各货币日净产出/消耗比、交易行均价趋势、通胀率、货币流通速度 |\n| ABTestAnalysisJob | 每日 05:00 | Spark | Hive 实验报表 | 各实验组核心指标对比、显著性检验结果 |\n| ChurnPredictionJob | 每周一 06:00 | Spark | Hive 流失预测表 | 基于近 14 天行为特征预测流失概率 |\n| PlayerPortraitJob | 每日 07:00 | Spark | Hive 用户画像表 | 玩家行为标签、付费倾向、活跃时段、偏好系统 |\n| DataQualityCheckJob | 每小时 | Spark SQL | 告警系统 | 数据完整性/延迟/异常值检测 |\n\n### 4.6 数据质量监控\n\n#### 4.6.1 完整性检查\n\n| 检查项 | 规则 | 告警阈值 | 检查频率 |\n|--------|------|----------|----------|\n| 事件丢失率 | 服务端事件数 / 业务操作数 | < 99% 即告警 | 每 5 分钟 |\n| 必填字段缺失 | event_id / event_name / player_id / timestamp 为空 | > 0.01% 告警 | 每小时 |\n| 客户端上报延迟 | 事件 timestamp 与 Kafka 接收时间差 | P99 > 30s 告警 | 每分钟 |\n| session 连续性 | session 内事件时间戳单调递增 | 异常 session > 1% 告警 | 每小时 |\n\n#### 4.6.2 延迟监控\n\n| 管道阶段 | SLA | 监控方式 |\n|----------|-----|----------|\n| 客户端 → 上报服务 | P99 < 3s | 上报服务 Prometheus metrics |\n| 上报服务 → Kafka | P99 < 1s | Kafka producer metrics |\n| Kafka → ClickHouse(实时) | P99 < 30s | Flink checkpoint lag |\n| Kafka → Hive(离线) | T+1 < 08:00 | Airflow DAG 监控 |\n| ClickHouse → 看板 | P99 < 5s | Grafana query duration |\n\n#### 4.6.3 异常值检测\n\n| 检测项 | 方法 | 说明 |\n|--------|------|------|\n| 事件量突变 | 同比/环比 ±50% 波动告警 | 区分正常高峰(版本更新)与异常 |\n| 单玩家事件频率 | 单玩家单小时事件数 > 均值 10 倍 | 可能为外挂/脚本 |\n| 经济数值异常 | 单笔交易金额 > 该货币 P99.9 | 可能为漏洞利用 |\n| 崩溃率突变 | 1 小时崩溃率 > 基线 3 倍 | 热更问题/新版本缺陷 |\n\n---\n\n## 5. 核心指标定义\n\n### 5.1 用户规模指标\n\n| 指标 | 定义 | 计算公式 | 统计周期 |\n|------|------|----------|----------|\n| DAU | 日活跃用户数 | COUNT(DISTINCT player_id) WHERE event_date = target_date AND event_name IN ('account.login', ...活跃事件集) | 自然日(UTC+8 00:00 切割) |\n| WAU | 周活跃用户数 | COUNT(DISTINCT player_id) WHERE event_date BETWEEN week_start AND week_end | 自然周(周一~周日) |\n| MAU | 月活跃用户数 | COUNT(DISTINCT player_id) WHERE event_month = target_month | 自然月 |\n| PCU | 峰值同时在线 | MAX(concurrent_online_count) 每分钟采样 | 实时 |\n| ACU | 平均同时在线 | AVG(concurrent_online_count) 每分钟采样 | 按日/周/月 |\n\n### 5.2 留存指标\n\n| 指标 | 定义 | 计算公式 | 说明 |\n|------|------|----------|------|\n| 次日留存率 | 注册次日登录的比例 | COUNT(DISTINCT 次日登录 player_id) / COUNT(DISTINCT 注册日 player_id) | 按注册日期队列(cohort) |\n| 7日留存率 | 注册第7日登录的比例 | 同上,偏移 7 天 | 含登录即算,不要求特定行为 |\n| 30日留存率 | 注册第30日登录的比例 | 同上,偏移 30 天 | 长期健康度指标 |\n| 加权留存 | 按登录天数加权 | Σ(第N日留存率 × 权重) / Σ权重 | 综合留存评分 |\n\n分维度:按 race_id、platform、channel、realm_tier、register_date 分组统计。\n\n### 5.3 付费指标\n\n| 指标 | 定义 | 计算公式 | 说明 |\n|------|------|----------|------|\n| LTV | 用户生命周期价值 | 总收入 / 总注册用户数(按注册队列,截至统计日) | 分 30/60/90/180 天 LTV |\n| ARPU | 每活跃用户平均收入 | 统计周期总收入 / 统计周期 DAU | 日/周/月 |\n| ARPPU | 每付费用户平均收入 | 统计周期总收入 / 统计周期付费用户数 | 日/周/月 |\n| 付费率 | 付费用户占比 | 付费用户数 / DAU | 日/周/月 |\n| 首充率 | 首次付费转化率 | 累计付费用户数 / 累计注册用户数 | 按注册队列 |\n| 复购率 | 二次付费率 | 付费 >= 2次用户数 / 付费 >= 1次用户数 | 按注册队列 |\n| 付费深度分布 | 各付费档位占比 | COUNT(*) WHERE amount_range GROUP BY amount_range | 6/30/68/128/328/648+ |\n\n### 5.4 系统参与率\n\n| 指标 | 定义 | 计算公式 | 说明 |\n|------|------|----------|------|\n| 修炼参与率 | 当日有修为增长的用户占比 | 有 exp_gain 事件的 player_id / DAU | 按 realm_tier 分组 |\n| 战斗参与率 | 当日有战斗的用户占比 | 有 battle_start 事件的 player_id / DAU | 按 battle_type 分组 |\n| 交易行渗透率 | 当日有交易行操作的用户占比 | 有 market_list 或 market_buy 事件的 player_id / DAU | |\n| 拍卖参与率 | 当日有拍卖操作的用户占比 | 有 auction_bid 事件的 player_id / DAU | |\n| 社交参与率 | 当日有社交行为的用户占比 | 有 social.* 事件的 player_id / DAU | 按 relation_type 分组 |\n| 探索参与率 | 当日有探索行为的用户占比 | 有 explore.* 事件的 player_id / DAU | 按 world_tier 分组 |\n| 副本参与率 | 当日进入副本的用户占比 | 有 instance_enter 事件的 player_id / DAU | 按 instance_type 分组 |\n| 世界事件参与率 | 世界事件期间参与用户占比 | 参与玩家数 / 事件期间在线 DAU | |\n\n### 5.5 经济健康度\n\n| 指标 | 定义 | 计算公式 | 告警阈值 |\n|------|------|----------|----------|\n| 通胀率 | 货币购买力变化 | (本周货币总量 - 上周货币总量) / 上周货币总量 | > 15%/周 告警 |\n| Faucet/Sink 比 | 产出/消耗比 | SUM(faucet) / ABS(SUM(sink)) | > 1.5 或 < 0.5 告警 |\n| 货币流通速度 | 货币转手频率 | 交易行成交额 / 货币存量 | 监控趋势 |\n| 交易行均价趋势 | 各类物品价格变化 | AVG(unit_price) GROUP BY item_category, week | 单品类周涨 > 50% 告警 |\n| 死亡修复 Sink / 总 Faucet | 死亡惩罚回收率 | death_penalty_sink / total_faucet | 验证高惩罚经济回收 |\n| 鸿蒙紫气净增发/充值额 | 高级货币平衡 | (总产出 - 总消耗) / 充值总额 | > 0.3 告警 |\n| 基尼系数 | 财富分布不均度 | 按货币持有量计算洛伦兹曲线基尼系数 | > 0.85 告警 |\n\n### 5.6 战斗平衡指标\n\n| 指标 | 定义 | 说明 |\n|------|------|------|\n| 各战斗类型胜率 | PVE/PVP 各类型胜率 | 按 realm_tier / race_id 分组 |\n| 技能使用频率 Top N | 最热门技能 | 按 realm_tier 分组 |\n| 元素反应触发率 | 各元素组合触发频率 | 评估元素系统深度 |\n| 逃跑成功率 | 各场景逃跑成功率 | 按 realm_tier 差距分组 |\n| 一键完成使用率 | 挂机战斗占比 | 区分手动/挂机 |\n| 平均战斗回合数 | 各类型战斗平均回合 | 过短/过长需调参 |\n\n---\n\n## 6. A/B 测试框架\n\n### 6.1 实验分组方案\n\n#### 6.1.1 分流策略\n\n\n分组算法:\n hash_value = SHA256(player_id + experiment_id) % 10000\n group = 根据 hash_value 落入预设区间\n\n示例:\n 实验 A:对照组 [0, 4999],实验组 [5000, 9999] → 50/50\n 实验 B:对照组 [0, 3299],实验A [3300, 6599],实验B [6600, 9999] → 33/33/34\n\n\n| 参数 | 说明 |\n|------|------|\n| 分流维度 | player_id 为主键(保证同一玩家始终在同一组) |\n| 分流层级 | 支持多层互斥:全服实验 → 境界层实验 → 种族实验 |\n| 互斥与正交 | 同一层级的实验互斥(一个玩家在同一层级只能属于一个实验);不同层级正交 |\n| 灰度比例 | 通过 Nacos 配置 ab_test.{experiment_id}.percent 控制,支持 1%~100% |\n| 白名单 | 支持按 player_id / device_id / channel 强制指定分组 |\n| 分流持久化 | 分组结果写入 player_ab_groups 表(player_id, experiment_id, group_id, assigned_at),避免重启后重新分配 |\n\n#### 6.1.2 实验配置表\n\nsql\nCREATE TABLE ab_experiments (\n id varchar(64) PRIMARY KEY,\n name varchar(128) NOT NULL,\n description text,\n hypothesis text,\n status varchar(16) NOT NULL DEFAULT 'draft', -- draft / running / paused / completed / archived\n experiment_type varchar(32) NOT NULL, -- feature_flag / ui_variant / param_tuning / content_test\n layer smallint NOT NULL DEFAULT 0, -- 互斥层\n traffic_percent numeric(5,2) NOT NULL DEFAULT 100.00, -- 参与流量百分比\n groups jsonb NOT NULL, -- [{group_id, name, description, percent, config_override}]\n primary_metric varchar(64) NOT NULL, -- 主要衡量指标\n secondary_metrics varchar(64)[], -- 次要指标\n guardrail_metrics varchar(64)[], -- 护栏指标(不能恶化的指标)\n min_sample_size int NOT NULL DEFAULT 1000, -- 最小样本量\n significance_level numeric(4,3) NOT NULL DEFAULT 0.05, -- 显著性水平 α\n power numeric(4,3) NOT NULL DEFAULT 0.80, -- 统计功效 1-β\n started_at timestamptz,\n ended_at timestamptz,\n created_by uuid,\n created_at timestamptz DEFAULT now(),\n updated_at timestamptz DEFAULT now()\n);\n\n\n### 6.2 指标显著性检验\n\n| 指标类型 | 检验方法 | 说明 |\n|----------|----------|------|\n| 比例型(留存率、付费率、参与率) | 卡方检验 / Z 检验 | 双侧检验,α = 0.05 |\n| 均值型(ARPU、LTV、战斗时长) | t 检验 / Mann-Whitney U | 方差不等时用 Welch t 检验 |\n| 分布型(付费深度、境界分布) | Kolmogorov-Snovov 检验 | 检验分布差异 |\n| 多重比较 | Bonferroni 校正 | 多实验组时 α' = α / k |\n\n决策规则:\n\n| 条件 | 决策 |\n|------|------|\n| 主要指标显著提升 + 护栏指标无显著恶化 + 样本量达标 | 推荐全量发布 |\n| 主要指标无显著差异 + 护栏指标无显著恶化 | 延长实验或放弃 |\n| 主要指标显著下降 或 护栏指标显著恶化 | 终止实验 |\n\n### 6.3 灰度实验与全量发布决策流程\n\n\n1. 实验设计\n ├─ 定义假设、指标、最小样本量、实验时长\n ├─ 计算所需样本量(基于 MDE + α + Power)\n └─ 配置实验表,状态 → draft\n\n2. 内部测试(1%~5%)\n ├─ Nacos 配置 ab_test.{id}.percent = 5\n ├─ 指定白名单测试人员\n ├─ 验证分流正确性、功能正确性、埋点完整性\n └─ 观察 24~48 小时,护栏指标无异常\n\n3. 小流量灰度(5%~20%)\n ├─ 扩大流量至 20%\n ├─ 持续监控护栏指标(崩溃率、经济异常、投诉量)\n ├─ 每日自动生成显著性检验报告\n └─ 观察 3~7 天\n\n4. 大流量验证(20%~50%)\n ├─ 扩大流量至 50%\n ├─ 主要指标开始具备统计显著性\n ├─ 进行细分维度分析(种族/境界/渠道)\n └─ 观察 7~14 天\n\n5. 全量决策\n ├─ 满足决策规则 → 发布全量 → 状态 → completed\n ├─ 不满足 → 延长实验或调整方案\n └─ 护栏恶化 → 立即回滚 → 状态 → paused\n\n6. 全量发布后观察\n ├─ 保持实验配置 7 天(可快速回滚)\n ├─ 监控全量后指标是否与实验期一致\n └─ 确认稳定后清理实验配置 → archived\n\n\n---\n\n## 7. 数据看板设计\n\n### 7.1 实时大盘\n\n访问路径:GM 后台 → 数据中心 → 实时大盘\n\n| 看板区域 | 展示内容 | 数据源 | 刷新频率 |\n|----------|----------|--------|----------|\n| 在线人数 | 当前在线 PCU、ACU 趋势(分/world_tier/race_id) | Valkey 在线集合 + Flink | 10 秒 |\n| 战斗监控 | 最近 1 分钟战斗次数、胜率、各类型占比 | ClickHouse realtime_metrics | 30 秒 |\n| 经济仪表盘 | 各货币实时 Faucet/Sink 流量、净增发曲线、交易行成交额 | ClickHouse realtime_metrics | 1 分钟 |\n| 崩溃率 | 近 1 小时崩溃率、各崩溃类型占比、与基线对比 | ClickHouse game_events | 1 分钟 |\n| 热更状态 | 各版本覆盖率、灰度组崩溃率、下载成功率 | ClickHouse + Nacos | 5 分钟 |\n| 世界事件 | 当前活跃世界事件、参与人数、进度 | PostgreSQL + Valkey | 30 秒 |\n\n### 7.2 运营日报\n\n自动生成:每日 09:00 (UTC+8) 通过 Spark 任务计算,推送到 GM 后台 + 钉钉群。\n\n| 板块 | 指标 | 对比维度 |\n|------|------|----------|\n| 用户规模 | DAU、新增、回流、PCU、ACU | 日环比、周同比 |\n| 留存 | 次日/7日/30日留存(按注册队列) | 近 30 天趋势 |\n| 付费 | 日收入、ARPU、ARPPU、付费率、首充数 | 日环比、周同比 |\n| 战斗 | 战斗次数、各类型胜率、平均回合数 | 按 battle_type |\n| 经济 | 各货币净增发、交易行成交额、拍卖成交额 | 周趋势 |\n| 社交 | 新建帮派数、新关系数、佣兵委托完成数 | 日环比 |\n| 探索 | 副本完成数、随机事件参与率、新地图解锁数 | 按 world_tier |\n| 异常 | 崩溃率、举报数、封禁数、经济告警数 | 阈值标记 |\n\n### 7.3 异常告警看板\n\n| 告警级别 | 触发条件 | 通知方式 | 处理 SLA |\n|----------|----------|----------|----------|\n| P0 - 紧急 | 崩溃率 > 5%、在线人数骤降 > 50%、经济漏洞(单笔异常增发)、数据管道中断 | 电话 + 钉钉 + 短信 | 15 分钟内响应 |\n| P1 - 严重 | 崩溃率 > 2%、经济 Faucet/Sink 比 > 2.0、热更失败率 > 5%、配置版本 skew > 1% | 钉钉 + 邮件 | 30 分钟内响应 |\n| P2 - 警告 | 次日留存下降 > 5pp、交易行均价周涨 > 50%、单玩家异常高频操作、事件参与率骤降 | 钉钉 | 2 小时内响应 |\n| P3 - 提醒 | 数据延迟 > SLA、非核心指标波动、灰度组指标微偏 | 邮件 | 24 小时内响应 |\n\n告警收敛:同一条告警 5 分钟内不重复发送;连续 3 次同类告警自动升级一级。\n\n---\n\n## 8. 数据安全与合规\n\n### 8.1 数据脱敏规则\n\n| 数据类型 | 脱敏方式 | 说明 |\n|----------|----------|------|\n| player_id | 保留(业务主键) | 分析场景使用真实 ID |\n| device_id | SHA-256 哈希 | 不存储原始设备 ID |\n| ip_address | 脱敏为 IP 段(如 192.168.1.xxx) | 仅在安全审计场景保留完整 IP |\n| 支付信息 | 不采集 | 仅存储支付渠道订单号和金额 |\n| 聊天内容 | 不进入数据管道 | 仅统计消息长度和频道类型 |\n| 真实姓名/手机号 | 不采集 | 注册使用第三方 OAuth,不收集个人信息 |\n| 角色名 | 可选脱敏 | 报表中可展示,对外数据需脱敏 |\n| appearance_config | 不进入数据管道 | 外观配置仅用于客户端展示 |\n\n### 8.2 数据保留策略\n\n| 数据类别 | 热存储(ClickHouse) | 温存储(Hive/数据湖) | 冷存储(归档) | 总保留 |\n|----------|---------------------|---------------------|---------------|--------|\n| 明细事件 | 90 天 | 永久(Parquet) | - | 永久 |\n| 聚合指标 | 180 天 | 永久 | - | 永久 |\n| 经济审计 | 与 PostgreSQL 对齐(12 个月) | 永久 | 3 年后压缩归档 | 永久 |\n| 战斗日志 | 与 PostgreSQL 对齐(8 周) | 6 个月 | 1 年后删除 | 18 个月 |\n| 设备指纹哈希 | 90 天 | 1 年 | 删除 | 1 年 |\n| IP 地址 | 30 天 | 90 天 | 删除 | 90 天 |\n| A/B 实验数据 | 与实验周期对齐 | 永久 | - | 永久 |\n| 崩溃日志 | 90 天 | 1 年 | 删除 | 1 年 |\n\n### 8.3 GDPR / 个保法合规\n\n| 合规要求 | 实施方案 |\n|----------|----------|\n| 数据最小化 | 仅采集业务分析必需字段;不采集聊天内容、通讯录、位置信息 |\n| 知情同意 | 首次启动弹出隐私政策,明确告知数据采集范围;用户可选择\"仅必要\"或\"完整体验\" |\n| 数据可携 | 提供 GM 后台\"数据导出\"功能,玩家可申请导出个人数据(JSON 格式) |\n| 被遗忘权 | 角色删除后 30 天内可撤回;30 天后触发异步清理任务,从数据管道中删除该玩家所有事件(通过 player_id 标记删除) |\n| 数据访问控制 | 数据管道访问需 RBAC 授权;ClickHouse 按角色限制查询范围;生产数据不可导出到个人设备 |\n| 跨境传输 | 数据存储于中国大陆服务器(阿里云/腾讯云);不做跨境同步(如需海外部署,独立数据管道) |\n| 审计日志 | 所有数据查询/导出操作记录到 data_access_audit_logs,保留 24 个月 |\n| 儿童保护 | 未满 16 周岁用户需监护人同意;采集 is_minor 标记,限制付费额度(参考防沉迷政策) |\n\n### 8.4 数据访问权限矩阵\n\n| 角色 | 明细事件 | 聚合指标 | 经济审计 | 个人信息 | GM 操作 |\n|------|----------|----------|----------|----------|---------|\n| 数据工程师 | 读写 | 读写 | 只读 | 不可访问 | 不可访问 |\n| 数值策划 | 只读 | 只读 | 只读 | 不可访问 | 不可访问 |\n| 运营 | 不可访问 | 只读 | 只读 | 脱敏后可读 | 只读 |\n| 客服 | 不可访问 | 不可访问 | 不可访问 | 授权后可读 | 受限操作 |\n| 管理层 | 不可访问 | 只读(看板) | 只读(看板) | 不可访问 | 不可访问 |\n\n---\n\n## 9. 已确认决策记录表\n\n| # | 决策内容 | 依据 | 日期 | 确认人 |\n|---|----------|------|------|--------|\n| D01 | 客户端和服务端埋点共用同一套通用字段 Schema,通过 event_category 字段区分来源 | 统一数据模型,降低管道复杂度 | 2026-07-02 | - |\n| D02 | 服务端事件通过 event_outbox 表保证事务一致性,异步投递到 Kafka | 业务事务与埋点解耦,避免阻塞主流程;outbox 保证不丢失 | 2026-07-02 | - |\n| D03 | 客户端事件批量上报(攒 20 条或 10 秒),通过独立上报服务网关接入 | 减少网络请求频率;独立网关隔离埋点流量与游戏逻辑流量 | 2026-07-02 | - |\n| D04 | ClickHouse 作为明细事件和实时聚合指标的主存储,Hive/数据湖作为离线报表存储 | ClickHouse 支持高并发实时查询;Hive 适合大规模离线分析和永久归档 | 2026-07-02 | - |\n| D05 | 经济监控指标直接镜像 economy_audit_logs 表设计,不额外定义事件结构 | 复用 TDD-04 已定义的经济审计 Schema,减少字段映射开销 | 2026-07-02 | - |\n| D06 | A/B 测试分流以 player_id + experiment_id 的 SHA256 哈希为基础 | 保证同一玩家分组稳定;不依赖第三方分流服务,减少外部依赖 | 2026-07-02 | - |\n| D07 | 数据保留策略按数据敏感度分级:明细事件 90 天热存 + 永久归档,个人信息最长 1 年 | 平衡分析需求与合规要求;个保法要求数据最小化和限期存储 | 2026-07-02 | - |\n| D08 | 崩溃和性能事件阈值与 PRD-03 §2.4 灰度策略对齐:崩溃率 > 5% 自动暂停灰度 | 复用 PRD-03 已定义的灰度回滚阈值,保持一致性 | 2026-07-02 | - |\n| D09 | 实时指标计算使用 Flink 1 分钟滚动窗口,延迟 SLA P99 < 30 秒 | 满足实时大盘和告警的时效性要求 | 2026-07-02 | - |\n| D10 | 游戏时间(现实:游戏 = 1:3)不作为埋点时间基准,所有埋点统一使用现实时间(UTC 毫秒) | 避免游戏时间与现实时间换算混乱;游戏时间仅在业务字段中体现 | 2026-07-02 | - |\n| D11 | event_name 采用 {module}.{action} 两段式命名,module 枚举值固定为 12 个 | 统一命名规范,便于路由、权限和看板分组 | 2026-07-02 | - |\n| D12 | Kafka 按 player_id hash 分区,保证单用户事件有序 | Flink 按用户做 session 窗口计算时需要事件有序 | 2026-07-02 | - |\n\n---\n\n## 10. 验收标准\n\n| # | 验收条目 | 测试方法 | 通过条件 |\n|---|----------|----------|----------|\n| 1 | 客户端 SDK 能正确采集 UI 曝光/点击/停留/崩溃事件,并按批量策略上报 | 模拟用户操作,抓包验证上报请求格式和频率 | 上报格式符合 §2.1 + §2.2 定义;批量上报间隔 <= 10 秒;事件到达 Kafka 延迟 P99 < 3 秒 |\n| 2 | 服务端事件通过 event_outbox 在业务事务中写入,并异步投递到 Kafka | 触发战斗/交易/突破等业务操作,验证 outbox 写入和 Kafka 消费 | 事件与业务数据在同一事务中;Kafka 消费成功率 > 99.99%;失败事件进入死信队列 |\n| 3 | Flink 清洗 Job 能正确去重、补全字段、标准化格式,并写入 ClickHouse | 向 Kafka 注入重复/缺字段/格式异常的事件,验证 ClickHouse 写入结果 | 重复事件被去重;缺字段被补全或标记;异常格式被过滤并记录 |\n| 4 | 实时指标(DAU/在线人数/战斗次数/经济流水)在 Flink 中以 1 分钟窗口聚合,延迟 < 30 秒 | 对比 Flink 聚合结果与 ClickHouse 明细查询结果 | 偏差 < 1%;端到端延迟 P99 < 30 秒 |\n| 5 | 经济监控指标与 economy_audit_logs 数据一致 | 对比同一时间段 ClickHouse 经济指标与 PostgreSQL economy_audit_logs 汇总 | 各货币 Faucet/Sink 金额偏差 < 0.01% |\n| 6 | A/B 测试分流稳定且均匀 | 对 10 万模拟用户执行分流算法,统计各组分布 | 各组偏差 < 1%;同一用户多次分流结果一致 |\n| 7 | 告警系统在异常条件触发后 1 分钟内发送通知 | 模拟崩溃率突增、经济异常波动,验证告警触发 | P0 告警 1 分钟内发送;P1 告警 3 分钟内发送 |\n| 8 | 运营日报在每日 09:00 前自动生成并推送 | 检查连续 7 天日报生成时间和内容完整性 | 每日 09:00 前完成;所有指标有值(无空缺);与手动查询 ClickHouse 结果一致 |\n| 9 | 数据保留策略自动执行:90 天前的明细事件从 ClickHouse 热存储中清理 | 检查 ClickHouse TTL 配置和实际数据清理情况 | 超过 TTL 的分区被自动删除;Hive 归档数据完整 |\n| 10 | 数据脱敏规则正确执行:IP 地址脱敏、设备 ID 哈希、聊天内容不进入管道 | 检查 ClickHouse 中存储的 IP 和 device_id 字段;验证聊天事件仅含统计字段 | IP 为脱敏格式;device_id 为哈希值;无聊天原始内容 |\n| 11 | 数据质量监控能检测事件丢失率、延迟、异常值 | 人为制造数据丢失(断开上报服务 5 分钟),验证告警 | 完整性告警在丢失发生后 5 分钟内触发 |\n| 12 | 核心指标看板(DAU/留存/LTV/ARPU)与手动 SQL 查询结果一致 | 选取 7 天数据,手动编写 SQL 计算并与看板对比 | 偏差 < 0.1%(精度差异除外) |\n\n---\n\n## 11. 版本记录\n\n| 版本 | 日期 | 修订内容 | 作者 |\n|------|------|----------|------|\n| v1.0 | 2026-07-02 | 初始版本:埋点 Schema 设计、核心业务埋点清单(角色/修炼/战斗/经济/社交/探索)、数据管道架构(Kafka + Flink + ClickHouse + Hive)、核心指标定义(DAU/留存/LTV/ARPU/经济健康度)、A/B 测试框架、数据看板设计、数据安全合规 | - |\n\n---\n\n> 设计原则:本文档继承 PRD-01 核心约束——无任务系统、无赛季重置、概率/机遇驱动。所有埋点设计均服务于理解玩家行为、保障经济健康、验证系统设计假设三大目标。数据采集遵循最小化原则,不侵入玩家隐私,不为运营 KPI 服务而过度采集。\n``\n\n---\n\nThis completes the TDD-10 document. The document is fully consistent with the existing project architecture, referencing:\n\n- **TDD-04** database tables (economy_audit_logs,battles,battle_logs,tribulation_records,market_orders,auctions) as the source of truth for economic and combat events\n- **TDD-05** API design for understanding server-side event trigger points\n- **TDD-06** offline settlement system for AFK-related metrics\n- **TDD-07** anti-cheat model for server-authoritative event validation\n- **TDD-08** GM backend architecture for dashboard integration\n- **PRD-03** hot update monitoring metrics and gray release thresholds\n- **PRD-01/PRD-02** game mechanics (9 realms, 19 races, 3 factions, ATB combat, 1:3 time ratio)\n\nSince I am in read-only mode, please copy the content above and save it to/Users/xuqinmin/Projects/NewsProject/lawless/docs/技术文档/TDD-10-数据埋点与分析设计.md`."}],"usage":{"input_tokens":3459,"cache_creation_input_tokens":0,"cache_read_input_tokens":33088,"output_tokens":16488,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"stop_reason":"end_turn","stop_details":null},"attributionAgent":"Explore","type":"assistant","uuid":"96eb2830-871f-42dc-863a-6b8bbde75ac5","timestamp":"2026-07-02T00:17:14.520Z","userType":"external","entrypoint":"cli","cwd":"/Users/xuqinmin/Projects/NewsProject/lawless","sessionId":"e62c4dc2-f8c6-4de1-bb50-390f2075d2b9","version":"2.1.197","gitBranch":"main"}