ソースを参照

feat(user_content_weight): implement user content weight system with database schema changes and recommendation service updates

liaoxg 1 週間 前
親
コミット
cb458fa788

+ 25 - 12578
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -1,12578 +1,25 @@
-package com.etotem.cfc.config;
-
-import com.etotem.cfc.mapper.*;
-import javax.annotation.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import lombok.var;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StreamUtils;
-
-import java.nio.charset.StandardCharsets;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-@Component
-public class DatabaseInitializer implements CommandLineRunner {
-
-    private static final Logger log = LoggerFactory.getLogger(DatabaseInitializer.class);
-
-    /** 迁移是否已全部完成(供定时任务判断,避免启动期时序竞态) */
-    private static volatile boolean migrationsComplete = false;
-
-    public static boolean isMigrationsComplete() {
-        return migrationsComplete;
-    }
-
-    @Resource
-    private JdbcTemplate jdbcTemplate;
-
-    @Resource
-    private ResourceLoader resourceLoader;
-
-    @Value("${app.init-test-data:false}")
-    private boolean initTestData;
-
-    @Override
-    public void run(String... args) throws Exception {
-        log.info("开始初始化数据库...");
-
-        // 1. 检查并创建数据库
-        initializeDatabase();
-
-        // 2. 检查并创建表
-        initializeTables();
-
-        // 3. 执行数据库迁移(添加新列)
-        runMigrations();
-
-        // 4. 初始化食品相关表(DDL,始终执行)
-        initFoodTables();
-
-        // 5. 初始化测试/种子数据(仅测试/开发环境)
-        if (initTestData) {
-            log.info("init-test-data=true,开始初始化测试/种子数据...");
-            initializeDefaultData();
-            log.info("测试/种子数据初始化完成!");
-        } else {
-            log.info("init-test-data=false,跳过测试/种子数据初始化(生产模式)");
-        }
-
-        migrationsComplete = true;
-        log.info("数据库初始化完成!");
-    }
-
-    private void initializeDatabase() {
-        try {
-            // 尝试连接数据库,如果不存在则创建
-            jdbcTemplate.execute("CREATE DATABASE IF NOT EXISTS zxyj DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
-            log.info("数据库检查完成");
-        } catch (Exception e) {
-            log.warn("创建数据库失败: {}", e.getMessage());
-        }
-    }
-
-    private void initializeTables() {
-        try {
-            org.springframework.core.io.Resource resource = resourceLoader.getResource("classpath:schema.sql");
-            String content;
-            try (java.io.InputStream is = resource.getInputStream()) {
-                content = new String(StreamUtils.copyToByteArray(is), StandardCharsets.UTF_8);
-            }
-
-            // Remove SQL single-line comments
-            content = content.replaceAll("(?m)^\\s*--.*$", "");
-
-            // 提取所有 CREATE TABLE IF NOT EXISTS 语句。
-            // 不能用非贪婪 ".*?;" 匹配:COMMENT 字符串字面量中可能含分号(如
-            // task_reminder_config.offset_minutes 的注释 "截止前N分钟; after_timeout..."),
-            // 会被提前截断导致语句不完整而建表失败。此处按字符扫描,跳过引号内部的分号。
-            List<String> createTableSQLs = new ArrayList<>();
-            Pattern createTableHead = Pattern.compile(
-                    "^\\s*CREATE\\s+TABLE\\s+IF\\s+NOT\\s+EXISTS\\b", Pattern.CASE_INSENSITIVE);
-            StringBuilder stmt = new StringBuilder();
-            boolean inSingleQuote = false;
-            boolean inBacktick = false;
-            for (int i = 0; i < content.length(); i++) {
-                char c = content.charAt(i);
-                if (c == '\'' && !inBacktick) {
-                    if (inSingleQuote && i + 1 < content.length() && content.charAt(i + 1) == '\'') {
-                        stmt.append("''");
-                        i++;
-                        continue;
-                    }
-                    inSingleQuote = !inSingleQuote;
-                    stmt.append(c);
-                } else if (c == '`' && !inSingleQuote) {
-                    inBacktick = !inBacktick;
-                    stmt.append(c);
-                } else if (c == ';' && !inSingleQuote && !inBacktick) {
-                    String sql = stmt.toString().trim();
-                    if (!sql.isEmpty() && createTableHead.matcher(sql).find()) {
-                        createTableSQLs.add(sql + ";");
-                    }
-                    stmt.setLength(0);
-                } else {
-                    stmt.append(c);
-                }
-            }
-
-            log.info("从 schema.sql 加载了 {} 个建表语句", createTableSQLs.size());
-
-            for (String sql : createTableSQLs) {
-                try {
-                    jdbcTemplate.execute(sql);
-                } catch (Exception e) {
-                    log.warn("创建表失败: {}", e.getMessage());
-                }
-            }
-
-            log.info("数据表检查完成");
-        } catch (Exception e) {
-            log.error("读取 schema.sql 失败", e);
-        }
-    }
-
-    private void runMigrations() {
-        // 迁移1: 任务表添加执行者字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN executor_type ENUM('child', 'parent') DEFAULT 'child' COMMENT '执行者类型'");
-            log.info("已添加executor_type列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN executor_id BIGINT COMMENT '执行者ID'");
-            log.info("已添加executor_id列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD INDEX idx_executor (executor_type, executor_id)");
-            log.info("已添加idx_executor索引到tasks表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移2: 用户表添加角色和积分字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN roles VARCHAR(100) COMMENT '角色列表'");
-            log.info("已添加roles列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN total_points INT DEFAULT 0 COMMENT '家长总积分'");
-            log.info("已添加total_points列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_roles (roles(20))");
-            log.info("已添加idx_roles索引到users表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移3: users表添加新字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN id_card VARCHAR(18) COMMENT '身份证号'");
-            log.info("已添加id_card列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN real_name VARCHAR(50) COMMENT '真实姓名'");
-            log.info("已添加real_name列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN phone VARCHAR(11) COMMENT '手机号'");
-            log.info("已添加phone列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN birthday DATE COMMENT '生日'");
-            log.info("已添加birthday列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN gender ENUM('male', 'female') COMMENT '性别'");
-            log.info("已添加gender列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_phone (phone)");
-            log.info("已添加idx_phone索引到users表");
-} catch (Exception e) {
-
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN role ENUM('parent', 'child', 'teacher') NOT NULL");
-            log.info("已更新users.role字段支持teacher角色");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        // 迁移5.1: 修改users.role为支持admin
-        try {
-            jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN role ENUM('parent', 'child', 'teacher', 'admin') NOT NULL");
-            log.info("已更新users.role字段支持admin角色");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        // 迁移5.2: 确保管理员角色为admin(修复旧数据遗留问题)
-        try {
-            int updated = jdbcTemplate.update("UPDATE admins SET role = 'admin' WHERE username = 'admin'");
-            if (updated > 0) {
-                log.info("已修正管理员角色为admin");
-            }
-        } catch (Exception e) {
-            // 更新失败,忽略错误
-        }
-
-        // 迁移6: 创建streets表(街道地址维度表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS streets (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "province VARCHAR(50) COMMENT '省份', " +
-                    "province_code VARCHAR(20) COMMENT '省份编码', " +
-                    "city VARCHAR(50) COMMENT '城市', " +
-                    "city_code VARCHAR(20) COMMENT '城市编码', " +
-                    "district VARCHAR(50) COMMENT '区县', " +
-                    "district_code VARCHAR(20) COMMENT '区县编码', " +
-                    "street VARCHAR(100) COMMENT '街道', " +
-                    "street_code VARCHAR(20) COMMENT '街道编码', " +
-                    "full_name VARCHAR(200) COMMENT '完整地址', " +
-                    "level INT COMMENT '层级:1省2市3区4街道', " +
-                    "parent_id BIGINT COMMENT '父级ID', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_level (level), " +
-                    "INDEX idx_parent_id (parent_id), " +
-                    "INDEX idx_street_code (street_code), " +
-                    "INDEX idx_full_name (full_name(50))" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建streets表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移7: families表添加地址字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN street_id BIGINT COMMENT '街道ID'");
-            log.info("已添加street_id列到families表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN province VARCHAR(50) COMMENT '省份'");
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN city VARCHAR(50) COMMENT '城市'");
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN district VARCHAR(50) COMMENT '区县'");
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN street VARCHAR(100) COMMENT '街道'");
-            log.info("已添加地址字段到families表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD INDEX idx_street_id (street_id)");
-            log.info("已添加idx_street_id索引到families表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移7b: families表添加teacher_id和creator_id字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN teacher_id BIGINT COMMENT '绑定的成长规划师ID'");
-            log.info("已添加teacher_id列到families表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN creator_id BIGINT COMMENT '家庭创建者ID'");
-            log.info("已添加creator_id列到families表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移8: teachers表添加地址字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE teachers ADD COLUMN street_id BIGINT COMMENT '街道ID'");
-            log.info("已添加street_id列到teachers表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE teachers ADD COLUMN province VARCHAR(50) COMMENT '省份'");
-            jdbcTemplate.execute("ALTER TABLE teachers ADD COLUMN city VARCHAR(50) COMMENT '城市'");
-            jdbcTemplate.execute("ALTER TABLE teachers ADD COLUMN district VARCHAR(50) COMMENT '区县'");
-            jdbcTemplate.execute("ALTER TABLE teachers ADD COLUMN street VARCHAR(100) COMMENT '街道'");
-            log.info("已添加地址字段到teachers表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE teachers ADD INDEX idx_street_id (street_id)");
-            log.info("已添加idx_street_id索引到teachers表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移9: users表添加成长规划师相关字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN teacher_no VARCHAR(50) COMMENT '成长规划师证书号'");
-            log.info("已添加teacher_no列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN teacher_photo VARCHAR(500) COMMENT '成长规划师照片'");
-            log.info("已添加teacher_photo列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN certificate_image VARCHAR(500) COMMENT '成长规划师证书照片'");
-            log.info("已添加certificate_image列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN teacher_status VARCHAR(20) DEFAULT 'pending' COMMENT '成长规划师审核状态'");
-            log.info("已添加teacher_status列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_teacher_status (teacher_status)");
-            log.info("已添加idx_teacher_status索引到users表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移10: users表添加teacherFamilyIds字段(成长规划师关联的家庭ID列表)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN teacher_family_ids VARCHAR(500) COMMENT '成长规划师关联的家庭ID列表(逗号分隔)'");
-            log.info("已添加teacher_family_ids列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移11: families表添加teacherId字段(绑定的成长规划师ID)
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD COLUMN teacher_id BIGINT COMMENT '绑定的成长规划师ID'");
-            log.info("已添加teacher_id列到families表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE families ADD INDEX idx_teacher_id (teacher_id)");
-            log.info("已添加idx_teacher_id索引到families表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        // 迁移12: 创建 teacher_messages 表(家长咨询成长规划师)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS teacher_messages (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "parent_id BIGINT NOT NULL COMMENT '家长用户ID', " +
-                    "teacher_id BIGINT NOT NULL COMMENT '成长规划师用户ID', " +
-                    "content TEXT NOT NULL COMMENT '消息内容', " +
-                    "reply_content TEXT COMMENT '回复内容', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态:pending(待回复)/replied(已回复)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "replied_at DATETIME COMMENT '回复时间', " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_teacher_id (teacher_id), " +
-                    "INDEX idx_parent_id (parent_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建teacher_messages表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-// 迁移13: admin_task_templates表添加teacher_id字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN teacher_id BIGINT COMMENT '成长规划师ID'");
-            log.info("已添加teacher_id列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移13b: admin_task_templates表添加新字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN complete_types VARCHAR(100) COMMENT '完成方式JSON'");
-            log.info("已添加complete_types列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN duration INT COMMENT '预计完成时长(分钟)'");
-            log.info("已添加duration列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN review_type VARCHAR(20) COMMENT '审核人类型: creator/parent/teacher/ai'");
-            log.info("已添加review_type列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN task_type VARCHAR(20) COMMENT '任务性质: onetime/recurring'");
-            log.info("已添加task_type列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN frequency VARCHAR(20) COMMENT '频率: daily/weekly/monthly'");
-            log.info("已添加frequency列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN max_frequency INT COMMENT '周期内最多完成次数'");
-            log.info("已添加max_frequency列到admin_task_templates表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移14: rewards表child_id字段允许NULL(模板奖励不需要child_id)
-        try {
-            jdbcTemplate.execute("ALTER TABLE rewards MODIFY COLUMN child_id BIGINT NULL COMMENT '孩子ID,模板奖励为NULL'");
-            log.info("已修改rewards.child_id字段允许NULL");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        // 迁移15: admins表添加缺失列
-        try {
-            jdbcTemplate.execute("ALTER TABLE admins ADD COLUMN nickname VARCHAR(50) DEFAULT NULL AFTER password");
-            log.info("已添加nickname列到admins表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admins ADD COLUMN email VARCHAR(100) DEFAULT NULL AFTER phone");
-            log.info("已添加email列到admins表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE admins MODIFY COLUMN status VARCHAR(20) DEFAULT 'active'");
-            log.info("已修改admins.status字段类型");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        // 迁移16: 创建用户操作日志表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_operation_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT \'用户ID\', " +
-                    "nickname VARCHAR(50) COMMENT \'用户昵称\', " +
-                    "operation_type VARCHAR(20) NOT NULL COMMENT \'操作类型: login/logout/create/update/delete/query等\', " +
-                    "description VARCHAR(500) COMMENT \'操作描述\', " +
-                    "request_path VARCHAR(200) COMMENT \'请求路径\', " +
-                    "request_method VARCHAR(10) COMMENT \'请求方法\', " +
-                    "request_params TEXT COMMENT \'请求参数(脱敏)\', " +
-                    "response_status INT COMMENT \'响应状态码\', " +
-                    "client_ip VARCHAR(50) COMMENT \'客户端IP\', " +
-                    "user_agent VARCHAR(500) COMMENT \'User-Agent\', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_operation_type (operation_type), " +
-                    "INDEX idx_created_at (created_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建user_operation_logs表");
-        } catch (Exception e) {
-// 表已存在,忽略错误
-        }
-
-// 迁移16: tasks表添加bonus_rule字段(POINT-002: 超额积分规则)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN bonus_rule VARCHAR(500) COMMENT \'超额积分规则JSON\'");
-            log.info("已添加bonus_rule列到tasks表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移17: tasks表添加points_expire_days字段(POINT-009: 积分有效期)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN points_expire_days INT DEFAULT 0 COMMENT \'积分有效期天数,0表示永久有效\'");
-            log.info("已添加points_expire_days列到tasks表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移18: points_log表添加expire_at字段(POINT-009: 积分有效期)
-        try {
-            jdbcTemplate.execute("ALTER TABLE points_log ADD COLUMN expire_at DATE COMMENT \'积分过期日期\'");
-            log.info("已添加expire_at列到points_log表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移19: points_log表添加expired字段(POINT-009: 过期状态标记)
-        try {
-            jdbcTemplate.execute("ALTER TABLE points_log ADD COLUMN expired TINYINT DEFAULT 0 COMMENT \'是否已过期: 0否1是\'");
-            log.info("已添加expired列到points_log表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-// 迁移20: tasks表添加template_id字段(TASK-004: 重复任务模板追踪)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN template_id BIGINT COMMENT \'模板任务ID\'");
-            log.info("已添加template_id列到tasks表");
-        } catch (Exception e) {
-// 列已存在,忽略错误
-        }
-
-        // 迁移21: tasks表添加is_template字段(TASK-004: 标记模板任务)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN is_template TINYINT DEFAULT 0 COMMENT '是否为模板任务'");
-            log.info("已添加is_template列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移22: 修复tasks表child_id和deadline允许NULL(支持多孩子和家长任务)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks MODIFY COLUMN child_id BIGINT NULL COMMENT '执行者ID'");
-            log.info("已修改tasks.child_id允许NULL");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks MODIFY COLUMN deadline DATETIME NULL COMMENT '截止时间'");
-            log.info("已修改tasks.deadline允许NULL");
-        } catch (Exception e) {
-            // 修改失败,忽略错误
-        }
-
-        // 迁移23: tasks表添加新字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN task_type VARCHAR(20) COMMENT '任务性质: onetime/recurring'");
-            log.info("已添加task_type列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移24: tasks表添加parent_task_id字段(购买任务→每日使用子任务链;子任务在父任务完成前不显示)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN parent_task_id BIGINT COMMENT '父任务ID(购买任务→每日使用子任务)'");
-            log.info("已添加parent_task_id列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN frequency VARCHAR(20) COMMENT '频率: daily/weekly/monthly'");
-            log.info("已添加frequency列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN max_frequency INT COMMENT '周期内最多完成次数'");
-            log.info("已添加max_frequency列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN complete_types VARCHAR(100) COMMENT '完成方式JSON'");
-            log.info("已添加complete_types列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN review_type VARCHAR(20) COMMENT '审核人类型: creator/parent/teacher/ai'");
-            log.info("已添加review_type列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN earliest_start DATETIME COMMENT '最早开始时间'");
-            log.info("已添加earliest_start列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN latest_end DATETIME COMMENT '最晚结束时间'");
-            log.info("已添加latest_end列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移24: tasks表添加minigame_code字段(小游戏任务)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN minigame_code VARCHAR(50) DEFAULT NULL COMMENT '小游戏代码: schulte/1a2b/sudoku'");
-            log.info("已添加minigame_code列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移25: tasks表添加duration字段(TASK-011: 任务预计时长)
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN duration INT DEFAULT 0 COMMENT '预计时长(分钟)'");
-            log.info("已添加duration列到tasks表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks ADD INDEX idx_minigame (minigame_code) WHERE minigame_code IS NOT NULL");
-            log.info("已添加idx_minigame索引到tasks表");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS trial_memberships (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "start_date DATETIME NOT NULL COMMENT '试用开始时间', " +
-                    "end_date DATETIME NOT NULL COMMENT '试用结束时间', " +
-                    "status VARCHAR(20) DEFAULT 'PENDING' COMMENT '状态:PENDING/ACTIVE/EXPIRED/CONVERTED', " +
-                    "trial_days INT DEFAULT 7 COMMENT '试用天数', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_end_date (end_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建trial_memberships表");
-        } catch (Exception e) {
-            log.warn("创建trial_memberships表可能已存在: {}", e.getMessage());
-        }
-
-        // assessment_appointments 新字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_appointments ADD COLUMN user_id BIGINT COMMENT '用户ID'");
-        } catch (Exception e) {
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_appointments ADD COLUMN guide_id BIGINT COMMENT '成长规划师ID'");
-        } catch (Exception e) {
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_appointments ADD COLUMN package_id BIGINT COMMENT '套餐ID'");
-        } catch (Exception e) {
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_appointments ADD COLUMN remark VARCHAR(500) COMMENT '备注'");
-        } catch (Exception e) {
-        }
-
-        // assessment_orders 表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS assessment_orders (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_no VARCHAR(64) NOT NULL UNIQUE, " +
-                    "family_id BIGINT NOT NULL, " +
-                    "user_id BIGINT NOT NULL, " +
-                    "child_id BIGINT, " +
-                    "guide_id BIGINT NOT NULL, " +
-                    "package_id BIGINT NOT NULL, " +
-                    "guide_name VARCHAR(50), " +
-                    "package_name VARCHAR(100), " +
-                    "total_price BIGINT DEFAULT 0, " +
-                    "discount_amount BIGINT DEFAULT 0, " +
-                    "actual_price BIGINT DEFAULT 0, " +
-                    "status VARCHAR(20) DEFAULT 'pending', " +
-                    "pay_time VARCHAR(50), " +
-                    "pay_type VARCHAR(20), " +
-                    "transaction_id VARCHAR(64), " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family (family_id), " +
-                    "INDEX idx_guide (guide_id), " +
-                    "INDEX idx_status (status)) " +
-                    "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评估订单表'");
-        } catch (Exception e) {
-        }
-
-        // 迁移26: guide_applications表添加address和bank_card字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_applications ADD COLUMN address VARCHAR(500) COMMENT '地址'");
-            log.info("已添加address列到guide_applications表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_applications ADD COLUMN bank_card VARCHAR(50) COMMENT '银行卡号'");
-            log.info("已添加bank_card列到guide_applications表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_applications ADD COLUMN bank_name VARCHAR(100) COMMENT '开户行'");
-            log.info("已添加bank_name列到guide_applications表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移27: users表添加address字段(成长规划师地址)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN address VARCHAR(500) COMMENT '地址'");
-            log.info("已添加address列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移28: 创建guide_application_records表(申请过程记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_application_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "application_id BIGINT NOT NULL COMMENT '关联申请ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '操作人用户ID', " +
-                    "action VARCHAR(50) NOT NULL COMMENT '操作: submit/approve/reject/withdraw/resubmit', " +
-                    "from_status VARCHAR(20) COMMENT '操作前状态', " +
-                    "to_status VARCHAR(20) NOT NULL COMMENT '操作后状态', " +
-                    "remark VARCHAR(500) COMMENT '备注/原因', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_application_id (application_id), " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_action (action)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师申请过程记录表'");
-            log.info("已创建guide_application_records表");
-} catch (Exception e) {
-
-        }
-
-
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'points_log' AND COLUMN_NAME = 'category'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE points_log ADD COLUMN category VARCHAR(20) DEFAULT 'task' COMMENT '积分分类: task任务积分, system系统积分'");
-                log.info("已添加category列到points_log表");
-            } else {
-                log.info("category列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加category列失败: {}", e.getMessage());
-        }
-
-        // 迁移22: 创建invite_card表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS invite_card (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "type VARCHAR(20) NOT NULL COMMENT 'child/family/guide', " +
-                    "code VARCHAR(64) NOT NULL UNIQUE COMMENT '邀请码', " +
-                    "ref_id BIGINT NOT NULL COMMENT '关联ID(childId/familyId)', " +
-                    "creator_id BIGINT NOT NULL COMMENT '创建人', " +
-                    "expires_at DATETIME NOT NULL, " +
-                    "used TINYINT DEFAULT 0, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_code (code), " +
-                    "INDEX idx_ref_type (ref_id, type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='邀请卡片'");
-            log.info("已创建invite_card表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移23: 创建wishes表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS wishes (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT COMMENT '家庭ID', " +
-                    "child_id BIGINT COMMENT '目标孩子ID', " +
-                    "created_by BIGINT COMMENT '创建者用户ID', " +
-                    "creator_type VARCHAR(20) COMMENT '创建者类型: child/parent', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '心愿标题', " +
-                    "description VARCHAR(500) COMMENT '心愿描述', " +
-                    "category VARCHAR(32) COMMENT '心愿分类', " +
-                    "points_required INT COMMENT '所需积分', " +
-                    "points_set_by BIGINT COMMENT '定价者ID', " +
-                    "points_set_at DATETIME COMMENT '定价时间', " +
-                    "status VARCHAR(32) DEFAULT 'active' COMMENT '状态: draft/active/pending_exchange/approved/exchanging/fulfilled/cancelled/rejected', " +
-                    "exchange_requested_at DATETIME COMMENT '申请兑换时间', " +
-                    "exchange_approved_by BIGINT COMMENT '批准者ID', " +
-                    "exchange_approved_at DATETIME COMMENT '批准时间', " +
-                    "points_deducted_at DATETIME COMMENT '扣积分时间', " +
-                    "fulfilled_by BIGINT COMMENT '兑现者ID', " +
-                    "fulfilled_at DATETIME COMMENT '兑现时间', " +
-                    "child_confirmed_at DATETIME COMMENT '孩子确认收货时间', " +
-                    "rejected_by BIGINT COMMENT '拒绝者ID', " +
-                    "rejected_at DATETIME COMMENT '拒绝时间', " +
-                    "reject_reason VARCHAR(500) COMMENT '拒绝原因', " +
-                    "reject_count INT DEFAULT 0 COMMENT '被拒绝次数', " +
-                    "cancelled_by BIGINT COMMENT '取消者ID', " +
-                    "cancelled_at DATETIME COMMENT '取消时间', " +
-                    "cancel_reason VARCHAR(500) COMMENT '取消原因', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心愿单表'");
-            log.info("已创建wishes表");
-        } catch (Exception e) {
-            log.warn("创建wishes表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移24: users表添加个人信息补充字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'ethnicity'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE users " +
-                        "ADD COLUMN ethnicity VARCHAR(32) DEFAULT NULL COMMENT '民族', " +
-                        "ADD COLUMN blood_type VARCHAR(16) DEFAULT NULL COMMENT '血型', " +
-                        "ADD COLUMN highest_education VARCHAR(32) DEFAULT NULL COMMENT '最高学历', " +
-                        "ADD COLUMN marital_status VARCHAR(16) DEFAULT NULL COMMENT '婚姻状态', " +
-                        "ADD COLUMN family_role VARCHAR(16) DEFAULT NULL COMMENT '家长身份: 爸爸/妈妈/爷爷/奶奶/姥爷/姥姥/其他'");
-                log.info("已添加个人信息补充字段到users表");
-            } else {
-                log.info("个人信息补充字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加个人信息补充字段失败: {}", e.getMessage());
-        }
-
-        // Phase 0: 浠艾福俱乐部 — 服务商字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'vendor_type'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN vendor_type VARCHAR(32) DEFAULT NULL COMMENT '服务商类型: planner/activity_provider/product_supplier'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN vendor_status VARCHAR(16) DEFAULT NULL COMMENT '服务商审核状态: pending/approved/rejected'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN vendor_reject_reason VARCHAR(500) DEFAULT NULL COMMENT '审核拒绝原因'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN is_family_admin TINYINT DEFAULT 0 COMMENT '是否家庭管理员'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN vendor_info VARCHAR(2000) DEFAULT NULL COMMENT '服务商资质信息(JSON)'");
-                log.info("已添加浠艾福俱乐部服务商字段到users表");
-            } else {
-                log.info("浠艾福俱乐部服务商字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加服务商字段失败: {}", e.getMessage());
-        }
-
-        // Phase 0: 迁移已有规划师到服务商体系
-        try {
-            int updated = jdbcTemplate.update(
-                    "UPDATE users SET vendor_type = 'planner', vendor_status = 'approved' WHERE teacher_status = 'approved' AND vendor_type IS NULL"
-            );
-            if (updated > 0) {
-                log.info("已迁移 {} 名规划师到服务商体系", updated);
-            }
-        } catch (Exception e) {
-            log.warn("迁移规划师到服务商体系失败: {}", e.getMessage());
-        }
-
-        // ==================== Phase 1: 浠艾福俱乐部商品系统 ======        // 商品表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS products (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                            "  name VARCHAR(200) NOT NULL," +
-                            "  description VARCHAR(1000)," +
-                            "  intro TEXT," +
-                            "  cover_image VARCHAR(500)," +
-                            "  images TEXT," +
-                            "  price INT NOT NULL DEFAULT 0 COMMENT '价格(分)'," +
-                            "  stock INT NOT NULL DEFAULT 0," +
-                            "  sales_count INT NOT NULL DEFAULT 0," +
-                            "  product_type VARCHAR(32) NOT NULL COMMENT 'activity/course/physical/digital/service'," +
-                            "  vendor_id BIGINT," +
-                            "  vendor_name VARCHAR(100)," +
-                            "  status VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT 'draft/pending/approved/rejected/on_shelf/off_shelf'," +
-                            "  reject_reason VARCHAR(500)," +
-                            "  member_price INT COMMENT '会员价(分)'," +
-                            "  profit_rate INT DEFAULT 0 COMMENT '平台利润率(千分比)'," +
-                            "  member_eligible VARCHAR(32) DEFAULT 'none' COMMENT 'all/budget/none'," +
-                            "  domain VARCHAR(32) COMMENT 'action/mind/body/wisdom/wealth'," +
-                            "  external_source VARCHAR(64)," +
-                            "  external_id VARCHAR(128)," +
-                            "  external_data TEXT," +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                            ")"
-            );
-        } catch (Exception e) {
-            log.warn("创建products表失败: {}", e.getMessage());
-        }
-
-        // 商品SKU表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS product_skus (" +
-                            "  id INT NOT NULL AUTO_INCREMENT," +
-                            "  product_id INT NOT NULL COMMENT '商品ID'," +
-                            "  sku_code VARCHAR(64) NOT NULL COMMENT 'SKU编码'," +
-                            "  specs JSON NOT NULL COMMENT '规格JSON'," +
-                            "  price DECIMAL(10,2) NOT NULL COMMENT 'SKU价格'," +
-                            "  stock INT NOT NULL DEFAULT 0 COMMENT '库存'," +
-                            "  original_price DECIMAL(10,2) COMMENT '原价/划线价'," +
-                            "  image VARCHAR(512) COMMENT 'SKU图片'," +
-                            "  enabled TINYINT(1) NOT NULL DEFAULT 1," +
-                            "  create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
-                            "  update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                            "  PRIMARY KEY (id)," +
-                            "  KEY idx_product_id (product_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品SKU'"
-            );
-            log.info("已创建product_skus表");
-        } catch (Exception e) {
-            log.warn("创建product_skus表失败: {}", e.getMessage());
-        }
-
-        // 订单表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS product_orders (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                            "  order_no VARCHAR(64) NOT NULL UNIQUE," +
-                            "  product_id BIGINT NOT NULL," +
-                            "  product_name VARCHAR(200)," +
-                            "  product_type VARCHAR(32)," +
-                            "  buyer_id BIGINT NOT NULL," +
-                            "  family_id BIGINT," +
-                            "  quantity INT NOT NULL DEFAULT 1," +
-                            "  unit_price INT NOT NULL COMMENT '单价(分)'," +
-                            "  total_amount INT NOT NULL COMMENT '总金额(分)'," +
-                            "  status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/completed/cancelled/refunded'," +
-                            "  payment_method VARCHAR(32) COMMENT 'wechat/points/membership'," +
-                            "  remark VARCHAR(500)," +
-                            "  paid_at DATETIME," +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                            ")"
-            );
-        } catch (Exception e) {
-            log.warn("创建product_orders表失败: {}", e.getMessage());
-        }
-
-        // 系统配置表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS sys_config (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                            "  config_key VARCHAR(64) NOT NULL UNIQUE," +
-                            "  config_value TEXT," +
-                            "  description VARCHAR(500)," +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                            ")"
-            );
-        } catch (Exception e) {
-            log.warn("创建sys_config表失败: {}", e.getMessage());
-        }
-
-        // Migration: product_orders add logistics fields
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN logistics_no VARCHAR(64) COMMENT '物流单号'");
-            log.info("已添加logistics_no列到product_orders表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN logistics_company VARCHAR(100) COMMENT '物流公司'");
-            log.info("已添加logistics_company列到product_orders表");
-        } catch (Exception e) {
-        }
-
-        // SysConfig 种子数据
-        try {
-            insertSysConfigSeed("points_exchange_rate", "1", "积分兑换汇率(1积分=1分,即0.01元)");
-            insertSysConfigSeed("points_deduct_cap", "0.5", "积分抵扣上限(50%)");
-            insertSysConfigSeed("member_fee_standard", "1314", "标准会员年费(元)");
-            insertSysConfigSeed("member_fee_premium", "1316800", "高级家庭会员年费(分)");
-            insertSysConfigSeed("member_eligible_budget", "1314", "等值商品选择预算上限(元)");
-            insertSysConfigSeed("renewal_discount_rate", "0.85", "续费折扣率");
-            insertSysConfigSeed("member_discount_standard", "0.9", "标准会员折扣率");
-            insertSysConfigSeed("member_discount_premium", "8000", "高级家庭会员商品折扣(bps)");
-            insertSysConfigSeed("member_fee_family", "131400", "家庭会员年费(分)");
-            insertSysConfigSeed("member_fee_family_yearly", "131400", "家庭会员年费(分)");
-            insertSysConfigSeed("member_fee_family_monthly", "13140", "家庭会员月费(分)");
-            insertSysConfigSeed("member_fee_family_quarterly", "32850", "家庭会员季费(分)");
-            insertSysConfigSeed("member_upgrade_threshold", "131400", "自动升级家庭会员累计消费门槛(分)");
-            insertSysConfigSeed("member_discount_family", "9000", "家庭会员商品折扣(bps)");
-            insertSysConfigSeed("member_fee_premium_monthly", "131400", "高级家庭会员月费(分)");
-            insertSysConfigSeed("member_fee_family_original_yearly", "199900", "家庭会员年费原价(分)");
-            insertSysConfigSeed("member_fee_family_original", "199900", "家庭会员原价兜底(分)");
-            insertSysConfigSeed("member_fee_premium_original", "1599900", "高级会员年费原价(分)");
-            insertSysConfigSeed("member_fee_premium_original_monthly", "159900", "高级会员月费原价(分)");
-            insertSysConfigSeed("commission_member_l1_rate", "2000", "推荐家庭会员L1佣金率(bps)");
-            insertSysConfigSeed("commission_member_l2_rate", "500", "推荐家庭会员L2佣金率(bps)");
-            insertSysConfigSeed("commission_product_profit_share", "1000", "下线商品购买利润分成(bps)");
-            insertSysConfigSeed("commission_service_rate", "1000", "下线服务购买佣金率(bps)");
-            insertSysConfigSeed("commission_event_fixed", "2000", "推荐新用户报名活动固定佣金(分)");
-            insertSysConfigSeed("withdraw_min_amount", "10000", "最低提现金额(分)");
-            insertSysConfigSeed("withdraw_tax_rate", "2000", "佣金税率(bps)");
-            insertSysConfigSeed("withdraw_fee_free_threshold", "80000", "免税额度(分)");
-            insertSysConfigSeed("article_energy_rate_normal", "1", "普通文章能量汇率(每100字)");
-            insertSysConfigSeed("article_energy_rate_premium", "2", "优质文章能量汇率(每100字)");
-            insertSysConfigSeed("article_energy_rate_original", "3", "原创文章能量汇率(每100字)");
-            insertSysConfigSeed("article_reading_min_seconds", "60", "文章阅读达标最少秒数");
-            insertSysConfigSeed("activity_checkin_default_points", "5", "活动签到默认积分");
-            insertSysConfigSeed("health_checkin_points", "5", "健康打卡积分");
-            insertSysConfigSeed("finance_checkin_points", "5", "理财打卡积分");
-            insertSysConfigSeed("trial_enabled", "true", "是否启用会员试用");
-            insertSysConfigSeed("trial_days", "7", "试用天数");
-            insertSysConfigSeed("trial_features", "[\"free_activities\",\"free_courses\",\"teacher_consultation\"]", "试用期间可用功能");
-            insertSysConfigSeed("member_pay_virtual_enabled", "1", "会员支付是否使用虚拟支付通道(1=虚拟,0=普通微信)");
-insertSysConfigSeed("gift_membership_threshold", "198000", "购买送会员商品累计达到该金额(分)赠送会员");
-insertSysConfigSeed("gift_membership_level", "FAMILY", "达到送会员额度后赠送的会员等级");
-insertSysConfigSeed("gift_membership_original_threshold", "1000000", "送会员商品原价达标阈值(分),达到此金额后送会员商品部分实付一口价");
-insertSysConfigSeed("gift_membership_pay_price", "198000", "送会员商品达标后一口实付价(分)");
-            insertSysConfigSeed("health_dimension_weights", "{\"growth\":0.20,\"sleep\":0.15,\"vision\":0.10,\"immunity\":0.15,\"nutrition\":0.15,\"gut\":0.10,\"exercise\":0.15}", "7维健康→身能量权重配置");
-            insertSysConfigSeed("health_dimension_sync_factor", "0.5", "7维健康同步至身能量系数");
-            log.info("SysConfig 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("SysConfig 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // Product 种子数据(5 个示例商品,覆盖全部 5 种 productType)
-        try {
-            insertProductSeed("亲子关系工作坊", "线下半日工作坊,重建家庭对话模式", "activity", 38800, "action", "all");
-            insertProductSeed("情绪管理21天训练营", "21天视频课程,识别并管理情绪", "course", 19900, "mind", "all");
-            insertProductSeed("肠道菌群检测套装", "家用检测 + 报告解读", "physical", 59900, "body", "budget");
-            insertProductSeed("儿童多模态认知测评", "在线测评 + 个性化建议", "digital", 9900, "wisdom", "none");
-            insertProductSeed("成长规划师1对1咨询", "60分钟专业规划", "service", 50000, "wealth", "budget");
-            log.info("Product 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("Product 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // 活动种子数据(3 个示例活动,覆盖身/心/智三个维度)
-        try {
-            insertActivitySeed("亲子户外徒步探险", "周末亲子徒步活动,在自然中锻炼体魄、增进亲子关系,全程约5公里。",
-                    "body", "offline", "published",
-                    "2026-08-15 09:00:00", "2026-08-15 16:00:00", "北京奥林匹克森林公园", 50, 0, 0,
-                    "{\"body\":80,\"mind\":0,\"wisdom\":0,\"action\":20,\"wealth\":0}");
-            insertActivitySeed("家庭正念静心工作坊", "专业导师带领的正念冥想体验,学习情绪调节和家庭沟通技巧。",
-                    "mind", "offline", "published",
-                    "2026-08-22 14:00:00", "2026-08-22 17:00:00", "北京市朝阳区心理成长中心", 30, 9900, 7900,
-                    "{\"body\":0,\"mind\":80,\"wisdom\":10,\"action\":10,\"wealth\":0}");
-            insertActivitySeed("少儿科学思维探索营", "通过动手实验激发孩子对科学的兴趣,培养逻辑思维与创造力。",
-                    "wisdom", "online", "published",
-                    "2026-09-05 10:00:00", "2026-09-05 12:00:00", "线上直播", 200, 19900, 15900,
-                    "{\"body\":0,\"mind\":0,\"wisdom\":70,\"action\":30,\"wealth\":0}");
-            log.info("Activity 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("Activity 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // 方案规则种子数据(主链路 P0-3:模板包 + 方案生成规则)
-        try {
-            Long pkgFocus = ensureTemplatePackage("专注力提升方案模板",
-                "针对注意力维度低分(0-60)的14天专注力提升训练", 14, "专注力");
-            Long pkgKeep = ensureTemplatePackage("注意力巩固方案模板",
-                "针对注意力维度正常(61-100)的14天巩固训练", 14, "注意力");
-            ensureTemplateItems(pkgFocus, new String[][]{
-                {"舒尔特方格训练", "每日5分钟舒尔特方格,提升视觉专注", "5", "daily"},
-                {"静坐冥想", "每日10分钟静坐冥想,训练抗干扰能力", "3", "daily"},
-                {"番茄钟作业法", "使用番茄钟完成当日作业,25分钟一节", "5", "daily"}
-            });
-            ensureTemplateItems(pkgKeep, new String[][]{
-                {"专注力保持打卡", "每日记录专注时长,保持良好习惯", "3", "daily"},
-                {"优质睡眠打卡", "每日21:30前入睡,保障注意力恢复", "3", "daily"},
-                {"亲子共读", "每周3次亲子共读,培养持续专注", "5", "weekly"}
-            });
-            ensurePlanRule("attention", 0, 60, pkgFocus, 1);
-            ensurePlanRule("attention", 61, 100, pkgKeep, 2);
-            log.info("方案规则种子数据已加载: 模板包 focus={}, keep={}", pkgFocus, pkgKeep);
-        } catch (Exception e) {
-            log.warn("方案规则种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // 报告解析中台:注册菌群检测报告类型(主链路 P0-4)
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM report_type_registry WHERE type_id = ?", Integer.class, "gut_flora");
-            if (count == null || count == 0) {
-                jdbcTemplate.update(
-                    "INSERT INTO report_type_registry (type_id, family, display_name, description, parser_path, " +
-                    "min_confidence, is_active, source, review_status, version, created_at, updated_at) " +
-                    "VALUES ('gut_flora', 'gut_flora', '菌群检测', '募极生物/北京肠道菌群检测报告', " +
-                    "'gut_flora/extract_gut_flora.py', 30, 1, 'prebuilt', 'approved', '1.0', NOW(), NOW())");
-                log.info("已注册报告类型 gut_flora");
-            } else {
-                log.info("报告类型 gut_flora 已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("报告类型注册失败: {}", e.getMessage());
-        }
-
-        // 文章种子数据(3 个示例文章,覆盖学习力/情绪管理/亲子教育分类)
-        try {
-            insertArticleSeed("如何培养孩子的自主学习力",
-                    "从内在动机出发,帮助孩子建立自主学习习惯的实用方法指南。",
-                    "article", 4L, "wisdom", "published", "曹老师",
-                    "normal", 5, 1800,
-                    "{\"body\":0,\"mind\":0,\"wisdom\":60,\"action\":40,\"wealth\":0}");
-            insertArticleSeed("儿童情绪管理的五个关键步骤",
-                    "当孩子情绪爆发时,家长应该如何应对?本文提供一套可操作的情绪管理框架。",
-                    "article", 2L, "mind", "published", "李老师",
-                    "premium", 4, 2200,
-                    "{\"body\":0,\"mind\":80,\"wisdom\":10,\"action\":10,\"wealth\":0}");
-            insertArticleSeed("亲子运动的正确打开方式",
-                    "不同年龄段孩子的运动建议,让全家人在快乐中收获健康。",
-                    "article", 3L, "action", "published", "王老师",
-                    "normal", 3, 1500,
-                    "{\"body\":40,\"mind\":0,\"wisdom\":0,\"action\":60,\"wealth\":0}");
-            log.info("Article 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("Article 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // 补充商品种子数据(2 个,丰富商品库)
-        try {
-            insertProductSeed("少儿专注力训练教具盒", "含舒尔特方格、记忆卡片等8种专注力训练工具,适合5-12岁儿童。", "physical", 16800, "wisdom", "all");
-            insertProductSeed("家庭年度VIP成长会员", "一年内畅享全部线上课程、活动折扣及规划师咨询服务。", "digital", 298000, "action", "all");
-            log.info("补充 Product 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("补充 Product 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // ==================== Phase 2: 内容区块可见性配置 ======        // 内容区块配置表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS content_sections (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                            "  page_key VARCHAR(50) NOT NULL," +
-                            "  section_key VARCHAR(50) NOT NULL," +
-                            "  title VARCHAR(100)," +
-                            "  allowed_roles VARCHAR(255) DEFAULT '[\"anonymous\"]'," +
-                            "  sort_order INT DEFAULT 0," +
-                            "  status VARCHAR(20) DEFAULT 'active'," +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                            ")"
-            );
-            log.info("content_sections 表已创建");
-        } catch (Exception e) {
-            log.warn("创建 content_sections 表失败: {}", e.getMessage());
-        }
-
-        // ContentSection 种子数据
-        try {
-            insertContentSectionSeed("mind", "func_entries", "功能入口", "[\"anonymous\"]", 1);
-            insertContentSectionSeed("mind", "daily_tip", "每日心理", "[\"anonymous\"]", 2);
-            insertContentSectionSeed("mind", "recommended_reading", "推荐阅读", "[\"anonymous\"]", 3);
-            insertContentSectionSeed("mind", "premium_content", "会员专属内容", "[\"parent\",\"teacher\"]", 4);
-            insertContentSectionSeed("mind", "mind_tasks", "心智任务", "[\"parent\",\"child\"]", 5);
-            insertContentSectionSeed("mind", "related_activities", "相关活动", "[\"parent\",\"child\"]", 6);
-            insertContentSectionSeed("mind", "purchased_courses", "已购课程", "[\"parent\",\"child\"]", 7);
-            insertContentSectionSeed("body", "func_entries", "功能入口", "[\"anonymous\"]", 1);
-            insertContentSectionSeed("body", "daily_stats", "今日数据", "[\"anonymous\"]", 2);
-            insertContentSectionSeed("body", "health_tips", "健康小贴士", "[\"anonymous\"]", 3);
-            insertContentSectionSeed("body", "teacher_tips", "规划师推荐", "[\"teacher\"]", 4);
-            log.info("ContentSection 种子数据已加载");
-        } catch (Exception e) {
-            log.warn("ContentSection 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // ==================== 文章内容系统种子数据 ======        // 文章分类种子数据
-        try {
-            Integer catCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM article_categories WHERE id IN (1,2,3,4,5)", Integer.class);
-            if (catCount == null || catCount == 0) {
-                jdbcTemplate.execute("INSERT IGNORE INTO article_categories (id, name, icon, color, sort_order, status) VALUES " +
-                        "(1, '心理健康', '🧠', '#5B9BD5', 1, 1), " +
-                        "(2, '情绪管理', '💖', '#FF6B35', 2, 1), " +
-                        "(3, '亲子教育', '👨‍👩‍👧‍👦', '#4CAF50', 3, 1), " +
-                        "(4, '学习力', '📚', '#FFD700', 4, 1), " +
-                        "(5, '专注力', '🎯', '#8D6E63', 5, 1)");
-                log.info("文章分类种子数据已加载");
-            }
-        } catch (Exception e) {
-            log.warn("文章分类种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // ==================== 佣金系统 ======        // 迁移: users表添加推荐人字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'referrer_id'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN referrer_id BIGINT DEFAULT NULL COMMENT '推荐人ID'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN referral_code VARCHAR(32) DEFAULT NULL COMMENT '个人邀请码'");
-                jdbcTemplate.execute("ALTER TABLE users ADD INDEX idx_referral_code (referral_code)");
-                log.info("已添加佣金字段到users表");
-            } else {
-                log.info("佣金字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加佣金字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: products表添加利润率字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'products' AND COLUMN_NAME = 'profit_rate'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE products ADD COLUMN profit_rate INT DEFAULT 0 COMMENT '平台利润率(bps,100=1%)'");
-                log.info("已添加profit_rate列到products表");
-            } else {
-                log.info("profit_rate列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加profit_rate列失败: {}", e.getMessage());
-        }
-
-        // 新表: commission_records (佣金记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS commission_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_id BIGINT NOT NULL COMMENT '订单ID', " +
-                    "order_type VARCHAR(32) NOT NULL COMMENT '订单类型: membership/product/assessment/package', " +
-                    "referrer_id BIGINT NOT NULL COMMENT '推荐人ID', " +
-                    "buyer_id BIGINT NOT NULL COMMENT '购买人ID', " +
-                    "commission_type VARCHAR(16) NOT NULL COMMENT '佣金类型: member/profit', " +
-                    "order_amount INT NOT NULL COMMENT '订单金额(分)', " +
-                    "profit_rate INT DEFAULT 0 COMMENT '利润率(bps,100=1%)', " +
-                    "commission_amount INT NOT NULL COMMENT '佣金金额(分)', " +
-                    "status VARCHAR(16) NOT NULL DEFAULT 'settled' COMMENT '状态: pending/settled', " +
-                    "remark VARCHAR(255) DEFAULT NULL, " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_referrer (referrer_id), " +
-                    "INDEX idx_buyer (buyer_id), " +
-                    "INDEX idx_order (order_id, order_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建commission_records表");
-        } catch (Exception e) {
-            log.warn("创建commission_records表失败: {}", e.getMessage());
-        }
-
-        // 新表: withdrawal_requests (提现申请)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS withdrawal_requests (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "amount INT NOT NULL COMMENT '提现金额(分)', " +
-                    "account_info TEXT COMMENT '账户信息(JSON)', " +
-                    "status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/approved/rejected', " +
-                    "audit_by BIGINT DEFAULT NULL COMMENT '审核人ID', " +
-                    "audit_at DATETIME DEFAULT NULL COMMENT '审核时间', " +
-                    "remark VARCHAR(255) DEFAULT NULL COMMENT '审核备注', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建withdrawal_requests表");
-        } catch (Exception e) {
-            log.warn("创建withdrawal_requests表失败: {}", e.getMessage());
-        }
-
-        // ==================== 会员体系 & 佣金扩展 ======        // 迁移: users表添加会员字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'member_level'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN member_level VARCHAR(20) DEFAULT 'FREE' COMMENT '会员等级: FREE/FAMILY/PROVIDER'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN member_expire_time DATETIME DEFAULT NULL COMMENT '家庭会员到期时间'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN total_consumption BIGINT DEFAULT 0 COMMENT '累计消费金额(分)'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN upgrade_from_consumption TINYINT DEFAULT 0 COMMENT '是否通过累计消费自动升级'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN direct_count INT DEFAULT 0 COMMENT '直接推荐人数'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN indirect_count INT DEFAULT 0 COMMENT '间接推荐人数'");
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN total_commission_earned BIGINT DEFAULT 0 COMMENT '累计获得佣金(分)'");
-                log.info("已添加会员字段到users表");
-            } else {
-                log.info("会员字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加会员字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: commission_records表添加扩展字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'commission_records' AND COLUMN_NAME = 'level'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE commission_records ADD COLUMN level INT DEFAULT 1 COMMENT '佣金层级: 1=直接推荐, 2=间接推荐'");
-                jdbcTemplate.execute("ALTER TABLE commission_records ADD COLUMN settled_at DATETIME DEFAULT NULL COMMENT '结算时间'");
-                jdbcTemplate.execute("ALTER TABLE commission_records ADD COLUMN withdrawn_at DATETIME DEFAULT NULL COMMENT '提现时间'");
-                log.info("已添加扩展字段到commission_records表");
-            } else {
-                log.info("commission_records扩展字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加commission_records扩展字段失败: {}", e.getMessage());
-        }
-
-        // 新表: member_upgrade_records (会员升级记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS member_upgrade_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "from_level VARCHAR(20) NOT NULL COMMENT '升级前等级', " +
-                    "to_level VARCHAR(20) NOT NULL COMMENT '升级后等级', " +
-                    "upgrade_type VARCHAR(20) NOT NULL COMMENT '升级类型: pay/consumption/admin', " +
-                    "order_id BIGINT DEFAULT NULL COMMENT '关联支付订单ID', " +
-                    "consumption_amount BIGINT DEFAULT NULL COMMENT '触发升级的累计消费金额', " +
-                    "expire_time DATETIME DEFAULT NULL COMMENT '家庭会员到期时间', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_order (order_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员升级记录'");
-            log.info("已创建member_upgrade_records表");
-        } catch (Exception e) {
-            log.warn("创建member_upgrade_records表失败: {}", e.getMessage());
-        }
-
-        // ==================== 文章内容系统 ======        // 文章分类表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS article_categories (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(50) NOT NULL COMMENT '分类名', " +
-                    "icon VARCHAR(20) DEFAULT '' COMMENT '图标emoji', " +
-                    "color VARCHAR(20) DEFAULT '#5B9BD5' COMMENT '标识色', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "status TINYINT DEFAULT 1 COMMENT '1启用/0禁用'" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类'");
-            log.info("已创建article_categories表");
-        } catch (Exception e) {
-            log.warn("创建article_categories表失败: {}", e.getMessage());
-        }
-
-        // 文章表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS articles (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "category_id BIGINT DEFAULT 0 COMMENT '所属分类ID', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '标题', " +
-                    "summary VARCHAR(500) DEFAULT '' COMMENT '摘要', " +
-                    "cover_image VARCHAR(500) DEFAULT '' COMMENT '封面图URL', " +
-                    "content LONGTEXT COMMENT '富文本内容', " +
-                    "tags VARCHAR(200) DEFAULT '' COMMENT '标签JSON数组', " +
-                    "author VARCHAR(100) DEFAULT '浠艾福' COMMENT '作者', " +
-                    "read_time INT DEFAULT 0 COMMENT '预计阅读分钟数', " +
-                    "related_dimensions VARCHAR(100) DEFAULT '' COMMENT '关联五维JSON数组', " +
-                    "visibility VARCHAR(20) DEFAULT 'public' COMMENT '浏览权限:public/login/private', " +
-                    "visible_to TEXT COMMENT '私密指定人群JSON', " +
-                    "status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/published/archived', " +
-                    "is_featured TINYINT DEFAULT 0 COMMENT '1精选/0普通', " +
-                    "published_at DATETIME DEFAULT NULL COMMENT '发布时间', " +
-                    "view_count INT DEFAULT 0 COMMENT '浏览次数', " +
-                    "created_by BIGINT DEFAULT 0 COMMENT '发布人adminID', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章'");
-            log.info("已创建articles表");
-        } catch (Exception e) {
-            log.warn("创建articles表失败: {}", e.getMessage());
-        }
-
-        // 迁移: articles表补充新字段(兼容旧表)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'articles' AND COLUMN_NAME = 'visibility'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN visibility VARCHAR(20) DEFAULT 'public' COMMENT '浏览权限:public/login/private' AFTER related_dimensions");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN visible_to TEXT COMMENT '私密指定人群JSON' AFTER visibility");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN tags VARCHAR(200) DEFAULT '' COMMENT '标签JSON数组' AFTER content");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN related_dimensions VARCHAR(100) DEFAULT '' COMMENT '关联五维JSON数组' AFTER read_time");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN is_featured TINYINT DEFAULT 0 COMMENT '1精选/0普通' AFTER status");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN published_at DATETIME DEFAULT NULL COMMENT '发布时间' AFTER is_featured");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN view_count INT DEFAULT 0 COMMENT '浏览次数' AFTER published_at");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN created_by BIGINT DEFAULT 0 COMMENT '发布人adminID' AFTER view_count");
-                log.info("已迁移articles表补充字段");
-            } else {
-                log.info("articles表字段已完整,跳过迁移");
-            }
-        } catch (Exception e) {
-            log.warn("articles表字段迁移失败: {}", e.getMessage());
-        }
-
-        // 迁移: articles表补充知识中心新字段(content_type/difficulty_level/dimension_ids)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'articles' AND COLUMN_NAME = 'content_type'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN content_type VARCHAR(20) DEFAULT 'article' COMMENT '内容类型: article/knowledge/course/tip' AFTER article_type");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN difficulty_level TINYINT DEFAULT 0 COMMENT '难度等级 1-5' AFTER content_type");
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN dimension_ids TEXT COMMENT '关联维度ID列表JSON' AFTER related_dimensions");
-                log.info("已迁移articles表知识中心新字段");
-            } else {
-                log.info("articles表知识中心字段已完整,跳过迁移");
-            }
-        } catch (Exception e) {
-            log.warn("articles表知识中心字段迁移失败: {}", e.getMessage());
-        }
-
-        // 文章标签关联表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS article_tags (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "article_id BIGINT NOT NULL COMMENT '文章ID', " +
-                    "tag_id BIGINT NOT NULL COMMENT '标签ID(关联dan_knowledge_tag.id)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_article_tag (article_id, tag_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章-标签关联表'");
-            log.info("已创建article_tags表");
-        } catch (Exception e) {
-            log.warn("创建article_tags表失败: {}", e.getMessage());
-        }
-
-        // ==================== 五维能量系统(账本模式) ======        // 维度定义表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS energy_dimension (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "code VARCHAR(16) NOT NULL UNIQUE COMMENT '维度代码: body/mind/wisdom/action/wealth', " +
-                            "name VARCHAR(20) NOT NULL COMMENT '维度名称: 身/心/智/行/富', " +
-                            "icon VARCHAR(16) COMMENT '图标emoji', " +
-                            "element VARCHAR(10) COMMENT '五行元素: 土/火/金/木/水', " +
-                            "sort_order INT DEFAULT 0 COMMENT '显示顺序', " +
-                            "status TINYINT DEFAULT 1 COMMENT '1启用/0禁用', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量维度定义表'"
-            );
-            log.info("已创建energy_dimension表");
-        } catch (Exception e) {
-            log.warn("创建energy_dimension表失败: {}", e.getMessage());
-        }
-
-        // 服务-维度比例配置表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS energy_source_config (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "source_type VARCHAR(32) NOT NULL COMMENT '来源类型: task/activity/course/product/consultation', " +
-                            "source_id BIGINT NOT NULL COMMENT '来源业务表ID', " +
-                            "source_name VARCHAR(200) COMMENT '冗余名称', " +
-                            "dimension_id BIGINT NOT NULL COMMENT '维度ID', " +
-                            "ratio INT NOT NULL COMMENT '占比(bps,10000=100%)', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "INDEX idx_source (source_type, source_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务-维度比例配置表'"
-            );
-            log.info("已创建energy_source_config表");
-        } catch (Exception e) {
-            log.warn("创建energy_source_config表失败: {}", e.getMessage());
-        }
-
-        // 购物车
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS cart_items (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID'," +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID'," +
-                    "quantity INT DEFAULT 1 COMMENT '数量'," +
-                    "selected TINYINT(1) DEFAULT 1 COMMENT '是否选中'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_user (user_id)," +
-                    "INDEX idx_product (product_id)," +
-                    "UNIQUE KEY uk_user_product (user_id, product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车'");
-            log.info("已创建cart_items表");
-        } catch (Exception e) {
-            log.warn("创建cart_items表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS shop_categories (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "name VARCHAR(64) NOT NULL COMMENT '分类名称'," +
-                    "parent_id BIGINT DEFAULT 0 COMMENT '父分类ID(0=根节点)'," +
-                    "level INT DEFAULT 0 COMMENT '层级(0/1/2/3)'," +
-                    "sort INT DEFAULT 0 COMMENT '排序'," +
-                    "image VARCHAR(512) COMMENT '分类图标'," +
-                    "enabled TINYINT(1) DEFAULT 1 COMMENT '启用'," +
-                    "dimension_codes VARCHAR(128) COMMENT '维度编码(逗号分隔: body,mind,heart)'," +
-                    "product_types VARCHAR(128) COMMENT '商品类型(逗号分隔: PHYSICAL,COURSE,ASSESSMENT)'," +
-                    "min_visible_level VARCHAR(50) COMMENT '最低可见会员级别编码(NULL=全部可见)'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_parent (parent_id)," +
-                    "INDEX idx_sort (sort)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品类目'");
-            log.info("已创建shop_categories表");
-        } catch (Exception e) {
-            log.warn("创建shop_categories表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS distribution_systems (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "name VARCHAR(64) NOT NULL COMMENT '体系名称'," +
-                    "description VARCHAR(255) COMMENT '描述'," +
-                    "owner_id BIGINT COMMENT '创建者ID'," +
-                    "profit_rate INT DEFAULT 0 COMMENT '平台利润率(千分比)'," +
-                    "enabled TINYINT(1) DEFAULT 1 COMMENT '启用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='销售体系'");
-            log.info("已创建distribution_systems表");
-        } catch (Exception e) {
-            log.warn("创建distribution_systems表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS distribution_relations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "system_id BIGINT NOT NULL COMMENT '体系ID'," +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID'," +
-                    "parent_id BIGINT COMMENT '上级用户ID(null=根)'," +
-                    "depth INT DEFAULT 0 COMMENT '层级深度'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "INDEX idx_system (system_id)," +
-                    "INDEX idx_user (user_id)," +
-                    "INDEX idx_parent (parent_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='销售关系'");
-            log.info("已创建distribution_relations表");
-        } catch (Exception e) {
-            log.warn("创建distribution_relations表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS after_sales_requests (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "order_id BIGINT NOT NULL COMMENT '订单ID'," +
-                    "order_no VARCHAR(32) NOT NULL COMMENT '订单号'," +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID'," +
-                    "type VARCHAR(32) NOT NULL COMMENT '类型: REFUND/RETURN_REFUND'," +
-                    "reason VARCHAR(255) COMMENT '原因'," +
-                    "description TEXT COMMENT '描述'," +
-                    "images TEXT COMMENT '凭证图片(JSON数组)'," +
-                    "refund_amount INT DEFAULT 0 COMMENT '退款金额(分)'," +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected/completed'," +
-                    "reject_reason VARCHAR(255) COMMENT '驳回原因'," +
-                    "handled_by BIGINT COMMENT '处理人ID'," +
-                    "handled_at DATETIME COMMENT '处理时间'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_order (order_id)," +
-                    "INDEX idx_user (user_id)," +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='售后申请'");
-            log.info("已创建after_sales_requests表");
-        } catch (Exception e) {
-            log.warn("创建after_sales_requests表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS shop_discount_rules (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "name VARCHAR(64) NOT NULL COMMENT '规则名称'," +
-                    "type VARCHAR(32) NOT NULL COMMENT '类型: PERCENT/FIXED/THRESHOLD'," +
-                    "value INT NOT NULL COMMENT '折扣值(PERCENT=百分比数字, FIXED/THRESHOLD=金额分)'," +
-                    "threshold_amount INT COMMENT '满减门槛(分,仅THRESHOLD)'," +
-                    "category_id BIGINT COMMENT '适用类目ID(null=全部)'," +
-                    "distribution_system_id BIGINT COMMENT '适用体系ID(null=全部)'," +
-                    "product_ids TEXT COMMENT '适用商品ID(逗号分隔,null=全部)'," +
-                    "start_time DATETIME COMMENT '开始时间'," +
-                    "end_time DATETIME COMMENT '结束时间'," +
-                    "max_uses INT DEFAULT 0 COMMENT '最大使用次数(0=不限)'," +
-                    "used_count INT DEFAULT 0 COMMENT '已使用次数'," +
-                    "enabled TINYINT(1) DEFAULT 1 COMMENT '启用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_category (category_id)," +
-                    "INDEX idx_enabled (enabled)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='折扣规则'");
-            log.info("已创建shop_discount_rules表");
-        } catch (Exception e) {
-            log.warn("创建shop_discount_rules表失败: {}", e.getMessage());
-        }
-
-        // 电商扩展字段 - products表
-        try {
-            jdbcTemplate.execute("ALTER TABLE products ADD COLUMN category_id BIGINT COMMENT '商品类目ID'");
-            log.info("已添加category_id列到products表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE products ADD COLUMN distribution_system_id BIGINT COMMENT '销售体系ID'");
-            log.info("已添加distribution_system_id列到products表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 电商扩展字段 - product_orders表
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN discount_amount INT DEFAULT 0 COMMENT '优惠金额(分)'");
-            log.info("已添加discount_amount列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN coupon_id BIGINT COMMENT '优惠券ID'");
-            log.info("已添加coupon_id列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN cancel_at DATETIME COMMENT '取消时间'");
-            log.info("已添加cancel_at列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN transaction_id VARCHAR(64) COMMENT '微信支付交易号'");
-            log.info("已添加transaction_id列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN cover_image VARCHAR(512) COMMENT '商品封面图快照'");
-            log.info("已添加cover_image列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN address_snapshot TEXT COMMENT '收货地址快照(JSON)'");
-            log.info("已添加address_snapshot列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 能量流水表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS energy_log (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                            "dimension_id BIGINT NOT NULL COMMENT '维度ID', " +
-                            "amount INT NOT NULL COMMENT '变动量(正=获得,负=消耗)', " +
-                            "balance_after INT NOT NULL COMMENT '变动后余额', " +
-                            "source_type VARCHAR(32) COMMENT '来源类型: task/product/medical_report/daily_record', " +
-                            "source_id BIGINT COMMENT '来源ID', " +
-                            "ref_id BIGINT COMMENT '关联旧流水ID(覆盖时标记)', " +
-                            "expires_at DATETIME COMMENT '过期时间(空=永不过期)', " +
-                            "description VARCHAR(500) COMMENT '描述', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "INDEX idx_child_dim (child_id, dimension_id), " +
-                            "INDEX idx_created (created_at), " +
-                            "INDEX idx_source (source_type, source_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量流水表'"
-            );
-            log.info("已创建energy_log表");
-        } catch (Exception e) {
-            log.warn("创建energy_log表失败: {}", e.getMessage());
-        }
-
-        // 维度余额表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS energy_balance (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                            "dimension_id BIGINT NOT NULL COMMENT '维度ID', " +
-                            "balance INT DEFAULT 0 COMMENT '当前能量值(可为负)', " +
-                            "total_earned INT DEFAULT 0 COMMENT '累计获得', " +
-                            "total_spent INT DEFAULT 0 COMMENT '累计消耗', " +
-                            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "UNIQUE KEY uk_child_dim (child_id, dimension_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='维度余额表'"
-            );
-            log.info("已创建energy_balance表");
-        } catch (Exception e) {
-            log.warn("创建energy_balance表失败: {}", e.getMessage());
-        }
-
-        // 维度种子数据(按相生链: 智→富→行→心→身)
-        try {
-            Integer dimCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM energy_dimension", Integer.class);
-            if (dimCount == null || dimCount == 0) {
-                jdbcTemplate.execute("INSERT INTO energy_dimension (code, name, icon, element, sort_order, status) VALUES " +
-                        "('mind', '心', '🔥', '火', 4, 1), " +
-                        "('body', '身', '🌏', '土', 5, 1), " +
-                        "('wisdom', '智', '⚔️', '金', 1, 1), " +
-                        "('action', '行', '🌿', '木', 3, 1), " +
-                        "('wealth', '富', '💧', '水', 2, 1)");
-                log.info("能量维度种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化能量维度种子数据失败: {}", e.getMessage());
-        }
-
-        // 为已有商品插入默认比例配置(与Product.domain一致)
-        try {
-            Integer productConfigCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM energy_source_config WHERE source_type = 'product'", Integer.class);
-            if (productConfigCount == null || productConfigCount == 0) {
-                String[][] domainMapping = {
-                        {"action", "action"}, {"mind", "mind"}, {"body", "body"},
-                        {"wisdom", "wisdom"}, {"wealth", "wealth"}
-                };
-                for (String[] mapping : domainMapping) {
-                    jdbcTemplate.execute(
-                            "INSERT INTO energy_source_config (source_type, source_id, source_name, dimension_id, ratio) " +
-                                    "SELECT 'product', p.id, p.name, d.id, 10000 " +
-                                    "FROM products p " +
-                                    "JOIN energy_dimension d ON d.code = '" + mapping[1] + "' " +
-                                    "WHERE p.domain = '" + mapping[0] + "' " +
-                                    "AND NOT EXISTS (" +
-                                    "  SELECT 1 FROM energy_source_config esc " +
-                                    "  WHERE esc.source_type = 'product' AND esc.source_id = p.id" +
-                                    ")"
-                    );
-                }
-                log.info("已有商品能量比例配置已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化商品能量比例配置失败: {}", e.getMessage());
-        }
-
-        // ==================== 精准营养 P0: health_report_survey =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_report_survey (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL COMMENT '关联报告ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                    "survey_data JSON COMMENT '调研问卷结果JSON', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_report (report_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告调研问卷'");
-            log.info("已创建 health_report_survey 表");
-        } catch (Exception e) {
-            log.warn("创建 health_report_survey 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 精准营养 P0: health_gut_flora + health_disease_risk =============
-        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_gut_flora (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL COMMENT '关联报告ID', " +
-                    "bacteria_name VARCHAR(100) NULL COMMENT '菌种名称', " +
-                    "bacteria_value VARCHAR(50) COMMENT '菌种丰度值', " +
-                    "normal_range VARCHAR(100) COMMENT '正常范围', " +
-                    "status VARCHAR(20) COMMENT '状态: 正常/偏低/偏高', " +
-                    "category VARCHAR(50) COMMENT '分类: 有益菌/有害菌/中性菌', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_report (report_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菌群检测专项数据'");
-            log.info("已创建 health_gut_flora 表");
-        } catch (Exception e) {
-            log.warn("创建 health_gut_flora 表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_disease_risk (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL COMMENT '关联报告ID', " +
-                    "disease_name VARCHAR(100) NOT NULL COMMENT '疾病名称', " +
-                    "risk_value VARCHAR(50) COMMENT '风险值(0-1)', " +
-                    "risk_level VARCHAR(20) COMMENT '风险等级: 高风险/需注意/低风险', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_report (report_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='疾病风险评估数据'");
-            log.info("已创建 health_disease_risk 表");
-        } catch (Exception e) {
-            log.warn("创建 health_disease_risk 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: health_reports 表添加新字段 =============        
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN balance_score INT DEFAULT NULL COMMENT '菌群平衡分'");
-            log.info("已添加balance_score列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN diversity_score INT DEFAULT NULL COMMENT '菌群多样性分'");
-            log.info("已添加diversity_score列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN beneficial_score INT DEFAULT NULL COMMENT '有益菌评分'");
-            log.info("已添加beneficial_score列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN harmful_score INT DEFAULT NULL COMMENT '有害菌评分'");
-            log.info("已添加harmful_score列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN core_genus_score INT DEFAULT NULL COMMENT '核心菌属评分'");
-            log.info("已添加core_genus_score列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移: health_reports 表添加报告编号和姓名字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN report_number VARCHAR(50) DEFAULT NULL COMMENT '报告编号'");
-            log.info("已添加report_number列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN person_name VARCHAR(50) DEFAULT NULL COMMENT '被检测人姓名'");
-            log.info("已添加person_name列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // ==================== 迁移: health_gut_flora 表添加新字段 =============        
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora ADD COLUMN population_level VARCHAR(50) DEFAULT NULL COMMENT '处于人群%水平'");
-            log.info("已添加population_level列到health_gut_flora表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora ADD COLUMN detection_rate VARCHAR(50) DEFAULT NULL COMMENT '%正常人有检出'");
-            log.info("已添加detection_rate列到health_gut_flora表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora ADD COLUMN description TEXT DEFAULT NULL COMMENT '菌种说明'");
-            log.info("已添加description列到health_gut_flora表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora ADD COLUMN `level` VARCHAR(20) DEFAULT 'GENUS' COMMENT '级别: GENUS/SPECIES'");
-            log.info("已添加level列到health_gut_flora表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // ==================== 迁移: guides 表统一 ======        // 迁移: guides 添加 type 字段(区分服务商类型)
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN type VARCHAR(32) DEFAULT 'teacher' COMMENT '服务商类型: teacher/planner/activity_provider/product_supplier'");
-            log.info("已添加type列到guides表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移: guides 添加 teachers 合并字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN teacher_no VARCHAR(20) COMMENT '服务商编号'");
-            log.info("已添加teacher_no列到guides表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN title VARCHAR(50) COMMENT '职称/称号'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN specialty VARCHAR(200) COMMENT '专长领域'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN bio TEXT COMMENT '简介'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN experience_years TINYINT DEFAULT 0 COMMENT '从业年限'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN rating INT DEFAULT 500 COMMENT '评分(百分位,500=5.00)'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN total_appointments INT DEFAULT 0 COMMENT '总服务次数'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN street_id BIGINT COMMENT '街道ID'");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN province VARCHAR(50) COMMENT '省份'");
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN city VARCHAR(50) COMMENT '城市'");
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN district VARCHAR(50) COMMENT '区县'");
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN street VARCHAR(100) COMMENT '街道'");
-            log.info("已添加地址字段到guides表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guides ADD COLUMN verified_at DATETIME COMMENT '审核通过时间'");
-        } catch (Exception e) {
-        }
-
-        // 迁移: 将 teachers 表数据合并到 guides(type='teacher')
-        try {
-            int migrated = jdbcTemplate.update(
-                    "INSERT IGNORE INTO guides (user_id, type, teacher_no, title, specialty, bio, experience_years, rating, total_appointments, " +
-                            "street_id, province, city, district, street, verified_at, status, level, created_at, updated_at) " +
-                            "SELECT t.user_id, 'teacher', t.teacher_no, t.title, t.specialty, t.bio, t.experience_years, t.rating, t.total_appointments, " +
-                            "t.street_id, t.province, t.city, t.district, t.street, t.verified_at, " +
-                            "CASE WHEN t.status = 'active' THEN 'active' ELSE 'inactive' END, " +
-                            "CASE WHEN t.verification_status = 'approved' THEN 'senior' WHEN t.verification_status = 'pending' THEN 'junior' ELSE 'junior' END, " +
-                            "t.created_at, t.updated_at " +
-                            "FROM teachers t " +
-                            "LEFT JOIN guides g ON g.user_id = t.user_id " +
-                            "WHERE g.id IS NULL"
-            );
-            if (migrated > 0) {
-                log.info("已从 teachers 表迁移 {} 条数据到 guides(type=teacher)", migrated);
-            }
-        } catch (Exception e) {
-            log.warn("迁移 teachers → guides 数据失败: {}", e.getMessage());
-        }
-
-        // 迁移: dan_assessment_results 表添加认知维度字段(6维认知体系扩展)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = 'perception_score'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE dan_assessment_results " +
-                        "ADD COLUMN perception_score INT COMMENT '感知得分', " +
-                        "ADD COLUMN spatial_score INT COMMENT '空间思维得分', " +
-                        "ADD COLUMN processing_speed_score INT COMMENT '加工速度得分'");
-                log.info("已为 dan_assessment_results 表添加认知维度字段");
-            } else {
-                log.info("dan_assessment_results 认知维度字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 dan_assessment_results 认知维度字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: dan_assessment_results 表添加 EMI 维度字段(v1.2 心智模型重构)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = 'emotion_management_score'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE dan_assessment_results " +
-                        "ADD COLUMN emotion_management_score INT COMMENT '情绪管理得分(EMI)', " +
-                        "ADD COLUMN empathy_score INT COMMENT '同理心得分(EMI)', " +
-                        "ADD COLUMN social_adaptability_score INT COMMENT '社会适应得分(EMI)', " +
-                        "ADD COLUMN self_motivation_score INT COMMENT '自我激励得分(EMI)'");
-                log.info("已为 dan_assessment_results 表添加 EMI 维度字段");
-            } else {
-                log.info("dan_assessment_results EMI 维度字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 dan_assessment_results EMI 维度字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: dan_assessment_results 表添加 EMI 心理子维度字段
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = 'emotion_score'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE dan_assessment_results " +
-                        "ADD COLUMN emotion_score INT COMMENT '情绪商数(0-100)', " +
-                        "ADD COLUMN resilience_score INT COMMENT '心理韧性(0-100)', " +
-                        "ADD COLUMN stress_coping_score INT COMMENT '压力应对(0-100)', " +
-                        "ADD COLUMN self_awareness_score INT COMMENT '自我认知(0-100)'");
-                log.info("已为 dan_assessment_results 表添加 EMI 心理子维度字段");
-            } else {
-                log.info("dan_assessment_results EMI 心理子维度字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 dan_assessment_results EMI 心理子维度字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: dan_assessment_results 表添加大五人格维度字段
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = 'openness_score'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE dan_assessment_results " +
-                        "ADD COLUMN openness_score INT COMMENT '开放性(0-100)', " +
-                        "ADD COLUMN conscientiousness_score INT COMMENT '尽责性(0-100)', " +
-                        "ADD COLUMN extraversion_score INT COMMENT '外向性(0-100)', " +
-                        "ADD COLUMN agreeableness_score INT COMMENT '宜人性(0-100)', " +
-                        "ADD COLUMN neuroticism_score INT COMMENT '神经质(0-100)', " +
-                        "ADD COLUMN big_five_overall_score INT COMMENT '大五人格综合分'");
-                log.info("已为 dan_assessment_results 表添加大五人格维度字段");
-            } else {
-                log.info("dan_assessment_results 大五人格维度字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 dan_assessment_results 大五人格维度字段失败: {}", e.getMessage());
-        }
-
-        // 迁移: users 表添加出生时辰字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN birth_hour VARCHAR(10) COMMENT '出生时辰: 子丑寅卯辰巳午未申酉戌亥'");
-            log.info("已添加birth_hour列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移: 重建 family_member_attributes 表结构(v1.2 心智模型)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'family_member_attributes' AND COLUMN_NAME = 'member_id'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                // 旧表存在但结构不同,先删除旧表重建
-                jdbcTemplate.execute("DROP TABLE IF EXISTS family_member_attributes_old");
-                jdbcTemplate.execute("RENAME TABLE family_member_attributes TO family_member_attributes_old");
-                jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_member_attributes (" +
-                        "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                        "member_id BIGINT NOT NULL COMMENT '家庭成员ID(children表或users表)', " +
-                        "member_type VARCHAR(10) NOT NULL COMMENT '成员类型: child/parent', " +
-                        "birth_datetime DATETIME COMMENT '出生日期(精确到分钟,用于八字排盘)', " +
-                        "eight_characters JSON COMMENT '八字四柱JSON', " +
-                        "wuxing_elements JSON COMMENT '五行星盘元素JSON', " +
-                        "zodiac VARCHAR(16) COMMENT '生肖: rat/ox/tiger/rabbit/dragon/snake/horse/sheep/monkey/rooster/dog/pig', " +
-                        "blood_type VARCHAR(5) COMMENT '血型: A/B/AB/O', " +
-                        "mind_base_score INT DEFAULT 0 COMMENT '心维度基础分(百分位,500=5.00)', " +
-                        "wisdom_base_score INT DEFAULT 0 COMMENT '智维度基础分(百分位,500=5.00)', " +
-                        "behavior_modifier JSON COMMENT '行为修正因子JSON', " +
-                        "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                        "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                        "UNIQUE KEY uk_member (member_id, member_type)" +
-                        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员先天属性表'");
-                log.info("已重建 family_member_attributes 表(v1.2 心智模型)");
-            } else {
-                log.info("family_member_attributes 表已为 v1.2 结构,跳过");
-            }
-} catch (Exception e) {
-            log.warn("重建 family_member_attributes 表失败: {}", e.getMessage());
-        }
-
-
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'users' AND COLUMN_NAME = 'show_to_family'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE users ADD COLUMN show_to_family TINYINT DEFAULT 1 COMMENT '是否对家庭成员可见: 1=是, 0=否'");
-                log.info("已为 users 表添加 show_to_family 列");
-            } else {
-                log.info("users 表 show_to_family 列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 users 表 show_to_family 列失败: {}", e.getMessage());
-        }
-
-        // 迁移: tasks 表添加 family_member_id 列(FamilyMember 迁移)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'tasks' AND COLUMN_NAME = 'family_member_id'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN family_member_id BIGINT COMMENT '家庭成员ID(关联 family_members.id)'");
-                log.info("已为 tasks 表添加 family_member_id 列");
-            } else {
-                log.info("tasks 表 family_member_id 列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 tasks 表 family_member_id 列失败: {}", e.getMessage());
-        }
-
-        // 迁移: family_members 表添加 role_override 列(FamilyMember 迁移)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'family_members' AND COLUMN_NAME = 'role_override'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN role_override VARCHAR(20) DEFAULT 'auto' COMMENT '角色覆盖: auto/parent/child/elderly,空=auto'");
-                log.info("已为 family_members 表添加 role_override 列");
-            } else {
-                log.info("family_members 表 role_override 列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 family_members 表 role_override 列失败: {}", e.getMessage());
-        }
-
-        // 迁移: family_members 表添加 id_card 列(孩子身份证号)
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'family_members' AND COLUMN_NAME = 'id_card'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN id_card VARCHAR(18) DEFAULT NULL COMMENT '身份证号(孩子)'");
-                log.info("已为 family_members 表添加 id_card 列");
-            } else {
-                log.info("family_members 表 id_card 列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加 family_members 表 id_card 列失败: {}", e.getMessage());
-        }
-
-        // 迁移: family_members 表添加孩子专属字段(原children表合并)
-        String[][] childColumns = {
-                {"penalty_enabled", "TINYINT DEFAULT 1 COMMENT '是否扣减积分(0否1是)'"},
-                {"theme", "VARCHAR(32) DEFAULT 'default' COMMENT '主题'"},
-                {"system_points", "INT DEFAULT 0 COMMENT '系统积分(干预/平台奖励)'"},
-                {"streak_days", "INT DEFAULT 0 COMMENT '连续打卡天数'"},
-                {"last_task_date", "DATE COMMENT '上次任务日期'"},
-                {"focus_max_daily", "TINYINT DEFAULT 3 COMMENT '每日专注上限'"},
-                {"focus_remaining", "TINYINT DEFAULT 3 COMMENT '今日剩余专注次数'"},
-                {"focus_reset_date", "DATE COMMENT '专注次数重置日期'"}
-        };
-        for (String[] col : childColumns) {
-            try {
-                Integer colExists = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'family_members' AND COLUMN_NAME = ?",
-                        Integer.class, col[0]);
-                if (colExists == null || colExists == 0) {
-                    jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN " + col[0] + " " + col[1]);
-                    log.info("已为 family_members 表添加 {} 列", col[0]);
-                }
-            } catch (Exception e) {
-                log.warn("检查/添加 family_members 表 {} 列失败: {}", col[0], e.getMessage());
-            }
-        }
-
-        // 家庭成员表添加 role_override 列(替换旧 capability_role)
-        ensureColumn("family_members", "role_override", "VARCHAR(20) DEFAULT 'auto' COMMENT '角色覆盖: auto/parent/child/elderly'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members DROP COLUMN capability_role");
-            log.info("已删除 family_members.capability_role 旧列,已由 role_override 替代");
-        } catch (Exception e) {
-            // 列不存在或已删除,忽略错误
-        }
-
-        // activities 表添加报名/签到相关字段
-        ensureColumn("activities", "require_registration", "TINYINT DEFAULT 1 COMMENT '是否需要报名: 1=需要, 0=直接参与'");
-        ensureColumn("activities", "require_checkin_review", "TINYINT DEFAULT 1 COMMENT '打卡是否需要审核: 1=需要, 0=直接通过'");
-        ensureColumn("activities", "energy_penalty_unregistered", "INT DEFAULT 5 COMMENT '未报名打卡的行能量扣减值'");
-
-        // family_members 表添加关系评分字段
-        ensureColumn("family_members", "trust_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '信任度 0-100'");
-        ensureColumn("family_members", "intimacy_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度 0-100'");
-        ensureColumn("family_members", "communication_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量 0-100'");
-        ensureColumn("family_members", "last_interaction_at", "DATETIME COMMENT '最近互动时间'");
-
-        // 创建购物车表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS cart (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID', " +
-                    "quantity INT NOT NULL DEFAULT 1 COMMENT '数量', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_product (user_id, product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车'");
-            log.info("已创建 cart 表");
-        } catch (Exception e) {
-            log.warn("创建 cart 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: activities表添加visible_scope列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'visible_scope'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN visible_scope VARCHAR(20) DEFAULT NULL COMMENT '可见范围: family(家庭)/role(角色)/user(用户)' AFTER visibility");
-                log.info("已添加visible_scope列到activities表");
-            } else {
-                log.info("activities表visible_scope列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities表visible_scope列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: articles表添加article_type列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'articles' AND COLUMN_NAME = 'article_type'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN article_type VARCHAR(20) DEFAULT 'normal' COMMENT '文章类型: normal(普通)/premium(优质)/original(原创)' AFTER read_time");
-                log.info("已添加article_type列到articles表");
-            } else {
-                log.info("articles表article_type列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加articles表article_type列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: articles表添加word_count列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'articles' AND COLUMN_NAME = 'word_count'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE articles ADD COLUMN word_count INT DEFAULT 0 COMMENT '文章字数' AFTER article_type");
-                log.info("已添加word_count列到articles表");
-            } else {
-                log.info("articles表word_count列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加articles表word_count列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: article_reading_records表添加task_id列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'article_reading_records' AND COLUMN_NAME = 'task_id'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE article_reading_records ADD COLUMN task_id BIGINT DEFAULT NULL COMMENT '关联的任务ID' AFTER duration_seconds");
-                log.info("已添加task_id列到article_reading_records表");
-            } else {
-                log.info("article_reading_records表task_id列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加article_reading_records表task_id列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: tasks表添加source_type列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'tasks' AND COLUMN_NAME = 'source_type'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN source_type VARCHAR(20) DEFAULT NULL COMMENT '来源类型: article/activity/manual' AFTER minigame_code");
-                log.info("已添加source_type列到tasks表");
-            } else {
-                log.info("tasks表source_type列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加tasks表source_type列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: tasks表添加source_id列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'tasks' AND COLUMN_NAME = 'source_id'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE tasks ADD COLUMN source_id BIGINT DEFAULT NULL COMMENT '来源ID' AFTER source_type");
-                log.info("已添加source_id列到tasks表");
-            } else {
-                log.info("tasks表source_id列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加tasks表source_id列失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移: activities表添加checkin_points列 =============        
-        try {
-            Integer colExists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'checkin_points'",
-                    Integer.class);
-            if (colExists == null || colExists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN checkin_points INT DEFAULT 0 COMMENT '签到积分(0=使用系统默认)' AFTER price");
-                log.info("已添加checkin_points列到activities表");
-            } else {
-                log.info("activities表checkin_points列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities表checkin_points列失败: {}", e.getMessage());
-        }
-
-        // 迁移: 创建family_invitations表(家庭邀请令牌)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_invitations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "token VARCHAR(64) NOT NULL UNIQUE COMMENT '邀请令牌(UUID)', " +
-                    "created_by BIGINT NOT NULL COMMENT '创建人用户ID', " +
-                    "status VARCHAR(16) DEFAULT 'active' COMMENT '状态: active/used/expired/revoked', " +
-                    "expires_at DATETIME COMMENT '过期时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_token (token), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭邀请令牌'");
-            log.info("已创建family_invitations表");
-        } catch (Exception e) {
-            log.warn("创建family_invitations表失败: {}", e.getMessage());
-        }
-
-        // ==================== P0 营养师: nutrition_indicator_mapping =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS nutrition_indicator_mapping (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "indicator_name_pattern VARCHAR(200) NOT NULL COMMENT '指标名匹配模式(SQL LIKE语法,%为通配符)'," +
-                    "nutrient VARCHAR(50) NOT NULL COMMENT '关联营养素名'," +
-                    "severity_weight DECIMAL(3,2) DEFAULT 1.00 COMMENT '权重(0-1)'," +
-                    "deficiency_symptoms TEXT COMMENT '缺乏症状描述'," +
-                    "excess_symptoms TEXT COMMENT '过量症状描述'," +
-                    "food_suggestions TEXT COMMENT '推荐食物(逗号分隔)'," +
-                    "sort_order INT DEFAULT 0 COMMENT '排序(大值优先匹配)'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_nutrient (nutrient)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标-营养素映射表'");
-            log.info("已创建 nutrition_indicator_mapping 表");
-        } catch (Exception e) {
-            log.warn("创建 nutrition_indicator_mapping 表失败: {}", e.getMessage());
-        }
-
-        // P0 营养师: nutrition_deficiency_record
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS nutrition_deficiency_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "child_id BIGINT NOT NULL COMMENT '孩子ID'," +
-                    "report_id BIGINT NOT NULL COMMENT '关联报告ID'," +
-                    "nutrient VARCHAR(50) NOT NULL COMMENT '营养素名'," +
-                    "deficiency_type VARCHAR(20) NOT NULL COMMENT 'deficiency/excess/borderline/unclassified'," +
-                    "severity DECIMAL(5,2) DEFAULT 0 COMMENT '严重程度(0-1)'," +
-                    "indicator_name VARCHAR(100) COMMENT '关联指标名'," +
-                    "indicator_value VARCHAR(50) COMMENT '指标检测值'," +
-                    "ref_range VARCHAR(100) COMMENT '参考范围'," +
-                    "symptoms TEXT COMMENT '症状描述'," +
-                    "food_suggestions TEXT COMMENT '推荐食物'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "INDEX idx_child (child_id)," +
-                    "INDEX idx_report (report_id)," +
-                    "INDEX idx_nutrient (nutrient)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养缺乏分析记录'");
-            log.info("已创建 nutrition_deficiency_record 表");
-        } catch (Exception e) {
-            log.warn("创建 nutrition_deficiency_record 表失败: {}", e.getMessage());
-        }
-
-        // P0 营养师: 指标-营养素映射 种子数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM nutrition_indicator_mapping", Integer.class);
-            if (count == null || count == 0) {
-                String[][] seedData = {
-                        {"铁蛋白", "铁", "1.00", "乏力、面色苍白、注意力不集中", "铁过量可能损伤肝脏", "动物肝脏,红肉,菠菜,黑木耳", "10"},
-                        {"25-羟基维生素D", "维生素D", "1.00", "影响钙吸收、骨骼发育", "维生素D过量可致高钙血症", "三文鱼,蛋黄,蘑菇,强化牛奶", "20"},
-                        {"维生素D", "维生素D", "1.00", "影响钙吸收、骨骼发育、免疫力下降", "维生素D过量可致高钙血症", "三文鱼,蛋黄,蘑菇,强化牛奶", "15"},
-                        {"锌", "锌", "0.80", "食欲减退、味觉异常、免疫力降低", "锌过量影响铜吸收", "牡蛎,牛肉,南瓜子,扁豆", "10"},
-                        {"钙", "钙", "0.80", "骨骼发育迟缓、牙齿问题", "高钙血症、肾结石", "牛奶,豆腐,虾皮,芝麻酱", "10"},
-                        {"维生素B12", "维生素B12", "1.00", "贫血、神经发育迟缓", "一般不易过量", "牛肉,鸡蛋,牛奶,鱼肉", "10"},
-                        {"维生素C", "维生素C", "0.60", "免疫力下降、牙龈出血", "腹泻、肾结石风险", "猕猴桃,橙子,草莓,青椒", "10"},
-                        {"白蛋白", "蛋白质", "0.90", "发育迟缓、肌肉萎缩", "肾脏负担", "鸡蛋,鱼肉,牛奶,豆制品", "10"},
-                        {"总蛋白", "蛋白质", "0.90", "营养不良、免疫力下降", "血液粘稠", "鸡蛋,鱼肉,牛奶,豆制品", "9"},
-                        {"膳食纤维", "膳食纤维", "0.50", "便秘、肠道菌群失衡", "腹胀、排便过多", "全谷物,蔬菜,豆类,水果", "10"},
-                        {"叶酸", "叶酸", "0.70", "贫血、发育迟缓", "一般不易过量", "菠菜,动物肝脏,豆类,柑橘", "10"},
-                        {"维生素A", "维生素A", "0.70", "视力问题、皮肤干燥、免疫力下降", "头痛、肝脏损伤", "胡萝卜,动物肝脏,南瓜,菠菜", "10"},
-                        {"硒", "硒", "0.50", "免疫力下降、甲状腺功能异常", "脱发、指甲脆裂", "巴西坚果,海鲜,蘑菇", "10"},
-                        {"镁", "镁", "0.40", "肌肉痉挛、睡眠问题", "腹泻、低血压", "坚果,全谷物,深绿蔬菜", "10"},
-                        {"益生菌%", "益生菌", "0.60", "肠道菌群失衡、消化问题", "一般不易过量", "酸奶,泡菜,味噌,康普茶", "10"}
-                };
-                for (String[] row : seedData) {
-                    jdbcTemplate.update("INSERT IGNORE INTO nutrition_indicator_mapping " +
-                                    "(indicator_name_pattern, nutrient, severity_weight, deficiency_symptoms, excess_symptoms, food_suggestions, sort_order) " +
-                                    "VALUES (?, ?, ?, ?, ?, ?, ?)",
-                            row[0], row[1], new java.math.BigDecimal(row[2]), row[3], row[4], row[5], Integer.parseInt(row[6]));
-                }
-                log.info("nutrition_indicator_mapping 种子数据已加载 (15条)");
-            } else {
-                log.info("nutrition_indicator_mapping 种子数据已存在 ({}条), 跳过", count);
-            }
-        } catch (Exception e) {
-            log.warn("nutrition_indicator_mapping 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // ==================== 心版块 Phase 1: emotion_checkin 表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS emotion_checkin (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '打卡人用户ID', " +
-                    "emotion_type INT NOT NULL COMMENT '情绪类型: 1快乐/2平和平静/3平静/4有点不舒服/5难受/6烦躁/7生气/8焦虑/9恐惧', " +
-                    "emotion_name VARCHAR(20) COMMENT '情绪名称: happy/calm/peaceful/uncomfortable/sad/irritable/angry/anxious/fearful', " +
-                    "energy_level INT NOT NULL DEFAULT 3 COMMENT '能量状态: 1很低/2低/3中等/4高/5很高', " +
-                    "note TEXT COMMENT '打卡备注', " +
-                    "photo_url VARCHAR(500) COMMENT '照片URL', " +
-                    "favorite_thing VARCHAR(500) COMMENT '今日最喜欢的一件事', " +
-                    "points_awarded INT DEFAULT 0 COMMENT '奖励积分', " +
-                    "parent_visible TINYINT DEFAULT 1 COMMENT '家长可见: 1可见/0不可见', " +
-                    "checkin_date DATE NOT NULL COMMENT '打卡日期', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_checkin_date (checkin_date), " +
-                    "INDEX idx_child_date (child_id, checkin_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪打卡表'");
-            log.info("已创建 emotion_checkin 情绪打卡表");
-        } catch (Exception e) {
-            log.warn("创建 emotion_checkin 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 1a-2: DAN Schema 修复 =============        // v1.2 EMI 心理子维度
-        String[] danEmiFields = {"emotion_score", "resilience_score", "stress_coping_score", "self_awareness_score"};
-        for (String field : danEmiFields) {
-            try {
-                Integer exists = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = ?",
-                        Integer.class, field);
-                if (exists == null || exists == 0) {
-                    jdbcTemplate.execute("ALTER TABLE dan_assessment_results ADD COLUMN " + field + " INT DEFAULT NULL COMMENT 'EMI子维度 0-100'");
-                    log.info("已添加 {} 列到 dan_assessment_results 表", field);
-                }
-            } catch (Exception e) {
-                log.warn("检查/添加 {} 列失败: {}", field, e.getMessage());
-            }
-        }
-        // 大五人格维度
-        String[] danBigFiveFields = {"openness_score", "conscientiousness_score", "extraversion_score", "agreeableness_score", "neuroticism_score", "big_five_overall_score"};
-        for (String field : danBigFiveFields) {
-            try {
-                Integer exists = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = ?",
-                        Integer.class, field);
-                if (exists == null || exists == 0) {
-                    jdbcTemplate.execute("ALTER TABLE dan_assessment_results ADD COLUMN " + field + " INT DEFAULT NULL COMMENT '大五人格 0-100'");
-                    log.info("已添加 {} 列到 dan_assessment_results 表", field);
-                }
-            } catch (Exception e) {
-                log.warn("检查/添加 {} 列失败: {}", field, e.getMessage());
-            }
-        }
-        // EMI 维度(情绪商数评估字段)
-        String[] danEmiDimFields = {"emotion_management_score", "empathy_score", "social_adaptability_score", "self_motivation_score"};
-        for (String field : danEmiDimFields) {
-            try {
-                Integer exists = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'dan_assessment_results' AND COLUMN_NAME = ?",
-                        Integer.class, field);
-                if (exists == null || exists == 0) {
-                    jdbcTemplate.execute("ALTER TABLE dan_assessment_results ADD COLUMN " + field + " INT DEFAULT NULL COMMENT 'EMI维度 0-100'");
-                    log.info("已添加 {} 列到 dan_assessment_results 表", field);
-                }
-            } catch (Exception e) {
-                log.warn("检查/添加 {} 列失败: {}", field, e.getMessage());
-            }
-        }
-
-        // ==================== 1b-1: bazi_reading_template 五行命理解读表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS bazi_reading_template (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "element VARCHAR(20) NOT NULL COMMENT '五行: wood/fire/earth/metal/water', " +
-                    "`condition` VARCHAR(20) NOT NULL COMMENT '状态: strong/weak/balanced', " +
-                    "personal_trait TEXT COMMENT '性格特质描述', " +
-                    "mind_growth_advice TEXT COMMENT '心理成长建议', " +
-                    "daily_tip_template TEXT COMMENT '每日宜忌模板', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_element_condition (element, `condition`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五行命理解读模板'");
-            log.info("已创建 bazi_reading_template 表");
-        } catch (Exception e) {
-            log.warn("创建 bazi_reading_template 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 1b-1: numsoul_config 生命灵数配置表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS numsoul_config (" +
-                    "number INT PRIMARY KEY COMMENT '灵数1-9', " +
-                    "title VARCHAR(50) NOT NULL COMMENT '称号', " +
-                    "keywords VARCHAR(200) COMMENT '性格关键词', " +
-                    "mind_growth_advice TEXT COMMENT '心理成长建议', " +
-                    "recommended_article_tags VARCHAR(200) COMMENT '关联文章标签', " +
-                    "color_hex VARCHAR(7) COMMENT '代表色' " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生命灵数配置'");
-            log.info("已创建 numsoul_config 表");
-        } catch (Exception e) {
-            log.warn("创建 numsoul_config 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 1b-1: bazi_reading_template 种子数据 =============        
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM bazi_reading_template", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.batchUpdate(
-                        "INSERT INTO bazi_reading_template (element, `condition`, personal_trait, mind_growth_advice, daily_tip_template) VALUES (?, ?, ?, ?, ?)",
-                        java.util.Arrays.asList(new Object[][]{
-                                {"wood", "strong", "性格坚韧、有进取心,具有领导力和开拓精神", "学会适当放松,避免过刚易折,培养弹性思维", "宜进行伸展运动,忌高强度冲突"},
-                                {"wood", "weak", "温和有礼、善于合作,但决策时容易犹豫", "增强自信心训练,培养果断决策能力", "宜与自然相处,忌过度迁就他人"},
-                                {"wood", "balanced", "性格中庸有度,既有韧性又有灵活性", "保持现状,适当拓展社交圈", "宜户外活动,忌久坐不动"},
-                                {"fire", "strong", "热情开朗、充满活力,富有感染力和创造力", "注意情绪管理,避免急躁冲动", "宜冷水刺激冷静,忌暴怒争执"},
-                                {"fire", "weak", "内敛含蓄、心思细腻,对艺术有敏锐感知", "适当表达情感,培养社交自信", "宜温暖陪伴,忌独处过久"},
-                                {"fire", "balanced", "性格温润有度,既有热情又懂克制", "保持兴趣爱好,适度拓展表达", "宜参与社交活动,忌情绪压抑"},
-                                {"earth", "strong", "稳重可靠、有责任心,是团队中的中流砥柱", "避免过度承担,学会说'不'", "宜适量运动,忌思虑过重"},
-                                {"earth", "weak", "随和友善、适应性强,容易与他人相处", "增强主见性,培养独立思考能力", "宜接触新事物,忌固守不变"},
-                                {"earth", "balanced", "性情敦厚、处事稳妥,人际关系和谐", "保持学习,适当挑战自我", "宜亲近自然,忌暴饮暴食"},
-                                {"metal", "strong", "意志坚定、追求完美,具有卓越的执行力", "学会灵活变通,避免过于严苛", "宜艺术鉴赏,忌过度批评"},
-                                {"metal", "weak", "温和寡言、善于倾听,是值得信赖的朋友", "增强表达勇气,培养自信心", "宜团体活动,忌过度自我封闭"},
-                                {"metal", "balanced", "为人正直、做事有度,不乏柔韧与包容", "保持开放心态,适度多元发展", "宜阅读学习,忌钻牛角尖"},
-                                {"water", "strong", "智慧深沉、善于谋略,具有出色洞察力", "避免过度缜密,适当放松心情", "宜静坐冥想,忌思虑过深"},
-                                {"water", "weak", "敏感细腻、有同理心,富有创作天赋", "增强抵抗力,培养情绪韧性", "宜温暖环境,忌受寒受凉"},
-                                {"water", "balanced", "性格圆融、随机应变,处事灵活得宜", "保持好奇心,适度扩展影响力", "宜游泳泡澡,忌情绪波动"},
-                        })
-                );
-                log.info("bazi_reading_template 种子数据已加载 (15条)");
-            }
-        } catch (Exception e) {
-            log.warn("bazi_reading_template 种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // ==================== 1b-1: numsoul_config 种子数据 =============        
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM numsoul_config", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.batchUpdate(
-                        "INSERT INTO numsoul_config (number, title, keywords, mind_growth_advice, recommended_article_tags, color_hex) VALUES (?, ?, ?, ?, ?, ?)",
-                        java.util.Arrays.asList(new Object[][]{
-                                {1, "开创者", "独立、领导、创新、自信", "培养团队协作意识,避免独断专行", "领导力,自信培养", "#FF4444"},
-                                {2, "和平者", "温和、合作、敏感、耐心", "增强自我主张,避免过度迎合他人", "人际交往,情绪表达", "#FF8C00"},
-                                {3, "表达者", "创意、社交、乐观、表达", "保持专注,避免浅尝辄止", "创造力,社交能力", "#FFD700"},
-                                {4, "建设者", "务实、稳定、有序、勤奋", "学会变通,避免过于固执", "专注力,学习习惯", "#4CAF50"},
-                                {5, "自由者", "冒险、变化、好奇、灵活", "培养持久力,避免缺乏恒心", "探索精神,适应能力", "#2196F3"},
-                                {6, "关怀者", "责任、关爱、奉献、平衡", "学会自我关爱,避免过度付出", "家庭关系,责任心", "#9C27B0"},
-                                {7, "探索者", "智慧、分析、内省、完美", "与人分享见解,避免过度封闭", "思维能力,学习力", "#673AB7"},
-                                {8, "成就者", "雄心、管理、决策、权威", "关注内在成长,避免过于追求外在成就", "目标管理,理财思维", "#3F51B5"},
-                                {9, "博爱者", "包容、智慧、善良、豁达", "设定个人边界,避免过度牺牲", "人际关系,情绪管理", "#E91E63"},
-                        })
-                );
-                log.info("numsoul_config 种子数据已加载 (9条)");
-            }
-        } catch (Exception e) {
-            log.warn("numsoul_config 种子数据初始化失败: {}", e.getMessage());
-        }
-
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_address (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "receiver_name VARCHAR(50) NOT NULL COMMENT '收货人姓名', " +
-                    "phone VARCHAR(20) NOT NULL COMMENT '收货人电话', " +
-                    "province VARCHAR(50) COMMENT '省份', " +
-                    "city VARCHAR(50) COMMENT '城市', " +
-                    "district VARCHAR(50) COMMENT '区县', " +
-                    "street VARCHAR(200) COMMENT '详细地址', " +
-                    "is_default INT DEFAULT 0 COMMENT '是否默认 1=是 0=否', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收货地址表'");
-            log.info("已创建 user_address 表");
-        } catch (Exception e) {
-            log.warn("创建 user_address 表失败: {}", e.getMessage());
-        }
-
-        // ==================== 会员价格体系 ======        // 迁移: activities表添加member_price列
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'activities' AND COLUMN_NAME = 'member_price'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN member_price INT COMMENT '会员价(分)' AFTER price");
-                log.info("已添加member_price列到activities表");
-            } else {
-                log.info("member_price列已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加activities.member_price失败: {}", e.getMessage());
-        }
-
-        // 迁移: 创建 member_discount_configs 表(分类级别折扣配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS member_discount_configs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "level_code VARCHAR(20) NOT NULL COMMENT '会员等级: FAMILY/PROVIDER', " +
-                    "target_type VARCHAR(20) NOT NULL COMMENT '目标类型: product/activity', " +
-                    "target_id BIGINT DEFAULT NULL COMMENT '目标ID(NULL表示分类级别)', " +
-                    "category_id BIGINT DEFAULT NULL COMMENT '类目ID(分类级别折扣)', " +
-                    "discount_percent INT NOT NULL COMMENT '折扣百分比(如90表示90%)', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '是否启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_level (level_code), " +
-                    "INDEX idx_target (target_type, target_id), " +
-                    "INDEX idx_category (target_type, category_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员折扣配置'");
-            log.info("已创建member_discount_configs表");
-        } catch (Exception e) {
-            log.warn("创建member_discount_configs表失败: {}", e.getMessage());
-        }
-
-        // ==================== 食材推荐指数 Phase: food_recommend_idx / food_recommend_idx_log =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `food_recommend_idx` (" +
-                    "`id` BIGINT NOT NULL AUTO_INCREMENT, " +
-                    "`user_id` BIGINT NOT NULL COMMENT '用户ID', " +
-                    "`food_id` BIGINT NOT NULL COMMENT '食材ID', " +
-                    "`food_name` VARCHAR(100) COMMENT '食材名称', " +
-                    "`index_score` INT NOT NULL DEFAULT 0 COMMENT '推荐指数(0-100, 来自菌群检测报告)', " +
-                    "`health_report_id` BIGINT COMMENT '关联健康报告ID', " +
-                    "`calculated_at` DATETIME COMMENT '计算时间', " +
-                    "`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "PRIMARY KEY (`id`), " +
-                    "INDEX `idx_fri_user` (`user_id`), " +
-                    "INDEX `idx_fri_food` (`food_id`), " +
-                    "UNIQUE KEY `uk_fri_user_food` (`user_id`, `food_id`) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材推荐指数当前值'");
-            log.info("已创建/确认 food_recommend_idx 表");
-        } catch (Exception e) {
-            log.warn("创建 food_recommend_idx 表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `food_recommend_idx_log` (" +
-                    "`id` BIGINT NOT NULL AUTO_INCREMENT, " +
-                    "`user_id` BIGINT NOT NULL COMMENT '用户ID', " +
-                    "`food_id` BIGINT NOT NULL COMMENT '食材ID', " +
-                    "`food_name` VARCHAR(100) COMMENT '食材名称', " +
-                    "`previous_index` INT COMMENT '变更前推荐指数', " +
-                    "`new_index` INT COMMENT '变更后推荐指数', " +
-                    "`health_report_id` BIGINT COMMENT '触发的健康报告ID', " +
-                    "`change_reason` VARCHAR(200) COMMENT '变更原因', " +
-                    "`changed_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "PRIMARY KEY (`id`), " +
-                    "INDEX `idx_fril_user` (`user_id`), " +
-                    "INDEX `idx_fril_food` (`food_id`) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材推荐指数变更历史日志'");
-            log.info("已创建/确认 food_recommend_idx_log 表");
-        } catch (Exception e) {
-            log.warn("创建 food_recommend_idx_log 表失败: {}", e.getMessage());
-        }
-
-        // 迁移25: activities表添加审核相关字段(活动工作流:待审核/驳回/发布)
-        try {
-            jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN audit_status VARCHAR(20) DEFAULT NULL COMMENT '审核状态:approved/pending/rejected'");
-            log.info("已添加audit_status列到activities表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN audit_reason VARCHAR(500) DEFAULT NULL COMMENT '驳回原因'");
-            log.info("已添加audit_reason列到activities表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN auditor_id BIGINT DEFAULT NULL COMMENT '审核人ID'");
-            log.info("已添加auditor_id列到activities表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE activities ADD COLUMN audited_at DATETIME DEFAULT NULL COMMENT '审核时间'");
-            log.info("已添加audited_at列到activities表");
-        } catch (Exception e) {
-
-        }
-
-        // 家庭挑战:目标模式与目标值(aggregate=集体总合目标 / all_members=全员个人目标)
-        ensureColumn("family_challenge", "target_mode", "VARCHAR(20) DEFAULT 'aggregate' COMMENT '目标模式: aggregate=集体总合/all_members=全员个人目标'");
-        ensureColumn("family_challenge", "target_value", "INT DEFAULT 0 COMMENT '目标值(aggregate=家庭合计值, all_members=每人目标值)'");
-        // 迁移: family_challenge 表添加回复时效字段(待同意成员超时未回复自动拒绝)
-        ensureColumn("family_challenge", "respond_deadline", "DATETIME NULL COMMENT '回复时效截止时间(超过后未回复的 pending 成员自动置为 rejected)'");
-
-        // 迁移248: 创建 health_report_edit_logs 表(健康报告修改留痕,原迁移222误置于initializeDefaultData中仅测试环境执行)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_report_edit_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL, " +
-                    "user_id BIGINT, " +
-                    "report_type VARCHAR(32), " +
-                    "action VARCHAR(20) COMMENT 'create/edit', " +
-                    "before_payload LONGTEXT, " +
-                    "after_payload LONGTEXT, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_report_id (report_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告修改留痕'");
-            log.info("已创建health_report_edit_logs表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移249: file_record 表添加 file_type 和 description 列(原迁移221/228误置于seedFullRegionData中,区域数据非空时永不执行)
-
-        // 迁移250: health_plans 添加 plan_json 和 status 列(支持结构化方案编辑)
-        try {
-            ensureColumn("health_plans", "plan_json", "JSON COMMENT '结构化方案内容(总览+营养+饮食+运动)'");
-        } catch (Exception e) {
-            log.warn("health_plans.plan_json 添加失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            ensureColumn("health_plans", "status", "VARCHAR(20) DEFAULT 'draft' COMMENT '方案状态: draft(草稿)/pending_review(待审核)/published(已发布)/rejected(已驳回)'");
-        } catch (Exception e) {
-            log.warn("health_plans.status 添加失败(可能已存在): " + e.getMessage());
-        }
-        // 迁移250: health_plans 新增审核字段(规划师/营养师方案维护流程)
-        try {
-            ensureColumn("health_plans", "reviewed_by", "BIGINT DEFAULT NULL COMMENT '审核人ID(规划师/营养师)'");
-            ensureColumn("health_plans", "reviewed_at", "DATETIME DEFAULT NULL COMMENT '审核时间'");
-            ensureColumn("health_plans", "review_comment", "TEXT DEFAULT NULL COMMENT '审核意见'");
-        } catch (Exception e) {
-            log.warn("health_plans 审核字段添加失败(可能已存在): " + e.getMessage());
-        }
-        // 迁移251: health_plans 新增 teacher_id 列(用户指定规划师)
-        try {
-            ensureColumn("health_plans", "teacher_id", "BIGINT DEFAULT NULL COMMENT '指定规划师ID(用户选择)'");
-        } catch (Exception ex) {
-            log.warn("health_plans.teacher_id 添加失败(可能已存在): " + ex.getMessage());
-        }
-        // 迁移251b: health_plans 新增 updated_at 列(实体HealthPlan含该字段,缺失导致selectById报Unknown column)
-        try {
-            ensureColumn("health_plans", "updated_at", "DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'");
-        } catch (Exception ex) {
-            log.warn("health_plans.updated_at 添加失败(可能已存在): " + ex.getMessage());
-        }
-        // 迁移251c: finance_checkins.child_id 允许NULL(家长本人打卡不选孩子,Service已支持childId为空;原NOT NULL无默认值导致INSERT报错)
-        try {
-            jdbcTemplate.execute("ALTER TABLE finance_checkins MODIFY COLUMN child_id BIGINT NULL COMMENT '孩子ID,家长本人打卡时为NULL'");
-            log.info("已修改finance_checkins.child_id字段允许NULL");
-        } catch (Exception e) {
-            log.warn("finance_checkins.child_id 修改失败: " + e.getMessage());
-        }
-        // 迁移251c: finance_checkins 补齐 type 列(initGuideModuleTables建表版本缺失,实体FinanceCheckin含type字段且收支统计依赖)
-        try {
-            ensureColumn("finance_checkins", "type", "VARCHAR(10) DEFAULT 'expense' COMMENT '类型: income(收入)/expense(支出)'");
-        } catch (Exception e) {
-            log.warn("finance_checkins.type 添加失败(可能已存在): " + e.getMessage());
-        }
-        // 迁移258: 创建energy_daily_limit表(每日能量上限配置持久化)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS energy_daily_limit (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "dimension_code VARCHAR(20) NOT NULL COMMENT '维度代码: body/mind/wisdom/action/wealth', " +
-                    "daily_limit INT NOT NULL DEFAULT 50 COMMENT '每日能量上限', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_dimension_code (dimension_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日能量上限配置'");
-            log.info("已创建energy_daily_limit表");
-            // 插入默认数据(幂等)
-            jdbcTemplate.execute("INSERT IGNORE INTO energy_daily_limit (dimension_code, daily_limit) VALUES " +
-                    "('body', 50), ('mind', 50), ('wisdom', 80), ('action', 60), ('wealth', 50)");
-            log.info("已插入energy_daily_limit默认数据");
-        } catch (Exception ex) {
-            log.warn("energy_daily_limit 表创建失败(可能已存在): " + ex.getMessage());
-        }
-        // 迁移251d: diet_preferences 补齐 must_eat 列(实体DietPreferences含mustEat字段,建表时两处均遗漏,查询报Unknown column)
-        try {
-            ensureColumn("diet_preferences", "must_eat", "JSON COMMENT '必吃食物列表'");
-        } catch (Exception e) {
-            log.warn("diet_preferences.must_eat 添加失败(可能已存在): " + e.getMessage());
-        }
-        ensureColumn("file_record", "file_type", "VARCHAR(50) DEFAULT NULL COMMENT '文件类型: image/pdf/video/audio/other'");
-        ensureColumn("file_record", "description", "TEXT COMMENT '文件描述'");
-
-        log.info("数据库迁移完成");
-
-        // 迁移252: 体素/心理/认知指标定义种子数据
-        try {
-            Object[][] rows = {
-                    {"body", "nutrition", "body_fat", "体脂率(%)", "18-28", "1"},
-                    {"body", "nutrition", "bmi", "BMI指数", "18.5-24", "2"},
-                    {"body", "nutrition", "protein", "蛋白质摄入(g/日)", "50-80", "3"},
-                    {"body", "nutrition", "calcium", "钙摄入(mg/日)", "800-1000", "4"},
-                    {"body", "nutrition", "vitamin_d", "维生素D(ng/ml)", "30-100", "5"},
-                    {"body", "chronic", "blood_pressure_systolic", "收缩压(mmHg)", "90-120", "1"},
-                    {"body", "chronic", "blood_pressure_diastolic", "舒张压(mmHg)", "60-80", "2"},
-                    {"body", "chronic", "blood_sugar_fasting", "空腹血糖(mmol/L)", "3.9-6.1", "3"},
-                    {"body", "chronic", "cholesterol_total", "总胆固醇(mmol/L)", "3.1-5.2", "4"},
-                    {"body", "chronic", "triglyceride", "甘油三酯(mmol/L)", "0.56-1.7", "5"},
-                    {"body", "exercise", "step_count", "日均步数", "6000-10000", "1"},
-                    {"body", "exercise", "sleep_duration", "睡眠时长(小时)", "7-9", "2"},
-                    {"mind", "emotion", "emotion_stability", "情绪稳定性", "0-100", "1"},
-                    {"mind", "emotion", "anxiety_level", "焦虑水平", "0-100", "2"},
-                    {"mind", "emotion", "sleep_quality", "睡眠质量", "0-100", "3"},
-                    {"mind", "personality", "openness", "开放性", "0-100", "1"},
-                    {"mind", "personality", "conscientiousness", "尽责性", "0-100", "2"},
-                    {"mind", "personality", "extraversion", "外向性", "0-100", "3"},
-                    {"mind", "personality", "agreeableness", "宜人性", "0-100", "4"},
-                    {"mind", "personality", "neuroticism", "神经质(反向)", "0-100", "5"},
-                    {"wisdom", "cognitive", "perception", "感知能力", "0-100", "1"},
-                    {"wisdom", "cognitive", "focus", "专注力", "0-100", "2"},
-                    {"wisdom", "cognitive", "memory", "记忆力", "0-100", "3"},
-                    {"wisdom", "cognitive", "logic", "逻辑思维", "0-100", "4"},
-                    {"wisdom", "cognitive", "spatial", "空间思维", "0-100", "5"},
-                    {"wisdom", "cognitive", "processing_speed", "加工速度", "0-100", "6"},
-                    {"wisdom", "cognitive", "growth_mindset", "成长型思维", "0-100", "7"}
-            };
-            for (Object[] r : rows) {
-                jdbcTemplate.update(
-                        "INSERT IGNORE INTO indicator_definitions (domain, category, code, name, data_type, ref_range, sort_order, status) VALUES (?,?,?,?,?,?,?,1)",
-                        r[0], r[1], r[2], r[3], "number", r[4], Integer.parseInt((String) r[5])
-                );
-            }
-            log.info("迁移252: indicator_definitions 种子数据已加载 ({}条)", rows.length);
-        } catch (Exception e) {
-            log.warn("迁移252失败: {}", e.getMessage());
-        }
-
-        log.info("数据库迁移完成");
-
-        // ==================== 健康维度 Phase 1: health_dimension_score / health_data_source_record / health_norm_reference =============        migrateHealthDimensionsTable();
-        seedHealthNorms();
-        seedMindActionWealthNorms();
-        runLateMigrations();
-        migration102();
-        // 迁移226-247: 原seedFullRegionData内的DDL迁移,确保不因省市区数据已存在而跳过
-        runFullRegionDataMigrations();
-        // seedFullRegionData(); 已废弃,区域数据由独立迁移处理
-
-        // 迁移269: sleep_record 修改 sleep_time/wake_time 为 TIME(前端按 HH:mm 打卡,java.sql.Time 三段格式)
-        try {
-            jdbcTemplate.execute("ALTER TABLE sleep_record MODIFY COLUMN sleep_time TIME, MODIFY COLUMN wake_time TIME");
-            log.info("已修改 sleep_record 时间为 TIME 类型");
-        } catch (Exception e) {
-            log.warn("sleep_record 时间列修改失败(可能已为 TIME): {}", e.getMessage());
-        }
-
-        // ==================== 迁移270: 先天画像来源权重配置表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS innate_portrait_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "source_type VARCHAR(20) NOT NULL," +
-                    "source_name VARCHAR(50) NOT NULL," +
-                    "weight INT DEFAULT 25," +
-                    "enabled TINYINT(1) DEFAULT 1," +
-                    "ai_enabled TINYINT(1) DEFAULT 1," +
-                    "sort_order INT DEFAULT 0," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "UNIQUE KEY uk_source (source_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='先天画像来源权重配置'");
-            Integer cnt = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM innate_portrait_config", Integer.class);
-            if (cnt == null || cnt == 0) {
-                jdbcTemplate.batchUpdate(
-                    "INSERT INTO innate_portrait_config (source_type, source_name, weight, sort_order) VALUES (?, ?, ?, ?)",
-                    java.util.Arrays.asList(new Object[][]{
-                        {"zodiac", "星座", 2500, 1},
-                        {"bazi", "八字", 2500, 2},
-                        {"blood", "血型", 2500, 3},
-                        {"numsoul", "数字能量", 2500, 4},
-                    })
-                );
-                log.info("迁移270: innate_portrait_config 种子数据已加载 (4条)");
-            }
-            log.info("迁移270: innate_portrait_config 表创建完成");
-        } catch (Exception e) {
-            log.warn("迁移270失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移271: 先天画像报告缓存表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS innate_portrait_report (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "member_id BIGINT NOT NULL," +
-                    "member_type VARCHAR(10) NOT NULL," +
-                    "family_id BIGINT NOT NULL," +
-                    "portrait_json TEXT," +
-                    "ai_reading TEXT," +
-                    "generated_at DATETIME," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "UNIQUE KEY uk_member (member_id, member_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='先天画像报告缓存'");
-            log.info("迁移271: innate_portrait_report 表创建完成");
-        } catch (Exception e) {
-            log.warn("迁移271失败: {}", e.getMessage());
-        }
-
-        // ==================== 迁移272: 数字能量详细配置表 =============        
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS numsoul_detail_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "number_type VARCHAR(20) NOT NULL," +
-                    "number_value INT NOT NULL," +
-                    "title VARCHAR(50)," +
-                    "keywords VARCHAR(200)," +
-                    "mind_base INT DEFAULT 0," +
-                    "mind_advice TEXT," +
-                    "color_hex VARCHAR(10)," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "UNIQUE KEY uk_type_num (number_type, number_value)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数字能量详细配置'");
-            Integer cnt2 = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM numsoul_detail_config", Integer.class);
-            if (cnt2 == null || cnt2 == 0) {
-                jdbcTemplate.batchUpdate(
-                    "INSERT INTO numsoul_detail_config (number_type, number_value, title, keywords, mind_base, mind_advice, color_hex) VALUES (?, ?, ?, ?, ?, ?, ?)",
-                    java.util.Arrays.asList(new Object[][]{
-                        {"life_path", 1, "开创者", "独立、领导、创新", 68, "培养团队协作意识,避免独断专行", "#FF4444"},
-                        {"life_path", 2, "和平者", "温和、合作、敏感", 72, "增强自我主张,避免过度迎合", "#FF8C00"},
-                        {"life_path", 3, "表达者", "创意、社交、乐观", 78, "保持专注,避免浅尝辄止", "#FFD700"},
-                        {"life_path", 4, "建设者", "务实、稳定、有序", 70, "学会变通,避免过于固执", "#4CAF50"},
-                        {"life_path", 5, "自由者", "冒险、变化、好奇", 75, "培养持久力,避免缺乏恒心", "#2196F3"},
-                        {"life_path", 6, "关怀者", "责任、关爱、奉献", 80, "学会自我关爱,避免过度付出", "#9C27B0"},
-                        {"life_path", 7, "探索者", "智慧、分析、内省", 76, "与人分享见解,避免过度封闭", "#673AB7"},
-                        {"life_path", 8, "成就者", "雄心、管理、决策", 72, "关注内在成长,避免过度追求外在", "#3F51B5"},
-                        {"life_path", 9, "博爱者", "包容、智慧、善良", 82, "设定个人边界,避免过度牺牲", "#E91E63"},
-                        {"life_path", 11, "启明者", "直觉、灵感、理想", 85, "落地执行,避免空想", "#7C4DFF"},
-                        {"life_path", 22, "建造师", "远见、实践、宏图", 88, "分步落地大目标", "#536DFE"},
-                        {"life_path", 33, "引路人", "大爱、奉献、疗愈", 90, "先照顾好自己再照亮他人", "#FF4081"},
-                    })
-                );
-                log.info("迁移272: numsoul_detail_config 生命灵数种子已加载");
-            }
-            log.info("迁移272: numsoul_detail_config 表创建完成");
-        } catch (Exception e) {
-            log.warn("迁移272失败: {}", e.getMessage());
-        }
-
-        // 迁移273: dan_report_uploads.file_id 加宽(OSS 完整 URL 超过原 VARCHAR(100) 导致截断报错)
-        try {
-            jdbcTemplate.execute("ALTER TABLE dan_report_uploads MODIFY COLUMN file_id VARCHAR(500) COMMENT '媒资文件ID或相对路径'");
-            log.info("迁移273: 已加宽 dan_report_uploads.file_id 为 VARCHAR(500)");
-        } catch (Exception e) {
-            log.warn("迁移273失败: {}", e.getMessage());
-        }
-
-        // 迁移274: dan_assessment_results.report_file_id 加宽(确认入库写入 OSS URL 超长截断)
-        try {
-            jdbcTemplate.execute("ALTER TABLE dan_assessment_results MODIFY COLUMN report_file_id VARCHAR(500) COMMENT '上传文件媒资ID或相对路径'");
-            log.info("迁移274: 已加宽 dan_assessment_results.report_file_id 为 VARCHAR(500)");
-        } catch (Exception e) {
-            log.warn("迁移274失败: {}", e.getMessage());
-        }
-
-        // 迁移275: dan_assessment_results.dan_level 兼容旧库(NOT NULL 无默认导致家长上传确认失败)
-        ensureColumn("dan_assessment_results", "dan_level",
-                "VARCHAR(10) NULL DEFAULT NULL COMMENT 'DAN等级A/B/C/D'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE dan_assessment_results MODIFY COLUMN dan_level VARCHAR(10) NULL DEFAULT NULL COMMENT 'DAN等级A/B/C/D'");
-            log.info("迁移275: 已将 dan_assessment_results.dan_level 改为可空并带默认");
-        } catch (Exception e) {
-            log.warn("迁移275失败: {}", e.getMessage());
-        }
-
-        runSystemMigrations();
-        registerCollectExpectedIndicators();
-
-        // 减脂专题表创建(远程 fatloss 功能)
-        createFatWeightRecordTable();
-        createFatDietRecordTable();
-        createFatExerciseRecordTable();
-        createFatGoalTable();
-        addProductVendorVisibleColumn();
-
-        // 迁移367: products 表添加健康约束字段(基础疾病禁忌/过敏原/药物相互作用标记)
-        addProductHealthConstraintColumns();
-
-        // 迁移368: 创建 drug_interactions 表(药物-食物禁忌对照表)
-        createDrugInteractionsTable();
-
-        // 迁移369: 创建 disease_intake_limits 表(疾病-饮食摄入阈值)
-        createDiseaseIntakeLimitsTable();
-
-        // 迁移370: 初始化 drug_interactions 种子数据
-        seedDrugInteractionsData();
-
-        // 迁移371: 初始化 disease_intake_limits 种子数据
-        seedDiseaseIntakeLimitsData();
-
-        // 指标统一层迁移(356~362)
-        migrateIndicatorDefinitionsColumns();
-        migrateIndicatorValuesColumns();
-        addIndicatorValuesKeys();
-        createIndicatorMappingRulesTable();
-        createIndicatorCorrelationsTable();
-        ensureIndicatorCollectionDate();
-        seedDimensionDefinitions();
-
-        // 商品组合推荐与采购任务迁移(363)
-        createProcurementTaskTable();
-
-        // 迁移364: health_report_drafts 添加解析进度/重试字段(known-type 解析失败退避重试,不再静默回退 opencode)
-        addDraftParseProgressColumns();
-
-        // 迁移365: diet_preferences 添加无特殊偏好标记(问卷第3步「无特殊偏好」一键跳过落库)
-        ensureColumn("diet_preferences", "no_preference", "TINYINT(1) DEFAULT 0 COMMENT '无特殊偏好标记(1=用户明确选择无特殊偏好)'");
-
-        // 迁移366: 新增 LITE 轻享会员等级(9.9元/月,解锁健康自检问卷与个性化方案)
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_levels (level_code, level_name, level_desc, price_monthly, price_quarterly, price_yearly, max_children, max_tasks_per_day, ai_review_enabled, priority_support, teacher_consultation) VALUES " +
-                    "('LITE', '轻享会员', '9.9元/月,解锁健康自检问卷与个性化方案', 990, 2970, 11880, 2, 10, 1, 0, 0)");
-            log.info("迁移366: 已插入 LITE 轻享会员等级");
-        } catch (Exception e) {
-            log.warn("迁移366: 插入 LITE 会员等级失败或已存在: {}", e.getMessage());
-        }
-    }
-
-    private void migrateHealthDimensionsTable() {
-        try {
-            if (tableExists("health_dimension_score")) {
-                jdbcTemplate.execute("RENAME TABLE `health_dimension_score` TO `health_dimension_score_old`");
-            }
-        } catch (Exception e) {
-            log.warn("health_dimension_score rename skipped: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `health_dimension_scores` (\n" +
-                    "  `id` bigint NOT NULL AUTO_INCREMENT,\n" +
-                    "  `member_id` bigint NOT NULL COMMENT '家庭成员ID',\n" +
-                    "  `dimension` varchar(20) NOT NULL COMMENT '维度: growth/sleep/vision/immunity/nutrition/gut/exercise',\n" +
-                    "  `score` int NOT NULL COMMENT '0-100分',\n" +
-                    "  `percentile` int DEFAULT NULL COMMENT '人群百分位 0-100',\n" +
-                    "  `data_source` varchar(20) NOT NULL COMMENT '数据源: REPORT/PHOTO/VOICE/MANUAL',\n" +
-                    "  `tier` tinyint NOT NULL DEFAULT 3 COMMENT '数据层级: 1自动/2语音/3手动',\n" +
-                    "  `raw_data` json DEFAULT NULL COMMENT '原始数据快照',\n" +
-                    "  `assess_date` date NOT NULL COMMENT '评估日期',\n" +
-                    "  `expire_date` date DEFAULT NULL COMMENT '数据过期日',\n" +
-                    "  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,\n" +
-                    "  `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\n" +
-                    "  PRIMARY KEY (`id`),\n" +
-                    "  UNIQUE KEY `uk_member_dim_date` (`member_id`, `dimension`, `assess_date`)\n" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康维度评分表'");
-        } catch (Exception e) {
-            log.warn("health_dimension_scores 表创建失败: {}", e.getMessage());
-        }
-
-        try {
-            if (tableExists("health_data_source_record")) {
-                jdbcTemplate.execute("RENAME TABLE `health_data_source_record` TO `health_data_source_record_old`");
-            }
-        } catch (Exception e) {
-            log.warn("health_data_source_record rename skipped: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `health_data_sources` (\n" +
-                    "  `id` bigint NOT NULL AUTO_INCREMENT,\n" +
-                    "  `member_id` bigint NOT NULL,\n" +
-                    "  `source_type` varchar(20) NOT NULL COMMENT 'PDF/PHOTO/VOICE/MANUAL/WEIXIN_STEP',\n" +
-                    "  `dimension_codes` json NOT NULL COMMENT '影响的维度列表',\n" +
-                    "  `parsed_result` json DEFAULT NULL COMMENT '解析结果全量',\n" +
-                    "  `file_url` varchar(500) DEFAULT NULL COMMENT '原始文件URL',\n" +
-                    "  `confidence` decimal(3,2) DEFAULT NULL COMMENT 'AI解析置信度',\n" +
-                    "  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,\n" +
-                    "  PRIMARY KEY (`id`),\n" +
-                    "  KEY `idx_member_source` (`member_id`, `source_type`)\n" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康数据源记录表'");
-        } catch (Exception e) {
-            log.warn("health_data_sources 表创建失败: {}", e.getMessage());
-        }
-
-        try {
-            if (tableExists("health_norm_reference")) {
-                jdbcTemplate.execute("RENAME TABLE `health_norm_reference` TO `health_norm_reference_old`");
-            }
-        } catch (Exception e) {
-            log.warn("health_norm_reference rename skipped: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `health_norm_reference` (\n" +
-                    "  `id` bigint NOT NULL AUTO_INCREMENT,\n" +
-                    "  `dimension` varchar(20) NOT NULL COMMENT '维度',\n" +
-                    "  `gender` varchar(10) NOT NULL COMMENT 'male/female/all',\n" +
-                    "  `age_min` int NOT NULL COMMENT '年龄下限(月)',\n" +
-                    "  `age_max` int NOT NULL COMMENT '年龄上限(月)',\n" +
-                    "  `percentile_5` int DEFAULT NULL,\n" +
-                    "  `percentile_15` int DEFAULT NULL,\n" +
-                    "  `percentile_25` int DEFAULT NULL,\n" +
-                    "  `percentile_50` int DEFAULT NULL COMMENT '中位值',\n" +
-                    "  `percentile_75` int DEFAULT NULL,\n" +
-                    "  `percentile_85` int DEFAULT NULL,\n" +
-                    "  `percentile_95` int DEFAULT NULL,\n" +
-                    "  `source` varchar(50) DEFAULT NULL COMMENT '常模来源',\n" +
-                    "  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,\n" +
-                    "  PRIMARY KEY (`id`),\n" +
-                    "  UNIQUE KEY `uk_dim_gender_age` (`dimension`, `gender`, `age_min`, `age_max`)\n" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康常模对照表'");
-        } catch (Exception e) {
-            log.warn("health_norm_reference 表重建失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO health_dimension_scores (member_id, dimension, score, data_source, tier, assess_date, created_at)\n" +
-                    " SELECT member_id,\n" +
-                    "  CASE dimension\n" +
-                    "    WHEN 'body' THEN 'growth'\n" +
-                    "    WHEN 'fitness' THEN 'exercise'\n" +
-                    "    WHEN 'cardio' THEN 'exercise'\n" +
-                    "    WHEN 'blood' THEN 'immunity'\n" +
-                    "    WHEN 'sleep' THEN 'sleep'\n" +
-                    "    WHEN 'psyche' THEN 'growth'\n" +
-                    "    WHEN 'diet' THEN 'nutrition'\n" +
-                    "    ELSE dimension\n" +
-                    "  END,\n" +
-                    "  score,\n" +
-                    "  UPPER(data_source),\n" +
-                    "  3,\n" +
-                    "  record_date,\n" +
-                    "  NOW()\n" +
-                    " FROM health_dimension_score_old WHERE is_latest = 1");
-        } catch (Exception e) {
-            log.warn("旧维度评分数据迁移跳过: {}", e.getMessage());
-        }
-    }
-
-    private void seedHealthNorms() {
-        try {
-            int count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM health_norm_reference", Integer.class);
-            if (count == 0) {
-                jdbcTemplate.execute("INSERT INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES\n" +
-                        "('growth', 'male', 72, 84, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('growth', 'female', 72, 84, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('growth', 'male', 84, 96, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('growth', 'female', 84, 96, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('growth', 'male', 96, 120, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('growth', 'female', 96, 120, 25, 35, 45, 55, 70, 80, 90, 'BMI-for-age→百分制'),\n" +
-                        "('sleep', 'all', 0, 12, 40, 50, 60, 70, 80, 88, 95, 'NSF婴幼儿睡眠→百分制'),\n" +
-                        "('sleep', 'all', 12, 36, 40, 50, 60, 70, 80, 88, 95, 'NSF幼儿睡眠→百分制'),\n" +
-                        "('sleep', 'all', 36, 72, 40, 50, 60, 70, 80, 88, 95, 'NSF学龄前睡眠→百分制'),\n" +
-                        "('sleep', 'all', 72, 156, 40, 50, 60, 70, 80, 88, 95, 'NSF学龄儿童睡眠→百分制'),\n" +
-                        "('vision', 'male', 72, 144, 45, 55, 65, 75, 85, 90, 95, '视力发育标准→百分制'),\n" +
-                        "('vision', 'female', 72, 144, 45, 55, 65, 75, 85, 90, 95, '视力发育标准→百分制'),\n" +
-                        "('immunity', 'all', 0, 72, 15, 30, 45, 65, 80, 90, 95, '年患病次数→百分制'),\n" +
-                        "('immunity', 'all', 72, 192, 15, 35, 50, 70, 85, 92, 98, '年患病次数→百分制'),\n" +
-                        "('nutrition', 'all', 36, 192, 20, 30, 40, 50, 60, 70, 80, '膳食多样性→百分制'),\n" +
-                        "('gut', 'all', 0, 192, 40, 50, 60, 70, 80, 85, 95, '菌群人群分布(平台自建)'),\n" +
-                        "('exercise', 'male', 72, 144, 30, 40, 50, 60, 70, 80, 90, '国家学生体质健康标准'),\n" +
-                        "('exercise', 'female', 72, 144, 25, 35, 45, 55, 65, 75, 85, '国家学生体质健康标准')");
-                log.info("health_norm_reference 常模种子数据已加载 (18条, 统一0-100百分制)");
-            } else {
-                log.info("health_norm_reference 常模数据已存在 ({}条), 跳过", count);
-            }
-        } catch (Exception e) {
-            log.warn("health_norm_reference 常模种子数据初始化失败: {}", e.getMessage());
-        }
-
-        // 迁移: articles表添加审核和作者类型字段
-        try {
-            Integer exists = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'articles' AND COLUMN_NAME = 'audit_status'",
-                    Integer.class);
-            if (exists == null || exists == 0) {
-                jdbcTemplate.execute("ALTER TABLE articles " +
-                        "ADD COLUMN author_type VARCHAR(20) DEFAULT 'admin' COMMENT '作者类型:admin/parent/child' AFTER created_by, " +
-                        "ADD COLUMN audit_status VARCHAR(20) DEFAULT 'approved' COMMENT '审核状态:approved/pending/rejected' AFTER status, " +
-                        "ADD COLUMN audit_reason TEXT COMMENT '驳回原因' AFTER audit_status, " +
-                        "ADD COLUMN auditor_id BIGINT DEFAULT 0 COMMENT '审核人 ID' AFTER audit_reason, " +
-                        "ADD COLUMN audited_at DATETIME COMMENT '审核时间' AFTER auditor_id");
-                log.info("已添加审核和作者类型字段到articles表");
-            } else {
-                log.info("articles表审核字段已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("检查/添加articles表审核字段失败: {}", e.getMessage());
-        }
-
-        // 迁移20240709-01: content字段扩为TEXT - 用户输入内容可能超VARCHAR上限
-        // activities.description
-        modifyColumnToText("activities", "description", "活动描述");
-        // tasks.description
-        modifyColumnToText("tasks", "description", "任务描述");
-        // wishes.description, reject_reason, cancel_reason
-        modifyColumnToText("wishes", "description", "心愿描述");
-        modifyColumnToText("wishes", "reject_reason", "拒绝原因");
-        modifyColumnToText("wishes", "cancel_reason", "取消原因");
-        // reward_wishlists.description
-        modifyColumnToText("reward_wishlists", "description", "心愿描述");
-        // products.description, reject_reason
-        modifyColumnToText("products", "description", "商品描述");
-        modifyColumnToText("products", "reject_reason", "审核拒绝原因");
-        // product_orders.remark
-        modifyColumnToText("product_orders", "remark", "备注");
-        // articles.summary
-        modifyColumnToText("articles", "summary", "摘要");
-        // activities.audit_reason
-        modifyColumnToText("activities", "audit_reason", "驳回原因");
-        // guide_applications.reject_reason
-        modifyColumnToText("guide_applications", "reject_reason", "拒绝原因");
-        // guide_application_records.remark
-        modifyColumnToText("guide_application_records", "remark", "备注/原因");
-        // user_operation_log.description
-        modifyColumnToText("user_operation_log", "description", "操作描述");
-        // follow_up.description, teacher_review
-        modifyColumnToText("follow_up", "description", "描述");
-        modifyColumnToText("follow_up", "teacher_review", "规划师点评");
-        // energy_log.description
-        modifyColumnToText("energy_log", "description", "描述");
-        // sys_config.description
-        modifyColumnToText("sys_config", "description", "配置说明");
-        // points_log.description
-        modifyColumnToText("points_log", "description", "描述");
-        // insurance_policies.remark
-        modifyColumnToText("insurance_policies", "remark", "备注");
-        // health_reports.remark
-        modifyColumnToText("health_reports", "remark", "备注");
-        // guide_service_logs.notes
-        modifyColumnToText("guide_service_logs", "notes", "服务记录");
-        // guide_packages.description
-        modifyColumnToText("guide_packages", "description", "套餐说明");
-        // guide_package_templates.description
-        modifyColumnToText("guide_package_templates", "description", "说明");
-        // service_types.description
-        modifyColumnToText("service_types", "description", "描述");
-        // commission_records.remark
-        modifyColumnToText("commission_records", "remark", "备注");
-        // zodiac_pairing.description, advice
-        modifyColumnToText("zodiac_pairing", "description", "配对解读");
-        modifyColumnToText("zodiac_pairing", "advice", "相处建议");
-        // blood_type_pairing.description, advice
-        modifyColumnToText("blood_type_pairing", "description", "配对描述");
-        modifyColumnToText("blood_type_pairing", "advice", "相处建议");
-        // life_number_relationship.description, advice
-        modifyColumnToText("life_number_relationship", "description", "关系解读");
-        modifyColumnToText("life_number_relationship", "advice", "相处建议");
-        // daily_health_checkin.remark
-        modifyColumnToText("daily_health_checkin", "remark", "备注");
-        // health_sleep_record.remark
-        modifyColumnToText("health_sleep_record", "remark", "备注");
-        // health_exercise_record.remark
-        modifyColumnToText("health_exercise_record", "remark", "备注");
-        // finance_checkins.note
-        modifyColumnToText("finance_checkins", "note", "备注");
-        // guide_packages.description (old duplicate)
-        // assessment_appointments.remark
-        modifyColumnToText("assessment_appointments", "remark", "备注");
-        // withdrawal_requests.remark
-        modifyColumnToText("withdrawal_requests", "remark", "备注");
-        // supply_settlements.remark
-        modifyColumnToText("supply_settlements", "remark", "备注");
-        // content_sections.description
-        ensureColumn("content_sections", "description", "TEXT COMMENT '描述说明'");
-        // education_systems.description
-        modifyColumnToText("education_systems", "description", "描述");
-        // dimension_config.description
-        modifyColumnToText("dimension_config", "description", "描述");
-        // energy_rules.description
-        modifyColumnToText("energy_rules", "description", "规则描述");
-        // team_goals.description
-        modifyColumnToText("team_goals", "description", "团队描述");
-        // product_dimension_config.remark
-        modifyColumnToText("product_dimension_config", "remark", "备注");
-        // indicator_values.remark
-        modifyColumnToText("indicator_values", "remark", "备注");
-        // tongue_records.overall_assessment
-        modifyColumnToText("tongue_records", "overall_assessment", "总体评估");
-        // system_config.description, config_value
-        modifyColumnToText("system_config", "description", "说明");
-        modifyColumnToText("system_config", "config_value", "配置值");
-        // supply_system.description
-        modifyColumnToText("supply_system", "description", "描述");
-        // supply_settlement.remark
-        modifyColumnToText("supply_settlement", "remark", "备注");
-        // growth_task.description
-        modifyColumnToText("growth_task", "description", "描述");
-        // distribution_systems.description
-        modifyColumnToText("distribution_systems", "description", "团队描述");
-        // mini_games.description
-        modifyColumnToText("mini_games", "description", "游戏描述");
-        // blood_type_config.description
-        modifyColumnToText("blood_type_config", "description", "性格描述");
-
-        // 迁移20240709-02: 北京菌群报告采集增强(P0 疾病关联菌 / P1 菌群状态)
-        // health_disease_risk.related_bacteria: 疾病关联菌(异常菌)明细 JSON
-        ensureColumn("health_disease_risk", "related_bacteria", "TEXT NULL COMMENT '关联菌明细JSON:[{bacteria,correlation,value,status}]'");
-        // health_reports.gut_status_level: 肠道菌群状态(0度~4度)
-        ensureColumn("health_reports", "gut_status_level", "VARCHAR(20) NULL COMMENT '肠道菌群状态(0度~4度)'");
-
-        // 迁移248: 任务系统升级(行为调度中心)——tasks 新增字段
-        ensureColumn("tasks", "prerequisite_task_id", "BIGINT NULL COMMENT '前置任务ID:完成后才解锁本任务'");
-        ensureColumn("tasks", "action_type", "VARCHAR(32) NULL COMMENT '联动动作: minigame/focus/survey/article/activity/cart/order'");
-        ensureColumn("tasks", "action_config", "JSON NULL COMMENT '联动参数: {\"gameCode\":\"schulte\",\"productId\":123,\"minSeconds\":30,\"completeMilestone\":\"paid\"/\"received\",\"surveyId\":99}'");
-        ensureColumn("tasks", "require_input", "TINYINT DEFAULT 0 COMMENT '1=需填写内容才能完成'");
-        ensureColumn("tasks", "start_required", "TINYINT DEFAULT 0 COMMENT '1=需先开始再完成(两阶段)'");
-        ensureColumn("tasks", "start_count", "INT DEFAULT 0 COMMENT '已开始次数(累计)'");
-        ensureColumn("tasks", "min_duration_seconds", "INT DEFAULT 0 COMMENT '最短持续秒数(专注/游戏类,未达标不计完成)'");
-
-        // 迁移248: 任务执行进度表(两阶段/里程碑/填写内容记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS task_executions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "task_id BIGINT NOT NULL COMMENT '任务实例ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '执行成员ID(family_members.id)', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'started' COMMENT 'started/finished/failed', " +
-                    "started_at DATETIME NOT NULL COMMENT '开始时间', " +
-                    "finished_at DATETIME COMMENT '完成时间', " +
-                    "milestone VARCHAR(32) COMMENT '购物任务里程碑: cart_added/paid/received(当前进度)', " +
-                    "content TEXT COMMENT '填写内容(require_input 任务)', " +
-                    "content_type VARCHAR(20) COMMENT 'content 类型: text/image/audio/video', " +
-                    "extra JSON COMMENT '扩展数据: {gameScore, focusMinutes, orderId, articleId, surveyId}', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_task_member (task_id, member_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务执行进度表'");
-            log.info("已创建task_executions表");
-        } catch (Exception e) {
-            log.warn("创建task_executions表失败: {}", e.getMessage());
-        }
-
-        // 迁移248: focus_sessions 添加 task_id 字段(专注任务挂钩)
-        ensureColumn("focus_sessions", "task_id", "BIGINT NULL COMMENT '关联的任务ID(专注任务挂钩)'");
-    }
-
-
-    private void seedMindActionWealthNorms() {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM health_norm_reference WHERE dimension LIKE 'bigFive%' OR dimension LIKE 'emotion%' OR dimension LIKE 'drive%' OR dimension LIKE 'selfConcept%' OR dimension LIKE 'action%' OR dimension LIKE 'wealth%'",
-                Integer.class);
-            if (count != null && count > 0) {
-                log.info("mind/action/wealth 常模数据已存在 ({}条), 跳过", count);
-                return;
-            }
-            java.util.List<String> sqls = new java.util.ArrayList<>();
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('bigFiveOpenness','all',0,84,20,27,35,45,55,63,70,'心理常模'),\n" +
-    "('bigFiveOpenness','all',84,144,27,34,42,52,62,70,77,'心理常模'),\n" +
-    "('bigFiveOpenness','all',144,216,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('bigFiveOpenness','all',216,1200,25,32,40,50,60,68,75,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('bigFiveConscientiousness','all',0,84,15,22,30,40,50,58,65,'心理常模'),\n" +
-    "('bigFiveConscientiousness','all',84,144,23,30,38,48,58,66,73,'心理常模'),\n" +
-    "('bigFiveConscientiousness','all',144,216,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('bigFiveConscientiousness','all',216,1200,33,40,48,58,68,76,83,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('bigFiveExtraversion','all',0,84,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('bigFiveExtraversion','all',84,144,27,34,42,52,62,70,77,'心理常模'),\n" +
-    "('bigFiveExtraversion','all',144,216,25,32,40,50,60,68,75,'心理常模'),\n" +
-    "('bigFiveExtraversion','all',216,1200,25,32,40,50,60,68,75,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('bigFiveAgreeableness','all',0,84,33,40,48,58,68,76,83,'心理常模'),\n" +
-    "('bigFiveAgreeableness','all',84,144,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('bigFiveAgreeableness','all',144,216,28,35,43,53,63,71,78,'心理常模'),\n" +
-    "('bigFiveAgreeableness','all',216,1200,30,37,45,55,65,73,80,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('bigFiveNeuroticism','all',0,84,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('bigFiveNeuroticism','all',84,144,23,30,38,48,58,66,73,'心理常模'),\n" +
-    "('bigFiveNeuroticism','all',144,216,20,27,35,45,55,63,70,'心理常模'),\n" +
-    "('bigFiveNeuroticism','all',216,1200,30,37,45,55,65,73,80,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('emotionStability','all',0,84,17,24,32,42,52,60,67,'心理常模'),\n" +
-    "('emotionStability','all',84,144,27,34,42,52,62,70,77,'心理常模'),\n" +
-    "('emotionStability','all',144,216,33,40,48,58,68,76,83,'心理常模'),\n" +
-    "('emotionStability','all',216,1200,37,44,52,62,72,80,87,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('driveAutonomy','all',0,84,10,17,25,35,45,53,60,'心理常模'),\n" +
-    "('driveAutonomy','all',84,144,25,32,40,50,60,68,75,'心理常模'),\n" +
-    "('driveAutonomy','all',144,216,37,44,52,62,72,80,87,'心理常模'),\n" +
-    "('driveAutonomy','all',216,1200,43,50,58,68,78,86,93,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('driveCompetence','all',0,84,15,22,30,40,50,58,65,'心理常模'),\n" +
-    "('driveCompetence','all',84,144,27,34,42,52,62,70,77,'心理常模'),\n" +
-    "('driveCompetence','all',144,216,35,42,50,60,70,78,85,'心理常模'),\n" +
-    "('driveCompetence','all',216,1200,37,44,52,62,72,80,87,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('driveRelatedness','all',0,84,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('driveRelatedness','all',84,144,27,34,42,52,62,70,77,'心理常模'),\n" +
-    "('driveRelatedness','all',144,216,25,32,40,50,60,68,75,'心理常模'),\n" +
-    "('driveRelatedness','all',216,1200,30,37,45,55,65,73,80,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('selfConceptOverall','all',0,84,20,27,35,45,55,63,70,'心理常模'),\n" +
-    "('selfConceptOverall','all',84,144,30,37,45,55,65,73,80,'心理常模'),\n" +
-    "('selfConceptOverall','all',144,216,33,40,48,58,68,76,83,'心理常模'),\n" +
-    "('selfConceptOverall','all',216,1200,33,40,48,58,68,76,83,'心理常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionChildParentChild','all',0,84,35,42,50,60,70,78,85,'关系质量常模'),\n" +
-    "('actionChildParentChild','all',84,144,33,40,48,58,68,76,83,'关系质量常模'),\n" +
-    "('actionChildParentChild','all',144,216,30,37,45,55,65,73,80,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionSibling','all',0,84,20,27,35,45,55,63,70,'关系质量常模'),\n" +
-    "('actionSibling','all',84,144,25,32,40,50,60,68,75,'关系质量常模'),\n" +
-    "('actionSibling','all',144,216,30,37,45,55,65,73,80,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionRelative','all',0,84,25,32,40,50,60,68,75,'关系质量常模'),\n" +
-    "('actionRelative','all',84,144,30,37,45,55,65,73,80,'关系质量常模'),\n" +
-    "('actionRelative','all',144,216,33,40,48,58,68,76,83,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionTeacherStudent','all',0,84,25,32,40,50,60,68,75,'关系质量常模'),\n" +
-    "('actionTeacherStudent','all',84,144,35,42,50,60,70,78,85,'关系质量常模'),\n" +
-    "('actionTeacherStudent','all',144,216,37,44,52,62,72,80,87,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionChildSociality','all',0,84,23,30,38,48,58,66,73,'关系质量常模'),\n" +
-    "('actionChildSociality','all',84,144,30,37,45,55,65,73,80,'关系质量常模'),\n" +
-    "('actionChildSociality','all',144,216,35,42,50,60,70,78,85,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionChildInterpersonal','all',0,84,20,27,35,45,55,63,70,'关系质量常模'),\n" +
-    "('actionChildInterpersonal','all',84,144,27,34,42,52,62,70,77,'关系质量常模'),\n" +
-    "('actionChildInterpersonal','all',144,216,33,40,48,58,68,76,83,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionParentChild','all',216,1200,33,40,48,58,68,76,83,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionMarital','all',216,1200,30,37,45,55,65,73,80,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionParental','all',216,1200,27,34,42,52,62,70,77,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionLeadership','all',216,1200,30,37,45,55,65,73,80,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionSociality','all',216,1200,35,42,50,60,70,78,85,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('actionInterpersonal','all',216,1200,33,40,48,58,68,76,83,'关系质量常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('wealthSkill','all',0,84,10,17,25,35,45,53,60,'财富素养常模'),\n" +
-    "('wealthSkill','all',84,144,20,27,35,45,55,63,70,'财富素养常模'),\n" +
-    "('wealthSkill','all',144,216,30,37,45,55,65,73,80,'财富素养常模'),\n" +
-    "('wealthSkill','all',216,1200,35,42,50,60,70,78,85,'财富素养常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('wealthAltruism','all',0,84,5,12,20,30,40,48,55,'财富素养常模'),\n" +
-    "('wealthAltruism','all',84,144,15,22,30,40,50,58,65,'财富素养常模'),\n" +
-    "('wealthAltruism','all',144,216,25,32,40,50,60,68,75,'财富素养常模'),\n" +
-    "('wealthAltruism','all',216,1200,30,37,45,55,65,73,80,'财富素养常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('wealthIncome','all',0,84,0,7,15,25,35,43,50,'财富素养常模'),\n" +
-    "('wealthIncome','all',84,144,10,17,25,35,45,53,60,'财富素养常模'),\n" +
-    "('wealthIncome','all',144,216,20,27,35,45,55,63,70,'财富素养常模'),\n" +
-    "('wealthIncome','all',216,1200,30,37,45,55,65,73,80,'财富素养常模')");
-
-sqls.add("INSERT IGNORE INTO health_norm_reference (dimension, gender, age_min, age_max, percentile_5, percentile_15, percentile_25, percentile_50, percentile_75, percentile_85, percentile_95, source) VALUES \n" +
-    "('wealthFx','all',0,84,0,2,10,20,30,38,45,'财富素养常模'),\n" +
-    "('wealthFx','all',84,144,5,12,20,30,40,48,55,'财富素养常模'),\n" +
-    "('wealthFx','all',144,216,15,22,30,40,50,58,65,'财富素养常模'),\n" +
-    "('wealthFx','all',216,1200,25,32,40,50,60,68,75,'财富素养常模')");
-            for (String sql : sqls) {
-                jdbcTemplate.execute(sql);
-            }
-            log.info("mind/action/wealth 常模种子数据已加载 ({}条)", sqls.size());
-        } catch (Exception e) {
-            log.warn("mind/action/wealth 常模种子数据初始化失败: {}", e.getMessage());
-        }
-    }
-
-    private void modifyColumnToText(String table, String column, String comment) {
-        if (!tableExists(table)) {
-            return;
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE " + table + " MODIFY COLUMN " + column + " TEXT COMMENT '" + comment + "'");
-            log.info("已修改{}.{}为TEXT类型", table, column);
-        } catch (Exception e) {
-            log.warn("修改{}.{}为TEXT失败: {}", table, column, e.getMessage());
-        }
-    }
-
-    private void initializeDefaultData() {
-        // 初始化预设奖励模板
-        try {
-            // 检查是否已有预设奖励
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM rewards WHERE is_template = 1", Integer.class);
-
-            if (count == null || count == 0) {
-// 插入预设奖励模板(child_id为NULL表示模板)
-                jdbcTemplate.execute("INSERT INTO rewards (family_id, child_id, title, points_required, category, is_template) VALUES " +
-                        "(0, NULL, \'看动画片30分钟\', 30, \'精神类\', 1), " +
-                        "(0, NULL, \'玩平板游戏30分钟\', 40, \'特权类\', 1), " +
-                        "(0, NULL, \'去游乐场\', 100, \'物质类\', 1), " +
-                        "(0, NULL, \'买玩具\', 150, \'物质类\', 1), " +
-                        "(0, NULL, \'吃冰淇淋\', 20, \'物质类\', 1), " +
-                        "(0, NULL, \'选择晚餐\', 25, \'特权类\', 1)");
-                log.info("预设奖励模板已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化预设奖励失败: {}", e.getMessage());
-        }
-
-        // 初始化奖励分类
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM reward_categories WHERE family_id = 0", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO reward_categories (family_id, name, icon, sort_order) VALUES " +
-                        "(0, '物质类', 'gift', 1), " +
-                        "(0, '精神类', 'star', 2), " +
-                        "(0, '特权类', 'crown', 3)");
-                log.info("奖励分类已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化奖励分类失败: {}", e.getMessage());
-        }
-
-        // 初始化打卡里程碑
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM streak_milestones", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO streak_milestones (days, reward_points) VALUES " +
-                        "(3, 5), (7, 10), (30, 30), (100, 100)");
-                log.info("打卡里程碑已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化打卡里程碑失败: {}", e.getMessage());
-        }
-
-        // 初始化勋章定义
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM badge_definitions", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO badge_definitions (badge_type, name, description, icon, condition_type, condition_value, reward_points) VALUES " +
-                        "('first_task', '初次完成任务', '首次完成任意任务', 'star', 'task_count', 1, 0), " +
-                        "('streak_3', '连续3天', '连续3天按时完成任务', 'fire', 'streak_days', 3, 5), " +
-                        "('streak_7', '连续7天', '连续7天按时完成任务', 'fire', 'streak_days', 7, 10), " +
-                        "('points_50', '积分达人', '一周获得50积分', 'trophy', 'weekly_points', 50, 0), " +
-                        "('task_100', '任务达人', '完成100个任务', 'medal', 'task_count', 100, 20)");
-                log.info("勋章定义已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化勋章定义失败: {}", e.getMessage());
-        }
-
-        // 初始化小游戏数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM mini_games", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO mini_games (game_code, game_name, description, icon, default_duration, default_points, game_url, sort_order, status) VALUES " +
-                        "('schulte', '舒尔特方格', '训练专注力和眼动能力,找到1-25按顺序点击', '🎯', 5, 5, '/pages/games/schulte', 1, 1), " +
-                        "('1a2b', '猜数字', '猜对数字和位置获得积分,锻炼逻辑思维', '🔢', 10, 5, '/pages/games/1a2b', 2, 1), " +
-                        "('sudoku', '数独', '填充数字使每行每列每个宫格都包含1-9', '🔳', 15, 8, '/pages/games/sudoku', 3, 1)");
-                log.info("小游戏数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化小游戏数据失败: {}", e.getMessage());
-        }
-
-// 初始化默认管理员
-        try {
-            // 先检查并添加role列(如果不存在)
-            try {
-                jdbcTemplate.execute("ALTER TABLE admins ADD COLUMN role VARCHAR(20) DEFAULT \'admin\' AFTER email");
-                log.info("已添加role列到admins表");
-            } catch (Exception e) {
-                // 列已存在,忽略错误
-            }
-
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admins", Integer.class);
-
-            if (count == null || count == 0) {
-                // 默认管理员: 手机号 13800138000, 密码 admin123
-                String encryptedPassword = org.springframework.util.DigestUtils.md5DigestAsHex("xzyj_admin_salt_admin123".getBytes());
-                jdbcTemplate.execute("INSERT INTO admins (username, password, real_name, phone, email, role, status) VALUES " +
-                        "(\'admin\', \'" + encryptedPassword + "\', \'系统管理员\', \'13800138000\', \'admin@xzyj.com\', \'admin\', 1)");
-                log.info("默认管理员已初始化: 手机号 13800138000, 密码 admin123");
-            }
-        } catch (Exception e) {
-            log.warn("初始化默认管理员失败: {}", e.getMessage());
-        }
-
-        // 初始化成长规划师WEB管理账号
-        try {
-            Integer teacherCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admins WHERE username = 'teacher'", Integer.class);
-            if (teacherCount == null || teacherCount == 0) {
-                String teacherPassword = org.springframework.util.DigestUtils.md5DigestAsHex("xzyj_admin_salt_teacher123".getBytes());
-                jdbcTemplate.execute("INSERT INTO admins (username, password, real_name, phone, role, status) VALUES " +
-                        "('teacher', '" + teacherPassword + "', '成长规划师', '13800138003', 'teacher', 1)");
-                log.info("成长规划师管理账号已初始化: 用户名 teacher, 密码 teacher123");
-            }
-        } catch (Exception e) {
-            log.warn("初始化成长规划师管理账号失败: {}", e.getMessage());
-        }
-
-        // 初始化任务模板示例数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admin_task_templates", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO admin_task_templates (title, description, points, category, need_review, recommended_age, difficulty, is_active) VALUES " +
-                        "('完成作业', '按时完成学校布置的家庭作业', 10, '学习', 1, 6, 'medium', 1), " +
-                        "('阅读30分钟', '自主阅读课外书籍30分钟', 8, '阅读', 0, 5, 'easy', 1), " +
-                        "('整理房间', '收拾整理自己的房间和书桌', 6, '家务', 0, 6, 'easy', 1), " +
-                        "('洗碗', '饭后帮忙清洗餐具', 5, '家务', 1, 8, 'medium', 1), " +
-                        "('户外运动1小时', '进行跑步、球类等户外运动', 12, '运动', 0, 7, 'hard', 1), " +
-                        "('练习书法', '练习毛笔或硬笔书法20分钟', 7, '学习', 0, 7, 'medium', 1), " +
-                        "('早睡早起', '晚上9点前睡觉,早上7点前起床', 5, '生活习惯', 0, 5, 'easy', 1), " +
-                        "('背诵古诗', '背诵一首古诗词', 8, '学习', 1, 6, 'medium', 1)");
-                log.info("任务模板示例数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化任务模板失败: {}", e.getMessage());
-        }
-
-        // 初始化街道数据示例(广东省广州市)
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM streets", Integer.class);
-
-            if (count == null || count == 0) {
-                // 省
-                jdbcTemplate.execute("INSERT INTO streets (province, province_code, full_name, level, parent_id, sort_order) VALUES " +
-                        "('广东省', '44', '广东省', 1, NULL, 1)");
-
-                // 市
-                jdbcTemplate.execute("INSERT INTO streets (province, province_code, city, city_code, full_name, level, parent_id, sort_order) VALUES " +
-                        "('广东省', '44', '广州市', '4401', '广东省广州市', 2, 1, 1), " +
-                        "('广东省', '44', '深圳市', '4403', '广东省深圳市', 2, 1, 2), " +
-                        "('广东省', '44', '珠海市', '4404', '广东省珠海市', 2, 1, 3)");
-
-                // 区
-                jdbcTemplate.execute("INSERT INTO streets (province, province_code, city, city_code, district, district_code, full_name, level, parent_id, sort_order) VALUES " +
-                        "('广东省', '44', '广州市', '4401', '天河区', '440106', '广东省广州市天河区', 3, 2, 1), " +
-                        "('广东省', '44', '广州市', '4401', '越秀区', '440104', '广东省广州市越秀区', 3, 2, 2), " +
-                        "('广东省', '44', '广州市', '4401', '番禺区', '440113', '广东省广州市番禺区', 3, 2, 3), " +
-                        "('广东省', '44', '深圳市', '4403', '南山区', '440305', '广东省深圳市南山区', 3, 3, 1), " +
-                        "('广东省', '44', '深圳市', '4403', '福田区', '440304', '广东省深圳市福田区', 3, 3, 2)");
-
-                // 街道
-                jdbcTemplate.execute("INSERT INTO streets (province, province_code, city, city_code, district, district_code, street, street_code, full_name, level, parent_id, sort_order) VALUES " +
-                        "('广东省', '44', '广州市', '4401', '天河区', '440106', '天河南街道', '440106001', '广东省广州市天河区天河南街道', 4, 4, 1), " +
-                        "('广东省', '44', '广州市', '4401', '天河区', '440106', '沙河街道', '440106002', '广东省广州市天河区沙河街道', 4, 4, 2), " +
-                        "('广东省', '44', '广州市', '4401', '越秀区', '440104', '东山街道', '440104001', '广东省广州市越秀区东山街道', 4, 5, 1), " +
-                        "('广东省', '44', '广州市', '4401', '番禺区', '440113', '市桥街道', '440113001', '广东省广州市番禺区市桥街道', 4, 6, 1), " +
-                        "('广东省', '44', '深圳市', '4403', '南山区', '440305', '南山街道', '440305001', '广东省深圳市南山区南山街道', 4, 7, 1), " +
-                        "('广东省', '44', '深圳市', '4403', '福田区', '440304', '福田街道', '440304001', '广东省深圳市福田区福田街道', 4, 8, 1)");
-
-                log.info("街道示例数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化街道数据失败: {}", e.getMessage());
-        }
-
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admins", Integer.class);
-
-            if (count == null || count == 0) {
-                // 默认管理员: 手机号 13800138000, 密码 admin123
-                String encryptedPassword = org.springframework.util.DigestUtils.md5DigestAsHex("xzyj_admin_salt_admin123".getBytes());
-                jdbcTemplate.execute("INSERT INTO admins (username, password, real_name, phone, email, role, status) VALUES " +
-                        "('admin', '" + encryptedPassword + "', '系统管理员', '13800138000', 'admin@xzyj.com', 'admin', 1)");
-                log.info("默认管理员已初始化: 手机号 13800138000, 密码 admin123");
-            }
-        } catch (Exception e) {
-            log.warn("初始化任务模板失败: {}", e.getMessage());
-        }
-
-// 初始化 users 表测试用户
-        try {
-            // 创建默认家庭(如果不存在)
-            Integer familyCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM families WHERE id = 1", Integer.class);
-            if (familyCount == null || familyCount == 0) {
-                jdbcTemplate.execute("INSERT INTO families (id, name, invite_code) VALUES (1, '默认家庭', '888888')");
-                log.info("默认家庭已创建");
-            }
-
-            // 密码加密: MD5("xzyj_salt_" + password)
-            String adminPassword = org.springframework.util.DigestUtils.md5DigestAsHex("xzyj_salt_admin123".getBytes());
-            String teacherPassword = org.springframework.util.DigestUtils.md5DigestAsHex("xzyj_salt_teacher123".getBytes());
-
-            // 创建管理员用户(管理员角色,密码 admin123)
-            Integer adminUserCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM users WHERE phone = '13800138000'", Integer.class);
-            if (adminUserCount == null || adminUserCount == 0) {
-                jdbcTemplate.execute("INSERT INTO users (openid, family_id, role, phone, nickname, real_name, password) VALUES " +
-                        "('seed_admin_13800138000', 1, 'admin', '13800138000', '系统管理员', '系统管理员', '" + adminPassword + "')");
-                log.info("测试管理员用户已创建: 13800138000 (admin角色, 密码 admin123)");
-            }
-
-            // 创建测试教师用户
-            Integer teacherUserCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM users WHERE phone = '13800138001'", Integer.class);
-            if (teacherUserCount == null || teacherUserCount == 0) {
-                jdbcTemplate.execute("INSERT INTO users (openid, family_id, role, phone, nickname, real_name, password) VALUES " +
-                        "('seed_teacher_13800138001', 1, 'teacher', '13800138001', '测试教师', '测试教师', '" + teacherPassword + "')");
-                log.info("测试教师用户已创建: 13800138001 (教师角色, 密码 teacher123)");
-            }
-        } catch (Exception e) {
-            log.warn("初始化测试用户失败: {}", e.getMessage());
-        }
-
-        // 初始化星座配置种子数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM zodiac_config", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO zodiac_config (zodiac_code, zodiac_name, element, start_month, start_day, end_month, end_day, mind_base, wisdom_base, body_modifier, action_modifier, wealth_modifier) VALUES " +
-                        "('aries',       '白羊座', '火', 3, 21, 4, 19, 65, 70, 1.10, 1.05, 0.95), " +
-                        "('taurus',      '金牛座', '土', 4, 20, 5, 20, 60, 65, 1.05, 1.10, 1.15), " +
-                        "('gemini',      '双子座', '金', 5, 21, 6, 21, 70, 80, 0.95, 1.15, 0.90), " +
-                        "('cancer',      '巨蟹座', '水', 6, 22, 7, 22, 75, 60, 1.00, 0.90, 1.05), " +
-                        "('leo',         '狮子座', '火', 7, 23, 8, 22, 65, 75, 1.15, 1.00, 1.10), " +
-                        "('virgo',       '处女座', '土', 8, 23, 9, 22, 55, 85, 0.95, 1.05, 1.00), " +
-                        "('libra',       '天秤座', '金', 9, 23, 10, 23, 70, 75, 0.90, 0.95, 1.10), " +
-                        "('scorpio',     '天蝎座', '水', 10, 24, 11, 22, 80, 70, 1.10, 1.00, 1.15), " +
-                        "('sagittarius', '射手座', '火', 11, 23, 12, 21, 60, 65, 1.15, 1.15, 0.95), " +
-                        "('capricorn',   '摩羯座', '土', 12, 22, 1, 19, 55, 75, 1.05, 1.10, 1.20), " +
-                        "('aquarius',    '水瓶座', '金', 1, 20, 2, 18, 75, 85, 0.95, 0.90, 1.00), " +
-                        "('pisces',      '双鱼座', '水', 2, 19, 3, 20, 80, 60, 0.90, 0.95, 0.95)");
-                log.info("星座配置种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化星座配置失败: {}", e.getMessage());
-        }
-
-        // 初始化八字配置种子数据(十天干 + 十二地支)
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM bazi_config", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO bazi_config (stem_or_branch, type, element, yin_yang, mind_base, wisdom_base, body_modifier, action_modifier, wealth_modifier) VALUES " +
-                        "('甲', 'stem', '木', 'yang', 60, 75, 1.05, 1.10, 1.00), " +
-                        "('乙', 'stem', '木', 'yin',  65, 70, 0.95, 1.05, 1.00), " +
-                        "('丙', 'stem', '火', 'yang', 75, 65, 1.10, 1.00, 0.95), " +
-                        "('丁', 'stem', '火', 'yin',  70, 60, 1.05, 0.95, 1.00), " +
-                        "('戊', 'stem', '土', 'yang', 60, 65, 1.15, 1.05, 1.10), " +
-                        "('己', 'stem', '土', 'yin',  55, 60, 1.10, 1.00, 1.15), " +
-                        "('庚', 'stem', '金', 'yang', 65, 80, 1.05, 1.10, 1.05), " +
-                        "('辛', 'stem', '金', 'yin',  60, 75, 0.95, 1.00, 1.10), " +
-                        "('壬', 'stem', '水', 'yang', 70, 70, 1.00, 0.95, 1.15), " +
-                        "('癸', 'stem', '水', 'yin',  75, 65, 0.95, 0.90, 1.10), " +
-                        "('子', 'branch', '水', 'yang', 70, 65, 1.00, 0.95, 1.05), " +
-                        "('丑', 'branch', '土', 'yin',  55, 60, 1.10, 1.05, 1.10), " +
-                        "('寅', 'branch', '木', 'yang', 65, 75, 1.15, 1.10, 1.00), " +
-                        "('卯', 'branch', '木', 'yin',  60, 70, 1.05, 1.05, 0.95), " +
-                        "('辰', 'branch', '土', 'yang', 60, 65, 1.10, 1.00, 1.10), " +
-                        "('巳', 'branch', '火', 'yin',  75, 70, 1.05, 0.95, 1.00), " +
-                        "('午', 'branch', '火', 'yang', 80, 65, 1.15, 1.00, 0.95), " +
-                        "('未', 'branch', '土', 'yin',  55, 60, 1.05, 1.00, 1.05), " +
-                        "('申', 'branch', '金', 'yang', 65, 80, 1.00, 1.10, 1.05), " +
-                        "('酉', 'branch', '金', 'yin',  60, 75, 0.95, 1.05, 1.10), " +
-                        "('戌', 'branch', '土', 'yang', 60, 65, 1.10, 1.00, 1.15), " +
-                        "('亥', 'branch', '水', 'yin',  70, 60, 1.00, 0.95, 1.05)");
-                log.info("八字配置种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化八字配置失败: {}", e.getMessage());
-        }
-
-        // 初始化血型配置种子数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM blood_type_config", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO blood_type_config (blood_type, description, mind_base, wisdom_base, body_modifier, action_modifier, wealth_modifier) VALUES " +
-                        "('A',  '认真负责、严谨细致,但易焦虑', 70, 75, 0.95, 1.00, 1.05), " +
-                        "('B',  '乐观开朗、好奇心强,但缺乏耐心', 65, 70, 1.05, 1.10, 0.95), " +
-                        "('AB', '理性冷静、适应力强,但优柔寡断', 75, 80, 1.00, 0.95, 1.10), " +
-                        "('O',  '自信果断、行动力强,但固执己见', 60, 65, 1.15, 1.15, 1.15)");
-                log.info("血型配置种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化血型配置失败: {}", e.getMessage());
-        }
-
-        // 初始化优惠券种子数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM coupon", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.update(
-                        "INSERT INTO coupon (name, type, value, min_spend, applicable_to, valid_from, valid_until, total_count, used_count, grant_type, grant_level_code) " +
-                                "VALUES (?, ?, ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 YEAR), -1, 0, NULL, NULL)",
-                        "新用户专享10元券", "FIXED", 1000, 0, "ALL");
-                jdbcTemplate.update(
-                        "INSERT INTO coupon (name, type, value, min_spend, applicable_to, valid_from, valid_until, total_count, used_count, grant_type, grant_level_code) " +
-                                "VALUES (?, ?, ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 YEAR), -1, 0, NULL, NULL)",
-                        "会员升级50元券", "FIXED", 5000, 9900, "MEMBERSHIP");
-                // JOIN 赠券模板:开通家庭会员赠 20 元券
-                jdbcTemplate.update(
-                        "INSERT INTO coupon (name, type, value, min_spend, applicable_to, valid_from, valid_until, total_count, used_count, grant_type, grant_level_code, grant_quantity) " +
-                                "VALUES (?, ?, ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 YEAR), -1, 0, 'JOIN', 'FAMILY', 1)");
-                // JOIN 赠券模板:开通 Premium 会员赠 50 元券
-                jdbcTemplate.update(
-                        "INSERT INTO coupon (name, type, value, min_spend, applicable_to, valid_from, valid_until, total_count, used_count, grant_type, grant_level_code, grant_quantity) " +
-                                "VALUES (?, ?, ?, ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 1 YEAR), -1, 0, 'JOIN', 'PREMIUM', 1)");
-                log.info("优惠券种子数据已初始化(含 JOIN 赠券模板)");
-            }
-        } catch (Exception e) {
-            log.warn("初始化优惠券数据失败: {}", e.getMessage());
-        }
-
-        // 初始化成长规划师模块相关表
-        initGuideModuleTables(jdbcTemplate);
-    }
-
-    private void initGuideModuleTables(JdbcTemplate jdbcTemplate) {
-        // 服务类型表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS service_types (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '类型名称', " +
-                    "icon VARCHAR(50) COMMENT '图标', " +
-                    "description VARCHAR(500) COMMENT '描述', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE/DISABLED', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建service_types表失败: {}", e.getMessage());
-        }
-
-        // 服务内容表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS service_contents (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "type_id BIGINT NOT NULL COMMENT '关联服务类型', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '内容标题', " +
-                    "content TEXT COMMENT '富文本内容', " +
-                    "duration INT COMMENT '建议时长(分钟)', " +
-                    "age_range VARCHAR(50) COMMENT '适用年龄', " +
-                    "price INT COMMENT '参考价格(分)', " +
-                    "status VARCHAR(20) DEFAULT 'DRAFT' COMMENT '状态:DRAFT/ACTIVE', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建service_contents表失败: {}", e.getMessage());
-        }
-
-        // 套餐模板表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_package_templates (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '模板名称', " +
-                    "validity_months INT COMMENT '有效期(月)', " +
-                    "reference_price INT COMMENT '参考价格(分)', " +
-                    "min_price INT COMMENT '最低售价(分)', " +
-                    "description VARCHAR(500) COMMENT '说明', " +
-                    "status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE/DISABLED', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_package_templates表失败: {}", e.getMessage());
-        }
-
-        // 套餐模板服务项表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS package_template_services (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "template_id BIGINT NOT NULL COMMENT '关联模板', " +
-                    "content_id BIGINT NOT NULL COMMENT '关联服务内容', " +
-                    "quantity INT DEFAULT 1 COMMENT '数量', " +
-                    "unit VARCHAR(20) COMMENT '单位' " +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建package_template_services表失败: {}", e.getMessage());
-        }
-
-        // 成长规划师套餐表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_packages (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "teacher_id BIGINT NOT NULL COMMENT '成长规划师ID', " +
-                    "template_id BIGINT COMMENT '关联模板', " +
-                    "name VARCHAR(100) NOT NULL COMMENT '套餐名称', " +
-                    "price INT NOT NULL COMMENT '销售价格(分)', " +
-                    "validity_months INT COMMENT '有效期(月)', " +
-                    "description VARCHAR(500) COMMENT '套餐说明', " +
-                    "status VARCHAR(20) DEFAULT 'DRAFT' COMMENT '状态:DRAFT/PUBLISHED/PAUSED', " +
-                    "sales_count INT DEFAULT 0 COMMENT '销量', " +
-                    "share_code VARCHAR(50) COMMENT '分享码', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_packages表失败: {}", e.getMessage());
-        }
-
-        // 迁移:guide_packages 表添加缺失列
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN guide_id BIGINT COMMENT '成长规划师ID' AFTER id");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN package_id BIGINT COMMENT '关联模板' AFTER guide_id");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN commission_rate INT COMMENT '佣金比例(bps,100=1%)' AFTER package_id");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages MODIFY COLUMN teacher_id BIGINT NULL");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages MODIFY COLUMN template_id BIGINT NULL");
-        } catch (Exception e) {
-        }
-
-        // 迁移:guide_packages 表添加 level 列(GuidePackage 实体需要)
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN level VARCHAR(20) COMMENT '套餐等级' AFTER name");
-        } catch (Exception e) {
-        }
-
-        // 迁移:guide_packages 表添加 validity_days 列
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN validity_days INT DEFAULT 0 COMMENT '有效期天数' AFTER validity_months");
-        } catch (Exception e) {
-        }
-
-        // 迁移:guide_packages 表添加 sort_order 列
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_packages ADD COLUMN sort_order INT DEFAULT 0 COMMENT '排序' AFTER status");
-        } catch (Exception e) {
-        }
-
-        // 成长规划师套餐服务项表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_package_services (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "package_id BIGINT NOT NULL COMMENT '关联套餐', " +
-                    "content_id BIGINT NOT NULL COMMENT '关联服务内容', " +
-                    "quantity INT DEFAULT 1 COMMENT '数量', " +
-                    "unit VARCHAR(20) COMMENT '单位' " +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_package_services表失败: {}", e.getMessage());
-        }
-
-        // 订单表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_orders (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_no VARCHAR(50) NOT NULL COMMENT '订单号', " +
-                    "teacher_id BIGINT NOT NULL COMMENT '成长规划师ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "package_id BIGINT NOT NULL COMMENT '套餐ID', " +
-                    "amount INT NOT NULL COMMENT '金额(分)', " +
-                    "status VARCHAR(20) DEFAULT 'PENDING' COMMENT '状态:PENDING/PAID/COMPLETED/REFUNDED', " +
-                    "pay_time DATETIME COMMENT '支付时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_orders表失败: {}", e.getMessage());
-        }
-
-        // 佣金明细表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_commissions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "teacher_id BIGINT NOT NULL COMMENT '成长规划师ID', " +
-                    "order_id BIGINT NOT NULL COMMENT '订单ID', " +
-                    "amount INT NOT NULL COMMENT '佣金金额(分)', " +
-                    "rate INT COMMENT '佣金比例(bps,100=1%)', " +
-                    "status VARCHAR(20) DEFAULT 'PENDING' COMMENT '状态:PENDING/COMPLETED', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_commissions表失败: {}", e.getMessage());
-        }
-
-        // 服务记录表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_service_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "teacher_id BIGINT NOT NULL COMMENT '成长规划师ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "order_id BIGINT COMMENT '订单ID', " +
-                    "service_content_id BIGINT NOT NULL COMMENT '服务内容ID', " +
-                    "notes VARCHAR(500) COMMENT '服务记录', " +
-                    "duration INT COMMENT '服务时长(分钟)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_service_logs表失败: {}", e.getMessage());
-        }
-
-        // 成长规划师邀请码表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_invite_codes (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "guide_id BIGINT NOT NULL COMMENT '成长规划师用户ID', " +
-                    "code VARCHAR(50) NOT NULL UNIQUE COMMENT '邀请码', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态', " +
-                    "used_by_user_id BIGINT COMMENT '使用该邀请码的用户ID', " +
-                    "used_at DATETIME COMMENT '使用时间', " +
-                    "expire_at DATETIME COMMENT '过期时间', " +
-                    "use_count INT DEFAULT 0 COMMENT '使用次数', " +
-                    "max_use_count INT COMMENT '最大使用次数', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ")");
-        } catch (Exception e) {
-            log.warn("创建guide_invite_codes表失败: {}", e.getMessage());
-        }
-
-        // 迁移29: assessment_orders表添加appointment_id字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_orders ADD COLUMN appointment_id BIGINT COMMENT '关联的预约ID'");
-            log.info("已添加appointment_id列到assessment_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 财富维度: 财商打卡记录表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS finance_checkins (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT NULL COMMENT '孩子ID,家长本人打卡时为NULL', " +
-                    "checkin_type VARCHAR(20) NOT NULL COMMENT '打卡类型: daily_plan/saving/expense/review', " +
-                    "type VARCHAR(10) DEFAULT 'expense' COMMENT '类型: income(收入)/expense(支出)', " +
-                    "checkin_date DATE NOT NULL COMMENT '打卡日期', " +
-                    "amount INT COMMENT '金额(分,收支记录)', " +
-                    "category VARCHAR(50) COMMENT '收支分类', " +
-                    "note VARCHAR(200) COMMENT '备注', " +
-                    "mood VARCHAR(20) COMMENT '心情', " +
-                    "earned_energy INT DEFAULT 0 COMMENT '获得的能量值', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_date (user_id, checkin_date), " +
-                    "INDEX idx_child (child_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='财商打卡记录表'");
-            log.info("已创建finance_checkins表");
-        } catch (Exception e) {
-            log.warn("创建finance_checkins表失败: {}", e.getMessage());
-        }
-
-        // 财富维度: 保单管理表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS insurance_policies (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT COMMENT '关联孩子ID', " +
-                    "policy_name VARCHAR(100) NOT NULL COMMENT '保单名称', " +
-                    "insurance_company VARCHAR(100) COMMENT '保险公司', " +
-                    "policy_type VARCHAR(50) COMMENT '保单类型: medical/life/accident/education/endowment', " +
-                    "insured_person VARCHAR(50) NOT NULL COMMENT '被保人姓名', " +
-                    "premium INT COMMENT '保费(分)', " +
-                    "sum_insured INT COMMENT '保额(分)', " +
-                    "start_date DATE COMMENT '生效日期', " +
-                    "end_date DATE COMMENT '到期日期', " +
-                    "renewal_type VARCHAR(20) DEFAULT 'annual' COMMENT '续费类型: annual/monthly/single', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/expired/cancelled', " +
-                    "policy_no VARCHAR(100) COMMENT '保单号', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_child (child_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='保单管理表'");
-            log.info("已创建insurance_policies表");
-        } catch (Exception e) {
-            log.warn("创建insurance_policies表失败: {}", e.getMessage());
-        }
-
-        // ==================== 健康检测报告模块 =============        // 健康报告表(体检报告/菌群检测报告)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_reports (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "family_id BIGINT COMMENT '家庭ID', " +
-                    "report_type VARCHAR(32) NOT NULL COMMENT '报告类型: physical_exam(体检)/gut_flora(菌群检测)', " +
-                    "report_date DATE COMMENT '报告日期', " +
-                    "overall_score INT COMMENT '健康总分(0-100)', " +
-                    "gut_health_score INT COMMENT '菌群健康分', " +
-                    "chronic_disease_score INT COMMENT '慢病控制分', " +
-                    "nutrition_score INT COMMENT '营养均衡分', " +
-                    "gut_age VARCHAR(32) COMMENT '肠道预测年龄', " +
-                    "gut_type VARCHAR(50) COMMENT '肠型', " +
-                    "file_url VARCHAR(500) COMMENT '报告文件URL', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/archived', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_report_type (report_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康检测报告表'");
-            log.info("已创建health_reports表");
-        } catch (Exception e) {
-            log.warn("创建health_reports表可能已存在: {}", e.getMessage());
-        }
-
-        // 健康指标明细表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_indicators (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL COMMENT '关联报告ID', " +
-                    "category VARCHAR(50) COMMENT '指标分类: 营养状况/疾病风险/肠道屏障/神经递质/...', " +
-                    "indicator_name VARCHAR(100) NOT NULL COMMENT '指标名称', " +
-                    "indicator_value VARCHAR(100) COMMENT '检测值', " +
-                    "unit VARCHAR(50) COMMENT '单位', " +
-                    "ref_range VARCHAR(200) COMMENT '参考范围', " +
-                    "status VARCHAR(50) COMMENT '评估状态: 正常/偏低/偏高/过多/注意/低风险/未检出', " +
-                    "sort_order INT DEFAULT 0 COMMENT '显示排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_report_id (report_id), " +
-                    "INDEX idx_category (category)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康指标明细表'");
-            log.info("已创建health_indicators表");
-        } catch (Exception e) {
-            log.warn("创建health_indicators表可能已存在: {}", e.getMessage());
-        }
-
-        // ---------- 健康报告表 新增菌群摘要字段 ----------
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports " +
-                    "ADD COLUMN gut_balance_score INT COMMENT '菌群平衡分(0-100)', " +
-                    "ADD COLUMN gut_diversity_score INT COMMENT '菌群多样性分(0-100)', " +
-                    "ADD COLUMN beneficial_bacteria_score INT COMMENT '有益菌分(0-100)', " +
-                    "ADD COLUMN harmful_bacteria_score INT COMMENT '有害菌分(0-100)', " +
-                    "ADD COLUMN core_species_score INT COMMENT '核心菌属分(0-100)', " +
-                    "ADD COLUMN health_rating VARCHAR(100) COMMENT '总分评级,如亚健康/优秀等'");
-            log.info("已为health_reports表添加6个菌群摘要字段");
-        } catch (Exception e) {
-            log.warn("为health_reports表添加字段可能已存在: {}", e.getMessage());
-        }
-
-
-        ensureColumn("health_reports", "subject_id", "BIGINT COMMENT '报告主体用户ID(关联users表,为null表示未绑定)'");
-
-        log.info("成长规划师模块、财富维度及健康检测报告数据库表初始化完成");
-
-        // 健康打卡表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_checkins (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID(家长)', " +
-                    "child_id BIGINT COMMENT '孩子ID', " +
-                    "checkin_date DATE COMMENT '打卡日期', " +
-                    "behaviors TEXT COMMENT '打卡行为JSON数组', " +
-                    "note VARCHAR(500) COMMENT '备注', " +
-                    "mood VARCHAR(20) COMMENT '心情: happy/normal/sad/angry/sick', " +
-                    "earned_energy INT DEFAULT 5 COMMENT '获得能量值', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_checkin_date (checkin_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康打卡表'");
-            log.info("已创建health_checkins表");
-        } catch (Exception e) {
-            log.warn("创建health_checkins表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移31: 创建联系人表
-
-        // 创建文章阅读记录表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS article_reading_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '孩子ID', " +
-                    "content VARCHAR(500) COMMENT '阅读内容摘要', " +
-                    "duration_seconds INT DEFAULT 0 COMMENT '阅读时长(秒)', " +
-                    "read_at DATETIME COMMENT '阅读时间', " +
-                    "created_at DATETIME, " +
-                    "INDEX idx_child_id (child_id), " +
-                    "INDEX idx_read_at (read_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章阅读记录表'");
-            log.info("已创建article_reading_records表");
-        } catch (Exception e) {
-            log.warn("创建article_reading_records表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移32: products表添加配送/类目/销售字段(商品编辑表单对齐)
-        ensureColumn("products", "delivery_method", "TINYINT DEFAULT 1 COMMENT '配送方式: 1=快递 2=自提 3=两者皆可'");
-        ensureColumn("products", "category_id", "BIGINT COMMENT '商品类目ID'");
-        ensureColumn("products", "distribution_system_id", "BIGINT COMMENT '销售体系ID'");
-
-        // 迁移33: 创建供应商销售体系表 + product_orders扩展字段
-        // 迁移222: health_reports 添加 shannon_index, payload_json 列并创建 health_report_edit_logs 表
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN shannon_index VARCHAR(32) DEFAULT NULL COMMENT '香农指数'");
-            log.info("已添加shannon_index列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_reports ADD COLUMN payload_json LONGTEXT COMMENT '报告完整载荷快照'");
-            log.info("已添加payload_json列到health_reports表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_report_edit_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "report_id BIGINT NOT NULL, " +
-                    "user_id BIGINT, " +
-                    "report_type VARCHAR(32), " +
-                    "action VARCHAR(20) COMMENT 'create/edit', " +
-                    "before_payload LONGTEXT, " +
-                    "after_payload LONGTEXT, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告修改留痕'");
-            log.info("已创建health_report_edit_logs表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-        ensureColumn("product_orders", "supply_system_id", "BIGINT COMMENT '所属供应商体系ID'");
-        ensureColumn("product_orders", "supplier_id", "BIGINT COMMENT '收款供应商用户ID'");
-        ensureColumn("product_orders", "supply_commission", "INT COMMENT '销售佣金(分)'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD KEY idx_supply_system_id (supply_system_id)");
-            log.info("已添加idx_supply_system_id索引到product_orders表");
-        } catch (Exception e) {
-            log.warn("添加idx_supply_system_id索引可能已存在: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_system (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '体系名称', " +
-                    "admin_id BIGINT NOT NULL COMMENT '管理员用户ID', " +
-                    "settlement_period_days INT NOT NULL DEFAULT 30 COMMENT '账期(天)', " +
-                    "platform_profit_rate DECIMAL(5,2) NOT NULL DEFAULT 0 COMMENT '平台留利比例(%)', " +
-                    "description VARCHAR(500) COMMENT '描述', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active/disabled', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "KEY idx_admin_id (admin_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商体系'");
-            log.info("已创建supply_system表");
-        } catch (Exception e) {
-            log.warn("创建supply_system表可能已存在: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_system_member (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '体系ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "role VARCHAR(20) NOT NULL DEFAULT 'member' COMMENT '角色: admin/member', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active/inactive', " +
-                    "joined_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_system_user (system_id, user_id), " +
-                    "KEY idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='体系成员'");
-            log.info("已创建supply_system_member表");
-        } catch (Exception e) {
-            log.warn("创建supply_system_member表可能已存在: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_settlement (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '体系ID', " +
-                    "period_start DATE NOT NULL COMMENT '结算周期开始', " +
-                    "period_end DATE NOT NULL COMMENT '结算周期结束', " +
-                    "total_sales INT NOT NULL DEFAULT 0 COMMENT '销售总额(分)', " +
-                    "platform_profit INT NOT NULL DEFAULT 0 COMMENT '平台留利金额(分)', " +
-                    "supplier_payout INT NOT NULL DEFAULT 0 COMMENT '供应商实付(分)', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/settled', " +
-                    "settled_at DATETIME COMMENT '结算时间', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "KEY idx_system_id (system_id), " +
-                    "KEY idx_period (period_start, period_end)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算记录'");
-            log.info("已创建supply_settlement表");
-        } catch (Exception e) {
-            log.warn("创建supply_settlement表可能已存在: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_settlement_detail (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "settlement_id BIGINT NOT NULL COMMENT '结算ID', " +
-                    "order_id BIGINT NOT NULL COMMENT '订单ID', " +
-                    "order_no VARCHAR(64) NOT NULL COMMENT '订单号', " +
-                    "product_name VARCHAR(200) NOT NULL COMMENT '商品名称', " +
-                    "amount INT NOT NULL COMMENT '订单金额(分)', " +
-                    "platform_fee INT NOT NULL COMMENT '平台留利(分)', " +
-                    "supplier_id BIGINT COMMENT '收款供应商用户ID', " +
-                    "supplier_name VARCHAR(100) COMMENT '收款供应商名称', " +
-                    "payout INT NOT NULL COMMENT '供应商实付(分)', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "KEY idx_settlement_id (settlement_id), " +
-                    "KEY idx_order_id (order_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算明细'");
-            log.info("已创建supply_settlement_detail表");
-        } catch (Exception e) {
-            log.warn("创建supply_settlement_detail表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移: growth_records表添加来源类型/去重/补充字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN source_type VARCHAR(20) DEFAULT 'manual' COMMENT '来源类型: manual/platform_purchase/self_upload/supplement'");
-            log.info("已添加source_type列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN source_file_url VARCHAR(500) COMMENT '原始报告文件URL'");
-            log.info("已添加source_file_url列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN order_id BIGINT COMMENT '关联订单ID'");
-            log.info("已添加order_id列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN report_date DATETIME COMMENT '测评/报告日期'");
-            log.info("已添加report_date列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN parent_record_id BIGINT COMMENT '关联的原始档案ID(补充档案专用)'");
-            log.info("已添加parent_record_id列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN is_latest TINYINT(1) DEFAULT 1 COMMENT '是否同组最新记录'");
-            log.info("已添加is_latest列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN dedup_hash VARCHAR(64) COMMENT '去重哈希值(SHA256)'");
-            log.info("已添加dedup_hash列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_records ADD COLUMN parsed_data TEXT COMMENT '上传报告的解析结果(JSON)'");
-            log.info("已添加parsed_data列到growth_records表");
-        } catch (Exception e) {
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE UNIQUE INDEX IF NOT EXISTS uk_growth_dedup_hash ON growth_records(dedup_hash)");
-            log.info("已添加uk_growth_dedup_hash唯一索引到growth_records表");
-        } catch (Exception e) {
-            try {
-                jdbcTemplate.execute("ALTER TABLE growth_records ADD UNIQUE INDEX uk_growth_dedup_hash (dedup_hash)");
-                log.info("已通过ALTER TABLE添加uk_growth_dedup_hash唯一索引");
-            } catch (Exception e2) {
-                log.warn("添加uk_growth_dedup_hash索引可能已存在: {}", e2.getMessage());
-            }
-        }
-
-        // 初始化成长任务种子数据
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM growth_task", Integer.class);
-
-            if (count == null || count == 0) {
-                jdbcTemplate.execute("INSERT INTO growth_task (type, title, description, reward_points, reward_energy, target_value, task_key, enabled, sort_order, created_at) VALUES " +
-                        "('DAILY', '每日签到', '完成健康打卡签到', 20, 3, 1, 'DAILY_CHECKIN', 1, 1, NOW()), " +
-                        "('DAILY', '完成任务', '完成一个任务', 30, 5, 1, 'DAILY_TASK', 1, 2, NOW()), " +
-                        "('DAILY', '每日分享', '分享小程序给好友', 10, 2, 1, 'DAILY_SHARE', 1, 3, NOW()), " +
-                        "('DAILY', 'AI对话', '与AI助手对话一次', 15, 3, 1, 'DAILY_AI', 1, 4, NOW())");
-                log.info("成长任务种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("初始化成长任务种子数据失败: {}", e.getMessage());
-        }
-
-        // 迁移34: dan_assessment_results表添加家庭成员/EMI心理/大五人格/孩子快照字段
-        ensureColumn("dan_assessment_results", "family_member_id", "BIGINT COMMENT '家庭成员ID'");
-        ensureColumn("dan_assessment_results", "family_member_name", "VARCHAR(50) COMMENT '成员姓名快照'");
-        ensureColumn("dan_assessment_results", "family_member_birthday", "DATE COMMENT '成员出生日期快照'");
-        ensureColumn("dan_assessment_results", "family_member_gender", "VARCHAR(10) COMMENT '成员性别快照'");
-        ensureColumn("dan_assessment_results", "family_member_age", "INT COMMENT '成员年龄快照'");
-        ensureColumn("dan_assessment_results", "emotion_score", "INT COMMENT '情绪商数(EMI)'");
-        ensureColumn("dan_assessment_results", "resilience_score", "INT COMMENT '心理韧性(EMI)'");
-        ensureColumn("dan_assessment_results", "stress_coping_score", "INT COMMENT '压力应对(EMI)'");
-        ensureColumn("dan_assessment_results", "self_awareness_score", "INT COMMENT '自我认知(EMI)'");
-        ensureColumn("dan_assessment_results", "openness_score", "INT COMMENT '开放性(大五人格)'");
-        ensureColumn("dan_assessment_results", "conscientiousness_score", "INT COMMENT '尽责性(大五人格)'");
-        ensureColumn("dan_assessment_results", "extraversion_score", "INT COMMENT '外向性(大五人格)'");
-        ensureColumn("dan_assessment_results", "agreeableness_score", "INT COMMENT '宜人性(大五人格)'");
-        ensureColumn("dan_assessment_results", "neuroticism_score", "INT COMMENT '神经质(大五人格)'");
-        ensureColumn("dan_assessment_results", "big_five_overall_score", "INT COMMENT '大五人格综合分'");
-        ensureColumn("dan_assessment_results", "child_name", "VARCHAR(50) COMMENT '孩子姓名快照'");
-        ensureColumn("dan_assessment_results", "child_birthday", "DATE COMMENT '出生日期快照'");
-        ensureColumn("dan_assessment_results", "child_gender", "VARCHAR(10) COMMENT '性别快照'");
-        ensureColumn("dan_assessment_results", "child_age", "INT COMMENT '年龄快照'");
-        ensureColumn("dan_assessment_results", "school", "VARCHAR(100) COMMENT '学校快照'");
-        ensureColumn("dan_assessment_results", "grade", "VARCHAR(20) COMMENT '年级快照'");
-        ensureColumn("dan_assessment_results", "grade_class", "VARCHAR(20) COMMENT '班级快照'");
-        ensureColumn("dan_assessment_results", "height", "INT COMMENT '身高(CM)快照'");
-        ensureColumn("dan_assessment_results", "weight", "INT COMMENT '体重(KG)快照'");
-        ensureColumn("dan_assessment_results", "family_status", "VARCHAR(50) COMMENT '家庭状况快照'");
-        ensureColumn("dan_assessment_results", "parent_degree", "VARCHAR(50) COMMENT '父母最高学历快照'");
-        ensureColumn("dan_assessment_results", "nation", "VARCHAR(20) COMMENT '民族快照'");
-        ensureColumn("dan_assessment_results", "province", "VARCHAR(50) COMMENT '省快照'");
-        ensureColumn("dan_assessment_results", "city", "VARCHAR(50) COMMENT '市快照'");
-        ensureColumn("dan_assessment_results", "district", "VARCHAR(50) COMMENT '区快照'");
-        ensureColumn("dan_assessment_results", "address", "VARCHAR(200) COMMENT '详细地址快照'");
-        ensureColumn("dan_assessment_results", "single_child", "VARCHAR(10) COMMENT '是否独生子女快照'");
-        ensureColumn("dan_assessment_results", "school_score", "VARCHAR(20) COMMENT '在校成绩快照'");
-        ensureColumn("dan_assessment_results", "urgent_name", "VARCHAR(50) COMMENT '紧急联系人姓名'");
-        ensureColumn("dan_assessment_results", "urgent_phone", "VARCHAR(20) COMMENT '紧急联系人电话'");
-        ensureColumn("dan_assessment_results", "pics", "TEXT COMMENT '图片IDs'");
-        ensureColumn("dan_assessment_results", "videos", "TEXT COMMENT '视频IDs'");
-        ensureColumn("dan_assessment_results", "audio", "VARCHAR(100) COMMENT '音频ID'");
-        ensureColumn("dan_assessment_results", "audio_url", "VARCHAR(255) COMMENT '音频URL'");
-        ensureColumn("dan_assessment_results", "process_desc", "TEXT COMMENT '过程描述'");
-        ensureColumn("dan_assessment_results", "result_desc", "TEXT COMMENT '结果简评'");
-
-        // 迁移35: points_log表添加family_member_id列(EnergyService.calcChildWealth家庭能量计算需要)
-        ensureColumn("points_log", "family_member_id", "BIGINT COMMENT '家庭成员ID'");
-
-        // 迁移36: family_members表添加generation + is_spouse列(辈分重构)
-        ensureColumn("family_members", "generation", "INT COMMENT '辈分值(0=家庭创建者,+n=向上n代,-n=向下n代)'");
-        ensureColumn("family_members", "is_spouse", "TINYINT(1) DEFAULT 0 COMMENT '是否配偶(同辈)'");
-        // 迁移37: relationship_type列已删除,旧数据已迁移完成
-
-        // 迁移38: product_orders表添加points_used/points_cost/money_amount列(混合支付支持)
-        ensureColumn("product_orders", "points_used", "INT DEFAULT 0 COMMENT '使用的积分数量'");
-        ensureColumn("product_orders", "points_cost", "INT DEFAULT 0 COMMENT '积分抵扣金额(分)'");
-        ensureColumn("product_orders", "money_amount", "INT DEFAULT 0 COMMENT '现金支付金额(分)'");
-
-        // 迁移39: 创建供应商体系相关表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_system (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '体系名称', " +
-                    "admin_id BIGINT COMMENT '管理员用户ID', " +
-                    "settlement_period_days INT DEFAULT 30 COMMENT '账期天数', " +
-                    "platform_profit_rate DECIMAL(10,2) DEFAULT 0.00 COMMENT '平台留利比例(%)', " +
-                    "description VARCHAR(500) COMMENT '描述', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/disabled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_admin (admin_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商体系'");
-            log.info("已创建supply_system表");
-        } catch (Exception e) {
-            log.warn("创建supply_system表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_system_member (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '体系ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "role VARCHAR(20) DEFAULT 'member' COMMENT '角色 admin/member', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/disabled', " +
-                    "joined_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_system (system_id), " +
-                    "INDEX idx_user (user_id), " +
-                    "UNIQUE INDEX idx_system_user (system_id, user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商体系成员'");
-            log.info("已创建supply_system_member表");
-        } catch (Exception e) {
-            log.warn("创建supply_system_member表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_settlement (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '体系ID', " +
-                    "period_start DATE COMMENT '结算周期开始', " +
-                    "period_end DATE COMMENT '结算周期结束', " +
-                    "total_sales INT DEFAULT 0 COMMENT '销售总额(分)', " +
-                    "platform_profit INT DEFAULT 0 COMMENT '平台留利(分)', " +
-                    "supplier_payout INT DEFAULT 0 COMMENT '供应商实付(分)', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态 pending/settled', " +
-                    "settled_at DATETIME COMMENT '结算时间', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_system (system_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_period (period_start, period_end)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商结算单'");
-            log.info("已创建supply_settlement表");
-        } catch (Exception e) {
-            log.warn("创建supply_settlement表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_settlement_detail (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "settlement_id BIGINT NOT NULL COMMENT '结算单ID', " +
-                    "order_id BIGINT COMMENT '订单ID', " +
-                    "order_no VARCHAR(64) COMMENT '订单号', " +
-                    "product_name VARCHAR(200) COMMENT '商品名称', " +
-                    "amount INT DEFAULT 0 COMMENT '订单金额(分)', " +
-                    "platform_fee INT DEFAULT 0 COMMENT '平台留利(分)', " +
-                    "supplier_id BIGINT COMMENT '收款供应商ID', " +
-                    "supplier_name VARCHAR(100) COMMENT '收款供应商名称', " +
-                    "payout INT DEFAULT 0 COMMENT '实付(分)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_settlement (settlement_id), " +
-                    "INDEX idx_order (order_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商结算明细'");
-            log.info("已创建supply_settlement_detail表");
-        } catch (Exception e) {
-            log.warn("创建supply_settlement_detail表失败: {}", e.getMessage());
-        }
-
-        // 迁移40: 添加supplier_admin角色到users.role(列已为VARCHAR,直接可用)
-        // 当前role列为VARCHAR(20),无需ALTER ENUM
-
-        // 迁移40: users表添加mascot字段(AI助手形象: xibao浠宝/fubao福宝)
-        ensureColumn("users", "mascot", "VARCHAR(20) DEFAULT NULL COMMENT 'AI助手形象: xibao(浠宝)/fubao(福宝)'");
-
-        // 迁移41: 创建family_relationships表(家庭成员双向关系,替代relationship_type/role_override)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_relationships (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '所属家庭ID', " +
-                    "from_member_id BIGINT NOT NULL COMMENT '关系起点成员ID', " +
-                    "to_member_id BIGINT NOT NULL COMMENT '关系终点成员ID', " +
-                    "generation_value INT NOT NULL COMMENT '辈分值: -1=子女, 0=同辈, 1=父母, 2=祖父母, 3=曾祖父母', " +
-                    "relationship_key VARCHAR(50) COMMENT '关系标签key(冗余用于显示)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_from_to (from_member_id, to_member_id), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_from (from_member_id), " +
-                    "INDEX idx_to (to_member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员双向关系表'");
-            log.info("已创建family_relationships表");
-        } catch (Exception e) {
-            log.warn("创建family_relationships表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移42: 创建butler_sessions表(AI管家会话管理)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS butler_sessions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "title VARCHAR(200) DEFAULT '新会话' COMMENT '会话标题', " +
-                    "conversation_id VARCHAR(100) COMMENT 'Dify对话ID', " +
-                    "context TEXT COMMENT '上下文信息(JSON)', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active(进行中)/archived(已归档)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_user_status (user_id, status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI管家会话表'");
-            log.info("已创建butler_sessions表");
-        } catch (Exception e) {
-            log.warn("创建butler_sessions表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移 79: 创建 tianpan_daily_fortune 表(家庭每日运势)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS tianpan_daily_fortune (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "date VARCHAR(20) NOT NULL COMMENT '日期 YYYY-MM-DD', " +
-                    "lunar_date VARCHAR(50) COMMENT '农历日期', " +
-                    "day_ganzhi VARCHAR(10) COMMENT '日柱', " +
-                    "five_elements_main VARCHAR(20) COMMENT '当日五行主气', " +
-                    "five_elements_detail VARCHAR(100) COMMENT '五行详情', " +
-                    "auspicious TEXT COMMENT '宜做的事(JSON数组)', " +
-                    "inauspicious TEXT COMMENT '忌做的事(JSON数组)', " +
-                    "family_advice TEXT COMMENT '家庭建议', " +
-                    "focus_member_name VARCHAR(50) COMMENT '关注成员', " +
-                    "focus_member_tip TEXT COMMENT '成员提示', " +
-                    "wuxing_tip TEXT COMMENT '五行提示', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_family_date (family_id, date), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_date (date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭每日运势表'");
-            log.info("已创建 tianpan_daily_fortune 表");
-        } catch (Exception e) {
-            log.warn("创建 tianpan_daily_fortune 表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移 80: 创建 tianpan_member_annual_energy 表(成员年度能量)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS tianpan_member_annual_energy (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '成员ID', " +
-                    "year INT NOT NULL COMMENT '年份', " +
-                    "dimensions_body INT DEFAULT 0 COMMENT '身能量', " +
-                    "dimensions_mind INT DEFAULT 0 COMMENT '心能量', " +
-                    "dimensions_wisdom INT DEFAULT 0 COMMENT '智能量', " +
-                    "dimensions_action INT DEFAULT 0 COMMENT '行能量', " +
-                    "dimensions_wealth INT DEFAULT 0 COMMENT '富能量', " +
-                    "jupiter_phase VARCHAR(50) COMMENT '木星相位', " +
-                    "saturn_phase VARCHAR(50) COMMENT '土星相位', " +
-                    "highlights TEXT COMMENT '年度亮点(JSON数组)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_member_year (member_id, year), " +
-                    "INDEX idx_member_id (member_id), " +
-                    "INDEX idx_year (year)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成员年度能量表'");
-            log.info("已创建 tianpan_member_annual_energy 表");
-        } catch (Exception e) {
-            log.warn("创建 tianpan_member_annual_energy 表可能已存在: {}", e.getMessage());
-        }
-    }
-
-    private void insertSysConfigSeed(String key, String value, String desc) {
-        Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM sys_config WHERE config_key = ?", Integer.class, key);
-        if (count == null || count == 0) {
-            jdbcTemplate.update(
-                    "INSERT INTO sys_config (config_key, config_value, description, updated_at) VALUES (?, ?, ?, NOW())",
-                    key, value, desc);
-        }
-    }
-
-    private void initFoodTables() {
-        log.info("开始初始化食品相关表...");
-
-        // 4张新表 (CREATE TABLE IF NOT EXISTS)
-        String[] ddl = {
-"CREATE TABLE IF NOT EXISTS foods ("
-            + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-            + "name VARCHAR(100) NOT NULL COMMENT '食材名称', "
-            + "category VARCHAR(50) COMMENT '分类: 蔬菜/水果/肉禽/水产/蛋奶/豆类/谷物/调味/其他', "
-            + "unit VARCHAR(20) DEFAULT 'g' COMMENT '计量单位', "
-            + "calories DECIMAL(8,2) COMMENT '热量(kcal/100g)', "
-            + "protein DECIMAL(8,2) COMMENT '蛋白质(g/100g)', "
-            + "fat DECIMAL(8,2) COMMENT '脂肪(g/100g)', "
-            + "carbs DECIMAL(8,2) COMMENT '碳水(g/100g)', "
-            + "fiber DECIMAL(8,2) COMMENT '膳食纤维(g/100g)', "
-            + "energy_kj DECIMAL(8,2) COMMENT '能量(kJ/100g)', "
-            + "starch DECIMAL(8,2) COMMENT '淀粉(g/100g)', "
-            + "cholesterol DECIMAL(8,2) COMMENT '胆固醇(mg/100g)', "
-            + "price_level TINYINT COMMENT '价格等级 1-5', "
-            + "nutrition_tags VARCHAR(500) COMMENT '营养标签JSON', "
-            + "suitable_for VARCHAR(200) COMMENT '适宜人群JSON', "
-            + "allergens VARCHAR(200) COMMENT '过敏原JSON', "
-            + "external_source VARCHAR(100) COMMENT '数据来源', "
-            + "external_id VARCHAR(100) COMMENT '外部ID', "
-            + "cover_image VARCHAR(500) COMMENT '食材图片', "
-            + "report_id BIGINT COMMENT '关联报告ID(从PDF解析的食物推荐)', "
-            + "score INT COMMENT '食物评分', "
-            + "diet_type VARCHAR(50) COMMENT '饮食类型', "
-            + "status VARCHAR(20) DEFAULT 'active', "
-            + "sort_order INT DEFAULT 0, "
-            + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-            + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-            + "INDEX idx_category (category), "
-            + "INDEX idx_price (price_level)"
-            + ");",
-
-                "CREATE TABLE IF NOT EXISTS recipes ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "name VARCHAR(200) NOT NULL COMMENT '食谱名称', "
-                        + "meal_type VARCHAR(20) COMMENT '早餐/午餐/晚餐/加餐', "
-                        + "description TEXT COMMENT '简介', "
-                        + "ingredients TEXT NOT NULL COMMENT '食材清单JSON', "
-                        + "steps TEXT COMMENT '烹饪步骤JSON', "
-                        + "cook_time INT COMMENT '烹饪时间(分钟)', "
-                        + "difficulty VARCHAR(20) COMMENT '难度: 简单/中等/困难', "
-                        + "total_calories DECIMAL(8,2) COMMENT '总热量', "
-                        + "total_protein DECIMAL(8,2) COMMENT '总蛋白质', "
-                        + "total_fat DECIMAL(8,2) COMMENT '总脂肪', "
-                        + "total_carbs DECIMAL(8,2) COMMENT '总碳水', "
-                        + "total_fiber DECIMAL(8,2) COMMENT '总膳食纤维', "
-                        + "suitable_for VARCHAR(200) COMMENT '适宜场景', "
-                        + "nutrition_tags VARCHAR(500) COMMENT '营养标签', "
-                        + "external_source VARCHAR(100), "
-                        + "external_id VARCHAR(100), "
-                        + "cover_image VARCHAR(500), "
-                        + "status VARCHAR(20) DEFAULT 'active', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-                        + "INDEX idx_meal_type (meal_type), "
-                        + "INDEX idx_cook_time (cook_time)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS seasonal_foods ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "food_id BIGINT NOT NULL COMMENT '关联foods.id', "
-                        + "month TINYINT NOT NULL COMMENT '月份 1-12', "
-                        + "region VARCHAR(50) DEFAULT '全国' COMMENT '产地', "
-                        + "peak_flag TINYINT DEFAULT 0 COMMENT '盛产标志', "
-                        + "sort_order INT DEFAULT 0, "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "INDEX idx_food_month (food_id, month), "
-                        + "INDEX idx_month (month)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS meal_logs ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "user_id BIGINT NOT NULL COMMENT '用户ID', "
-                        + "child_id BIGINT COMMENT '孩子ID', "
-                        + "meal_type VARCHAR(20) NOT NULL COMMENT '早餐/午餐/晚餐/加餐', "
-                        + "meal_date DATE NOT NULL COMMENT '用餐日期', "
-                        + "meal_time DATETIME COMMENT '具体时间', "
-                        + "foods TEXT NOT NULL COMMENT '食物清单JSON', "
-                        + "total_calories DECIMAL(8,2) COMMENT '总热量', "
-                        + "total_protein DECIMAL(8,2) COMMENT '总蛋白质', "
-                        + "total_fat DECIMAL(8,2) COMMENT '总脂肪', "
-                        + "total_carbs DECIMAL(8,2) COMMENT '总碳水', "
-                        + "total_fiber DECIMAL(8,2) COMMENT '总膳食纤维', "
-                        + "note TEXT COMMENT '备注', "
-                        + "images VARCHAR(1000) COMMENT '图片JSON', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "INDEX idx_user_date (user_id, meal_date), "
-                        + "INDEX idx_child_date (child_id, meal_date)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS report_food_suitability ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "report_id BIGINT NOT NULL COMMENT '健康报告ID', "
-                        + "food_id BIGINT COMMENT '食材ID', "
-                        + "food_name VARCHAR(100) NOT NULL COMMENT '食材名称', "
-                        + "category VARCHAR(50) COMMENT '分类', "
-                        + "score INT NOT NULL COMMENT '适宜度评分', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "INDEX idx_report (report_id), "
-                        + "INDEX idx_food (food_id)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS user_food_preference ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "user_id BIGINT NOT NULL COMMENT '用户ID', "
-                        + "food_id BIGINT COMMENT '食材ID', "
-                        + "food_name VARCHAR(100) NOT NULL COMMENT '食材名称', "
-                        + "score INT NOT NULL DEFAULT 0 COMMENT '评分', "
-                        + "reason VARCHAR(500) COMMENT '原因', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-                        + "INDEX idx_user (user_id)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS food_nutrients ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "food_id BIGINT NOT NULL COMMENT '食材ID', "
-                        + "nutrient_code VARCHAR(20) NOT NULL COMMENT '营养素编码', "
-                        + "amount_per_100g DECIMAL(10,4) NOT NULL COMMENT '每100g含量', "
-                        + "unit VARCHAR(20) NOT NULL COMMENT '单位', "
-                        + "source VARCHAR(50) DEFAULT 'importer' COMMENT '数据来源', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-                        + "UNIQUE KEY uk_food_nutrient (food_id, nutrient_code), "
-                        + "INDEX idx_nutrient (nutrient_code)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS rdi_standards ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "nutrient_code VARCHAR(20) NOT NULL COMMENT '营养素编码', "
-                        + "age_group VARCHAR(10) NOT NULL COMMENT '年龄段', "
-                        + "gender VARCHAR(6) DEFAULT 'all' COMMENT '性别', "
-                        + "rdi_type VARCHAR(10) NOT NULL COMMENT '参考类型', "
-                        + "amount DECIMAL(10,4) NOT NULL COMMENT '推荐量', "
-                        + "unit VARCHAR(20) NOT NULL COMMENT '单位', "
-                        + "source VARCHAR(100) COMMENT '数据来源', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "UNIQUE KEY uk_rdi (nutrient_code, age_group, gender, rdi_type), "
-                        + "INDEX idx_age (age_group)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS shopping_lists ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "user_id BIGINT NOT NULL COMMENT '用户ID', "
-                        + "child_id BIGINT COMMENT '孩子ID', "
-                        + "report_id BIGINT COMMENT '健康报告ID', "
-                        + "title VARCHAR(200) COMMENT '标题', "
-                        + "source VARCHAR(20) NOT NULL COMMENT '来源', "
-                        + "status VARCHAR(20) DEFAULT 'active' COMMENT '状态', "
-                        + "total_items INT DEFAULT 0 COMMENT '总项数', "
-                        + "purchased_items INT DEFAULT 0 COMMENT '已购项数', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-                        + "INDEX idx_user (user_id), "
-                        + "INDEX idx_report (report_id), "
-                        + "INDEX idx_status (status)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS shopping_list_items ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "list_id BIGINT NOT NULL COMMENT '购物清单ID', "
-                        + "food_id BIGINT COMMENT '食材ID', "
-                        + "food_name VARCHAR(100) NOT NULL COMMENT '食材名称', "
-                        + "category VARCHAR(50) COMMENT '分类', "
-                        + "quantity DECIMAL(8,2) DEFAULT 1 COMMENT '数量', "
-                        + "unit VARCHAR(20) DEFAULT '份' COMMENT '单位', "
-                        + "priority VARCHAR(10) DEFAULT 'medium' COMMENT '优先级', "
-                        + "reason VARCHAR(200) COMMENT '推荐原因', "
-                        + "score INT COMMENT '评分', "
-                        + "source VARCHAR(20) COMMENT '来源', "
-                        + "purchased TINYINT DEFAULT 0 COMMENT '是否已购', "
-                        + "purchased_at DATETIME COMMENT '购买时间', "
-                        + "sort_order INT DEFAULT 0 COMMENT '排序', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "INDEX idx_list (list_id), "
-                        + "INDEX idx_purchased (purchased)"
-                        + ");",
-
-                "CREATE TABLE IF NOT EXISTS follow_up ("
-                        + "id BIGINT AUTO_INCREMENT PRIMARY KEY, "
-                        + "family_id BIGINT NOT NULL COMMENT '家庭ID', "
-                        + "child_id BIGINT COMMENT '孩子ID', "
-                        + "teacher_id BIGINT COMMENT '规划师ID', "
-                        + "deficiency_id BIGINT COMMENT '缺乏项ID', "
-                        + "message_id BIGINT COMMENT '消息ID', "
-                        + "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态', "
-                        + "priority VARCHAR(10) DEFAULT 'medium' COMMENT '优先级', "
-                        + "description VARCHAR(500) COMMENT '描述', "
-                        + "parent_feedback TEXT COMMENT '家长反馈', "
-                        + "teacher_review VARCHAR(500) COMMENT '规划师点评', "
-                        + "due_date DATETIME COMMENT '截止日期', "
-                        + "completed_at DATETIME COMMENT '完成时间', "
-                        + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, "
-                        + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, "
-                        + "INDEX idx_family (family_id), "
-                        + "INDEX idx_teacher (teacher_id), "
-                        + "INDEX idx_status (status), "
-                        + "INDEX idx_due (due_date)"
-                        + ");"
-        };
-
-        for (String sql : ddl) {
-            try {
-                jdbcTemplate.execute(sql);
-            } catch (Exception e) {
-                log.warn("食品表DDL执行失败(可能已存在): {}", e.getMessage());
-            }
-        }
-
-        // 扩展 user_nutrition_profile(如果表不存在则跳过)
-        ensureColumn("user_nutrition_profile", "budget_monthly", "INT COMMENT '月食品预算(元)'");
-        ensureColumn("user_nutrition_profile", "family_taste_preferences", "TEXT COMMENT '家庭成员口味偏好JSON'");
-        ensureColumn("user_nutrition_profile", "cuisine_style", "VARCHAR(100) COMMENT '偏好菜系'");
-        ensureColumn("user_nutrition_profile", "meal_count", "INT DEFAULT 3 COMMENT '每日餐数'");
-        ensureColumn("user_nutrition_profile", "cooking_ability", "VARCHAR(20) DEFAULT 'simple' COMMENT '烹饪能力: simple/medium/advanced'");
-
-        log.info("食品相关表初始化完成");
-    }
-
-    private boolean tableExists(String tableName) {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?",
-                    Integer.class, tableName);
-            return count != null && count > 0;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    private boolean columnExists(String table, String column) {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?",
-                    Integer.class, table, column);
-            return count != null && count > 0;
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
-    private void ensureColumn(String table, String column, String definition) {
-        try {
-            jdbcTemplate.execute("ALTER TABLE " + table + " ADD COLUMN " + column + " " + definition);
-            log.info("已添加列 {}.{}", table, column);
-        } catch (Exception e) {
-            String msg = e.getMessage();
-            if (msg != null && (msg.contains("Duplicate") || msg.contains("already exists"))) {
-                log.info("列 {}.{} 已存在,跳过", table, column);
-            } else {
-                log.error("添加列 {}.{} 失败:{}", table, column, msg);
-                throw e;
-            }
-        }
-    }
-
-    /** 幂等创建任务模板包,返回 package id */
-    private Long ensureTemplatePackage(String name, String desc, int cycleDays, String category) {
-        Integer cnt = jdbcTemplate.queryForObject(
-            "SELECT COUNT(*) FROM task_template_packages WHERE name = ?", Integer.class, name);
-        if (cnt != null && cnt > 0) {
-            return jdbcTemplate.queryForObject(
-                "SELECT id FROM task_template_packages WHERE name = ? LIMIT 1", Long.class, name);
-        }
-        jdbcTemplate.update(
-            "INSERT INTO task_template_packages (creator_id, name, description, cycle_days, category, is_public, status, created_at, updated_at) " +
-            "VALUES (1, ?, ?, ?, ?, 1, 'published', NOW(), NOW())",
-            name, desc, cycleDays, category);
-        return jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-    }
-
-    /** 幂等写入模板包任务项 */
-    private void ensureTemplateItems(Long packageId, String[][] items) {
-        Integer cnt = jdbcTemplate.queryForObject(
-            "SELECT COUNT(*) FROM task_template_items WHERE package_id = ?", Integer.class, packageId);
-        if (cnt != null && cnt > 0) return;
-        for (String[] it : items) {
-            jdbcTemplate.update(
-                "INSERT INTO task_template_items (package_id, task_name, description, points, frequency, sort_order, created_at, updated_at) " +
-                "VALUES (?, ?, ?, ?, ?, 0, NOW(), NOW())",
-                packageId, it[0], it[1], Integer.valueOf(it[2]), it[3]);
-        }
-    }
-
-    /** 幂等写入方案生成规则 */
-    private void ensurePlanRule(String dimension, int scoreMin, int scoreMax, Long templateId, int priority) {
-        Integer cnt = jdbcTemplate.queryForObject(
-            "SELECT COUNT(*) FROM assessment_plan_rules WHERE dimension = ? AND score_min = ? AND score_max = ?",
-            Integer.class, dimension, scoreMin, scoreMax);
-        if (cnt != null && cnt > 0) return;
-        jdbcTemplate.update(
-            "INSERT INTO assessment_plan_rules (dimension, score_min, score_max, template_id, priority, is_active, created_at, updated_at) " +
-            "VALUES (?, ?, ?, ?, ?, 1, NOW(), NOW())",
-            dimension, scoreMin, scoreMax, templateId, priority);
-    }
-
-    private void insertProductSeed(String name, String desc, String type,
-                                   Integer price,
-                                   String domain, String memberEligible) {
-        Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM products WHERE name = ? AND product_type = ?", Integer.class, name, type);
-        if (count == null || count == 0) {
-            jdbcTemplate.update(
-                    "INSERT INTO products (name, description, price, product_type, vendor_id, vendor_name, status, domain, member_eligible, created_at, updated_at) " +
-                            "VALUES (?, ?, ?, ?, NULL, '平台官方', 'on_shelf', ?, ?, NOW(), NOW())",
-                    name, desc, price, type, domain, memberEligible);
-        }
-    }
-
-    private void insertActivitySeed(String title, String desc, String dimensionCode,
-                                    String activityType, String status,
-                                    String startTime, String endTime, String location,
-                                    int maxParticipants, int price, int memberPrice,
-                                    String dimensionWeights) {
-        Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM activities WHERE title = ?", Integer.class, title);
-        if (count == null || count == 0) {
-            jdbcTemplate.update(
-                    "INSERT INTO activities (title, description, dimension_code, dimension_weights, activity_type, status, " +
-                            "start_time, end_time, location, max_participants, current_participants, price, member_price, " +
-                            "require_registration, checkin_points, created_at, updated_at) " +
-                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, 1, 10, NOW(), NOW())",
-                    title, desc, dimensionCode, dimensionWeights, activityType, status,
-                    startTime, endTime, location, maxParticipants, price, memberPrice);
-        }
-    }
-
-    private void insertArticleSeed(String title, String summary, String contentType,
-                                   Long categoryId, String dimensionCode, String status,
-                                   String author, String articleType, int readTime, int wordCount,
-                                   String dimensionWeights) {
-        Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM articles WHERE title = ?", Integer.class, title);
-        if (count == null || count == 0) {
-            jdbcTemplate.update(
-                    "INSERT INTO articles (title, summary, content, content_type, category_id, " +
-                            "related_dimensions, dimension_weights, status, author, article_type, " +
-                            "read_time, word_count, is_featured, view_count, author_type, audit_status, " +
-                            "visibility, created_at, updated_at) " +
-                            "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, 0, 'admin', 'approved', 'public', NOW(), NOW())",
-                    title, summary, "(此处为示例文章正文内容,实际数据应在运营后台编辑发布。)",
-                    contentType, categoryId, "[\"" + dimensionCode + "\"]", dimensionWeights,
-                    status, author, articleType, readTime, wordCount);
-        }
-    }
-
-    private void insertContentSectionSeed(String pageKey, String sectionKey, String title,
-                                          String allowedRoles, int sortOrder) {
-        Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM content_sections WHERE page_key = ? AND section_key = ?",
-                Integer.class, pageKey, sectionKey);
-        if (count == null || count == 0) {
-            jdbcTemplate.update(
-                    "INSERT INTO content_sections (page_key, section_key, title, allowed_roles, sort_order, status, created_at, updated_at) " +
-                            "VALUES (?, ?, ?, ?, ?, 'active', NOW(), NOW())",
-                    pageKey, sectionKey, title, allowedRoles, sortOrder);
-        }
-    }
-
-    private void runLateMigrations() {
-        // 迁移51: 创建 member_subscription 表(家庭订阅记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS member_subscription (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "`level` VARCHAR(10) NOT NULL DEFAULT 'L1' COMMENT 'L1=一生一世, L2=久久一生', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT 'active/expired/cancelled', " +
-                    "start_time DATETIME DEFAULT NULL COMMENT '开始时间', " +
-                    "expire_time DATETIME DEFAULT NULL COMMENT '到期时间', " +
-                    "payment_id BIGINT DEFAULT NULL COMMENT '关联订单ID', " +
-                    "auto_renew TINYINT(1) DEFAULT 0 COMMENT '自动续费(L2)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_expire_time (expire_time)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭订阅记录'");
-            log.info("已创建member_subscription表");
-        } catch (Exception e) {
-            log.warn("创建member_subscription表失败: {}", e.getMessage());
-        }
-
-        // 迁移52: 创建 member_subscription_order 表(订阅订单)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS member_subscription_order (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "`level` VARCHAR(10) NOT NULL COMMENT 'L1/L2', " +
-                    "amount INT NOT NULL COMMENT '金额(分)', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/cancelled/refunded', " +
-                    "payment_type VARCHAR(20) DEFAULT NULL COMMENT '支付方式 wechat/alipay', " +
-                    "transaction_id VARCHAR(64) DEFAULT NULL COMMENT '微信支付订单号', " +
-                    "order_no VARCHAR(64) NOT NULL COMMENT '订单号', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "paid_at DATETIME DEFAULT NULL, " +
-                    "UNIQUE KEY uk_order_no (order_no), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅订单'");
-            log.info("已创建member_subscription_order表");
-        } catch (Exception e) {
-            log.warn("创建member_subscription_order表失败: {}", e.getMessage());
-        }
-
-        // 迁移53: 创建 subscription_benefit_log 表(权益使用日志)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS subscription_benefit_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "subscription_id BIGINT NOT NULL COMMENT '订阅ID', " +
-                    "benefit_code VARCHAR(50) NOT NULL COMMENT '权益代码', " +
-                    "used_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "detail TEXT COMMENT '使用详情(JSON)', " +
-                    "INDEX idx_subscription_id (subscription_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权益使用日志'");
-            log.info("已创建subscription_benefit_log表");
-        } catch (Exception e) {
-            log.warn("创建subscription_benefit_log表失败: {}", e.getMessage());
-        }
-
-        // 迁移54: 创建 promotion_tier 表(推广等级 R0-R4)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS promotion_tier (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "tier VARCHAR(20) NOT NULL DEFAULT 'R0' COMMENT 'R0利他者/R1传福人/R2聚能师/R3启慧者/R4传承者', " +
-                    "team_size_1st INT DEFAULT 0 COMMENT '一层团队人数', " +
-                    "team_size_2nd INT DEFAULT 0 COMMENT '二层团队人数', " +
-                    "team_size_3rd INT DEFAULT 0 COMMENT '三层团队人数', " +
-                    "total_team_size INT DEFAULT 0 COMMENT '三层累计总人数', " +
-                    "total_referral_earnings INT DEFAULT 0 COMMENT '累计推荐佣金(分)', " +
-                    "total_share_earnings INT DEFAULT 0 COMMENT '累计消费返利(分)', " +
-                    "promoted_at DATETIME DEFAULT NULL COMMENT '最近晋级时间', " +
-                    "last_change_at DATETIME DEFAULT NULL COMMENT '最后变更时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_user_id (user_id), " +
-                    "INDEX idx_tier (tier)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广等级'");
-            log.info("已创建promotion_tier表");
-        } catch (Exception e) {
-            log.warn("创建promotion_tier表失败: {}", e.getMessage());
-        }
-
-        // 迁移55: 创建 promotion_tier_change_log 表(推广等级变更记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS promotion_tier_change_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "old_tier VARCHAR(20) DEFAULT NULL COMMENT '变更前等级', " +
-                    "new_tier VARCHAR(20) NOT NULL COMMENT '变更后等级', " +
-                    "reason VARCHAR(50) DEFAULT NULL COMMENT 'qualify升级/demote降级/admin管理员调整', " +
-                    "changed_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广等级变更记录'");
-            log.info("已创建promotion_tier_change_log表");
-        } catch (Exception e) {
-            log.warn("创建promotion_tier_change_log表失败: {}", e.getMessage());
-        }
-
-        // 迁移56: 创建 referral_tree 表(推荐关系树三层)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS referral_tree (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "parent_id BIGINT NOT NULL COMMENT '推荐人ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '被推荐人ID', " +
-                    "level INT NOT NULL COMMENT '层级深度(1/2/3)', " +
-                    "path VARCHAR(255) DEFAULT NULL COMMENT 'materialized path如/1/2/3/', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_child_id (child_id), " +
-                    "INDEX idx_parent_id (parent_id), " +
-                    "INDEX idx_level (level)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐关系树'");
-            log.info("已创建referral_tree表");
-        } catch (Exception e) {
-            log.warn("创建referral_tree表失败: {}", e.getMessage());
-        }
-
-        // 迁移57: 创建 product_ppoint 表(产品P点配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_ppoint (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '产品ID', " +
-                    "ppoint INT NOT NULL DEFAULT 0 COMMENT 'P点值(平台利润分)', " +
-                    "start_date DATE DEFAULT NULL COMMENT '生效日期', " +
-                    "end_date DATE DEFAULT NULL COMMENT '失效日期', " +
-                    "created_by BIGINT DEFAULT NULL COMMENT '创建人', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product_id (product_id), " +
-                    "INDEX idx_dates (start_date, end_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品P点配置'");
-            log.info("已创建product_ppoint表");
-        } catch (Exception e) {
-            log.warn("创建product_ppoint表失败: {}", e.getMessage());
-        }
-
-        // 迁移58: 创建 assessment_products 表(测评商品扩展信息)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS assessment_products (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '关联products表', " +
-                    "assessment_type VARCHAR(20) NOT NULL COMMENT 'single=单包, bundle=套餐', " +
-                    "total_sessions INT NOT NULL DEFAULT 1 COMMENT '包含测评次数', " +
-                    "validity_days INT NOT NULL DEFAULT 365 COMMENT '有效期(天)', " +
-                    "guide_scope VARCHAR(50) DEFAULT 'all' COMMENT '规划师范围: all/assigned/auto', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product_id (product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评商品扩展信息'");
-            log.info("已创建assessment_products表");
-        } catch (Exception e) {
-            log.warn("创建assessment_products表失败: {}", e.getMessage());
-        }
-
-        // 迁移59: 创建 assessment_quotas 表(测评额度)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS assessment_quotas (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "quota_no VARCHAR(32) NOT NULL COMMENT '额度编号', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "child_id BIGINT COMMENT '指定孩子ID(NULL=不限)', " +
-                    "product_order_id BIGINT NOT NULL COMMENT '来源订单ID', " +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID', " +
-                    "product_name VARCHAR(100) NOT NULL COMMENT '商品名快照', " +
-                    "total_sessions INT NOT NULL DEFAULT 1 COMMENT '总次数', " +
-                    "remaining_sessions INT NOT NULL DEFAULT 1 COMMENT '剩余次数', " +
-                    "validity_start DATETIME NOT NULL COMMENT '有效期开始', " +
-                    "validity_end DATETIME NOT NULL COMMENT '有效期截止', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT 'active/expired/used_all/cancelled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family (family_id), " +
-                    "INDEX idx_order (product_order_id), " +
-                    "UNIQUE KEY uk_quota_no (quota_no)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评额度表'");
-            log.info("已创建assessment_quotas表");
-        } catch (Exception e) {
-            log.warn("创建assessment_quotas表失败: {}", e.getMessage());
-        }
-
-        // 迁移60: 创建 assessment_executions 表(测评执行记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS assessment_executions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "quota_id BIGINT NOT NULL COMMENT '关联额度ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '被测评孩子', " +
-                    "guide_id BIGINT COMMENT '执行规划师ID', " +
-                    "assessment_type VARCHAR(30) COMMENT '本次具体测评类型', " +
-                    "appointment_id BIGINT COMMENT '关联预约ID', " +
-                    "result_id BIGINT COMMENT '关联测评结果ID', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/in_progress/completed/cancelled', " +
-                    "scheduled_date DATETIME COMMENT '预约执行时间', " +
-                    "completed_at DATETIME COMMENT '实际完成时间', " +
-                    "notes VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_quota (quota_id), " +
-                    "INDEX idx_child (child_id), " +
-                    "INDEX idx_appointment (appointment_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评执行记录表'");
-            log.info("已创建assessment_executions表");
-        } catch (Exception e) {
-            log.warn("创建assessment_executions表失败: {}", e.getMessage());
-        }
-
-        // 迁移61: dan_assessment_results表添加source字段(报告来源)
-        ensureColumn("dan_assessment_results", "source",
-                "VARCHAR(20) DEFAULT 'planner_entry' COMMENT '报告来源: planner_entry/parent_upload/auto_fetch'");
-
-        // 迁移62: 创建 growth_guidances 表(结构化指导意见)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS growth_guidances (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "result_id BIGINT NOT NULL COMMENT '关联测评结果ID', " +
-                    "dimension VARCHAR(30) NOT NULL COMMENT '维度: attention/focus/memory/logic/emotion/general', " +
-                    "score INT COMMENT '该维度得分(0-100)', " +
-                    "suggestion TEXT NOT NULL COMMENT '建议内容', " +
-                    "priority INT DEFAULT 0 COMMENT '优先级(0=普通, 1=重要, 2=紧急)', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_result (result_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评指导意见(结构化)'");
-            log.info("已创建growth_guidances表");
-        } catch (Exception e) {
-            log.warn("创建growth_guidances表失败: {}", e.getMessage());
-        }
-
-        // 迁移63: 创建 assessment_plan_rules 表(方案生成规则)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS assessment_plan_rules (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "dimension VARCHAR(30) NOT NULL COMMENT '测评维度: attention/focus/memory/logic/emotion', " +
-                    "score_min INT NOT NULL COMMENT '分数下限(含)', " +
-                    "score_max INT NOT NULL COMMENT '分数上限(含)', " +
-                    "template_id BIGINT NOT NULL COMMENT '关联TaskTemplatePackage ID', " +
-                    "priority INT DEFAULT 0 COMMENT '优先级', " +
-                    "is_active TINYINT(1) DEFAULT 1 COMMENT '是否启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_dimension (dimension), " +
-                    "INDEX idx_score (score_min, score_max)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='方案生成规则'");
-            log.info("已创建assessment_plan_rules表");
-        } catch (Exception e) {
-            log.warn("创建assessment_plan_rules表失败: {}", e.getMessage());
-        }
-
-        // 迁移64: task_plan_instances表添加source字段(方案来源)
-        ensureColumn("task_plan_instances", "source",
-                "VARCHAR(20) DEFAULT 'manual' COMMENT '方案来源: manual/assessment/template'");
-
-        // 迁移65: task_plan_instances表添加source_result_id和remark字段
-        ensureColumn("task_plan_instances", "source_result_id",
-                "BIGINT COMMENT '关联测评结果ID(来源为assessment时)'");
-        ensureColumn("task_plan_instances", "remark",
-                "TEXT COMMENT '方案备注(含指导意见摘要)'");
-
-        // 迁移66: task_plan_instances表添加审核确认字段(阶段五)
-        ensureColumn("task_plan_instances", "reviewed_by",
-                "BIGINT COMMENT '审核人(规划师ID)'");
-        ensureColumn("task_plan_instances", "reviewed_at",
-                "DATETIME COMMENT '审核时间'");
-        ensureColumn("task_plan_instances", "review_comment",
-                "VARCHAR(500) COMMENT '审核意见'");
-        ensureColumn("task_plan_instances", "confirmed_by",
-                "BIGINT COMMENT '确认人(家长ID)'");
-        ensureColumn("task_plan_instances", "confirmed_at",
-                "DATETIME COMMENT '确认时间'");
-        ensureColumn("task_plan_instances", "activated_at",
-                "DATETIME COMMENT '激活时间'");
-
-        // 迁移67: family_access_logs 表(G7 familyId 越权访问日志,可选,用于安全审计)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_access_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '访问方用户ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '被访问的家庭ID', " +
-                    "request_uri VARCHAR(500) NOT NULL COMMENT '请求路径', " +
-                    "request_method VARCHAR(10) NOT NULL, " +
-                    "access_type VARCHAR(20) NOT NULL COMMENT 'check_type: query/path/body', " +
-                    "result VARCHAR(10) NOT NULL COMMENT 'allowed/denied/log_only', " +
-                    "client_ip VARCHAR(50), " +
-                    "user_agent VARCHAR(500), " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_time (user_id, created_at), " +
-                    "INDEX idx_family_time (family_id, created_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭访问安全日志'");
-            log.info("已创建family_access_logs表");
-        } catch (Exception e) {
-            log.warn("创建family_access_logs表失败: {}", e.getMessage());
-        }
-
-        // 迁移68: 创建 five_dimension_scores 表(G1 五维能量分数持久化,记录每次计算的维度分数快照)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS five_dimension_scores (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '成员ID(user或family_member)', " +
-                    "member_type VARCHAR(20) NOT NULL COMMENT '成员类型: user/member', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "dimension_code VARCHAR(20) NOT NULL COMMENT '维度编码: body/mind/wisdom/action/wealth', " +
-                    "score INT NOT NULL COMMENT '分数(0-100)', " +
-                    "assessed_at DATETIME NOT NULL COMMENT '评估时间', " +
-                    "source_type VARCHAR(50) COMMENT '来源类型: periodic/task/assessment/manual', " +
-                    "source_id BIGINT COMMENT '来源记录ID', " +
-                    "detail_json TEXT COMMENT '详细数据JSON', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_member_dim (member_id, member_type, dimension_code), " +
-                    "INDEX idx_family_time (family_id, assessed_at), " +
-                    "INDEX idx_source (source_type, source_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维能量分数历史记录'");
-            log.info("已创建five_dimension_scores表");
-            // 迁移69: 创建 promotion_tier_config 表(推广等级R0-R4阈值配置)
-            try {
-                jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS promotion_tier_config (" +
-                        "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                        "tier_code VARCHAR(10) NOT NULL UNIQUE COMMENT '等级编码: R0/R1/R2/R3/R4', " +
-                        "tier_name VARCHAR(50) NOT NULL COMMENT '等级名称', " +
-                        "min_team_size_1st INT NOT NULL DEFAULT 0 COMMENT '一级团队人数下限', " +
-                        "min_team_size_2nd INT NOT NULL DEFAULT 0 COMMENT '二级团队人数下限', " +
-                        "min_total_referral_earnings INT NOT NULL DEFAULT 0 COMMENT '累计推荐佣金下限(分)', " +
-                        "min_total_share_earnings INT NOT NULL DEFAULT 0 COMMENT '累计消费返利下限(分)', " +
-                        "commission_rate_l1 INT NOT NULL DEFAULT 0 COMMENT 'L1佣金比例(%)', " +
-                        "commission_rate_l2 INT NOT NULL DEFAULT 0 COMMENT 'L2佣金比例(%)', " +
-                        "sort_order INT NOT NULL DEFAULT 0 COMMENT '排序', " +
-                        "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                        "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                        ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广等级阈值配置'");
-                log.info("已创建promotion_tier_config表");
-            } catch (Exception e) {
-                log.warn("创建promotion_tier_config表失败: {}", e.getMessage());
-            }
-
-            try {
-                Integer configCount = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM promotion_tier_config", Integer.class);
-                if (configCount == null || configCount == 0) {
-                    jdbcTemplate.execute("INSERT INTO promotion_tier_config (tier_code, tier_name, min_team_size_1st, min_team_size_2nd, min_total_referral_earnings, min_total_share_earnings, commission_rate_l1, commission_rate_l2, sort_order) VALUES " +
-                            "('R0', '初始用户', 0, 0, 0, 0, 0, 0, 0), " +
-                            "('R1', '推广达人', 3, 0, 0, 0, 20, 5, 1), " +
-                            "('R2', '高级推广', 10, 5, 50000, 20000, 25, 8, 2), " +
-                            "('R3', '资深推广', 30, 20, 200000, 80000, 30, 10, 3), " +
-                            "('R4', '首席推广', 100, 50, 500000, 200000, 35, 15, 4)");
-                    log.info("R0-R4推广等级阈值种子数据已初始化");
-                }
-            } catch (Exception e) {
-                log.warn("初始化推广等级阈值种子数据失败: {}", e.getMessage());
-            }
-
-        } catch (Exception e) {
-            log.warn("创建five_dimension_scores表失败: {}", e.getMessage());
-        }
-
-        // 迁移70: package_orders表添加user_coupon_id列
-        try {
-            jdbcTemplate.execute("ALTER TABLE package_orders ADD COLUMN user_coupon_id BIGINT COMMENT '使用的用户优惠券ID'");
-            log.info("已添加user_coupon_id列到package_orders表");
-        } catch (Exception e) {
-            log.warn("添加user_coupon_id列失败(可能已存在): {}", e.getMessage());
-        }
-
-        // 迁移71: family_invitations表添加max_use_count和used_count列(G9 邀请次数控制)
-        ensureColumn("family_invitations", "max_use_count", "INT DEFAULT 1 COMMENT '最大使用次数'");
-        ensureColumn("family_invitations", "used_count", "INT DEFAULT 0 COMMENT '已使用次数'");
-
-        // 迁移72: 创建teacher_family_binding_requests表(G10 规划师绑定家庭审批)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS teacher_family_binding_requests (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "teacher_id BIGINT NOT NULL COMMENT '规划师用户ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "invitation_token VARCHAR(128) COMMENT '关联邀请码/令牌', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected/cancelled', " +
-                    "requested_at DATETIME COMMENT '申请时间', " +
-                    "decided_by BIGINT COMMENT '审批人用户ID', " +
-                    "decided_at DATETIME COMMENT '审批时间', " +
-                    "reject_reason VARCHAR(200) COMMENT '拒绝原因', " +
-                    "message VARCHAR(500) COMMENT '申请留言', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_teacher_family (teacher_id, family_id), " +
-                    "INDEX idx_family_status (family_id, status) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规划师绑定家庭申请表'");
-            log.info("已创建teacher_family_binding_requests表");
-        } catch (Exception e) {
-            log.warn("创建teacher_family_binding_requests表失败: {}", e.getMessage());
-        }
-
-        // 迁移73: 创建chat_conversations表(G14 Dify会话本地镜像)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS chat_conversations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL, " +
-                    "dify_conversation_id VARCHAR(64), " +
-                    "assistant_type VARCHAR(32) COMMENT 'family/nutrition/tongue', " +
-                    "title VARCHAR(200), " +
-                    "last_message_at DATETIME, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_dify_conv (dify_conversation_id), " +
-                    "INDEX idx_user (user_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建chat_conversations表");
-        } catch (Exception e) {
-            log.warn("创建chat_conversations表失败: {}", e.getMessage());
-        }
-
-        // 迁移74: 创建chat_messages表(G14 Dify会话本地镜像)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS chat_messages (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "conversation_id BIGINT NOT NULL, " +
-                    "dify_message_id VARCHAR(64), " +
-                    "role VARCHAR(20) NOT NULL COMMENT 'user/assistant', " +
-                    "content TEXT NOT NULL, " +
-                    "inputs_json TEXT, " +
-                    "metadata TEXT, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_conv (conversation_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建chat_messages表");
-        } catch (Exception e) {
-            log.warn("创建chat_messages表失败: {}", e.getMessage());
-        }
-
-        // 迁移75: 创建schema_versions表(G23 迁移版本追踪)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS schema_versions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "version_code VARCHAR(64) NOT NULL UNIQUE, " +
-                    "description VARCHAR(500), " +
-                    "checksum VARCHAR(64), " +
-                    "applied_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "applied_by VARCHAR(100) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='迁移版本追踪表'");
-            log.info("已创建schema_versions表");
-        } catch (Exception e) {
-            log.warn("创建schema_versions表失败: {}", e.getMessage());
-        }
-
-        // 迁移76: DanAssessmentResult添加structured_analysis字段(G3)
-        ensureColumn("dan_assessment_results", "structured_analysis", "TEXT COMMENT '结构化分析JSON'");
-
-
-        // 迁移77: 创建 pending_refund 表(待退款记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS pending_refund (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "withdrawal_request_id BIGINT COMMENT '提现申请ID', " +
-                    "amount INT NOT NULL COMMENT '退款金额(分)', " +
-                    "attempt_count INT DEFAULT 0 COMMENT '当前尝试次数', " +
-                    "max_attempts INT DEFAULT 10 COMMENT '最大重试次数', " +
-                    "next_retry_time DATETIME COMMENT '下次重试时间', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/processing/success/failed', " +
-                    "failure_reason VARCHAR(500) COMMENT '失败原因', " +
-                    "refunded_amount INT COMMENT '实际退款金额(分)', " +
-                    "refunded_at DATETIME COMMENT '退款时间', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_next_retry (next_retry_time), " +
-                    "INDEX idx_withdrawal_request (withdrawal_request_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='待退款记录表'");
-            log.info("已创建pending_refund表");
-        } catch (Exception e) {
-            log.warn("创建pending_refund表失败: {}", e.getMessage());
-        }
-
-        // 迁移78: product_orders添加consignee_id字段(OrderTimeoutCancelTask查询需要)
-        ensureColumn("product_orders", "consignee_id", "BIGINT COMMENT '收货人ID'");
-
-        // 迁移79: pending_refund添加order_type/order_no字段(商品退款走待退款队列)
-        ensureColumn("pending_refund", "order_type", "VARCHAR(20) DEFAULT 'withdrawal' COMMENT '退款类型: withdrawal/product'");
-        ensureColumn("pending_refund", "order_no", "VARCHAR(64) COMMENT '商品订单号'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE pending_refund ADD INDEX idx_order_type (order_type)");
-        } catch (Exception e) {
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE pending_refund ADD INDEX idx_order_no (order_no)");
-        } catch (Exception e) {
-        }
-
-        // 迁移80: dan_assessment_results添加dimension字段(区分mind/wisdom报告上传)
-        ensureColumn("dan_assessment_results", "dimension",
-                "VARCHAR(10) DEFAULT 'mind' COMMENT '报告维度: mind(心-A2)/wisdom(智-B4)'");
-        ensureColumn("dan_assessment_results", "report_file_id", "VARCHAR(100) COMMENT '上传文件媒资ID'");
-        ensureColumn("dan_assessment_results", "draft_status",
-                "VARCHAR(10) DEFAULT 'pending' COMMENT '草稿状态: pending(待确认)/confirmed(已确认)'");
-
-        // 迁移81: activities添加dimension_weights JSON列(五维权重百分比)
-        ensureColumn("activities", "dimension_weights",
-                "JSON DEFAULT NULL COMMENT '{\"body\":0,\"mind\":0,\"wisdom\":0,\"action\":0,\"wealth\":0}'");
-        ensureColumn("products", "dimension_weights",
-                "JSON DEFAULT NULL COMMENT '{\"body\":0,\"mind\":0,\"wisdom\":0,\"action\":0,\"wealth\":0}'");
-        ensureColumn("articles", "dimension_weights",
-                "JSON DEFAULT NULL COMMENT '{\"body\":0,\"mind\":0,\"wisdom\":0,\"action\":0,\"wealth\":0}'");
-
-        // 迁移82: 存量数据回填 — 根据dimension_code/domain/relatedDimensions初始化dimension_weights
-        try {
-            // 回填activities: 已有dimension_code的记录,设对应维度为100
-            int actCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM activities WHERE dimension_code IS NOT NULL AND dimension_code != '' AND dimension_weights IS NULL",
-                    Integer.class);
-            if (actCount > 0) {
-                jdbcTemplate.update(
-                        "UPDATE activities SET dimension_weights = " +
-                                "JSON_OBJECT(" +
-                                "  'body', IF(dimension_code='body',100,0)," +
-                                "  'mind', IF(dimension_code='mind',100,0)," +
-                                "  'wisdom', IF(dimension_code='wisdom',100,0)," +
-                                "  'action', IF(dimension_code='action',100,0)," +
-                                "  'wealth', IF(dimension_code='wealth',100,0)" +
-                                ") WHERE dimension_code IS NOT NULL AND dimension_code != '' AND dimension_weights IS NULL");
-                log.info("已回填{}条activities的dimension_weights", actCount);
-            }
-        } catch (Exception e) {
-            log.warn("回填activities.dimension_weights失败: {}", e.getMessage());
-        }
-
-        try {
-            // 回填products: 已有domain的记录,设对应维度为100
-            int prodCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM products WHERE domain IS NOT NULL AND domain != '' AND dimension_weights IS NULL",
-                    Integer.class);
-            if (prodCount > 0) {
-                jdbcTemplate.update(
-                        "UPDATE products SET dimension_weights = " +
-                                "JSON_OBJECT(" +
-                                "  'body', IF(domain='body',100,0)," +
-                                "  'mind', IF(domain='mind',100,0)," +
-                                "  'wisdom', IF(domain='wisdom',100,0)," +
-                                "  'action', IF(domain='action',100,0)," +
-                                "  'wealth', IF(domain='wealth',100,0)" +
-                                ") WHERE domain IS NOT NULL AND domain != '' AND dimension_weights IS NULL");
-                log.info("已回填{}条products的dimension_weights", prodCount);
-            }
-        } catch (Exception e) {
-            log.warn("回填products.dimension_weights失败: {}", e.getMessage());
-        }
-
-        try {
-            // 回填articles: 已有relatedDimensions的记录,尝试解析维度名并设权重
-            int artCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM articles WHERE related_dimensions IS NOT NULL AND related_dimensions != '' AND dimension_weights IS NULL",
-                    Integer.class);
-            if (artCount > 0) {
-                // 用MySQL函数解析relatedDimensions中的维度关键词
-                jdbcTemplate.update("UPDATE articles SET dimension_weights = JSON_OBJECT(" +
-                        "'body', IF(INSTR(COALESCE(related_dimensions,''),'body')>0 OR INSTR(COALESCE(related_dimensions,''),'身')>0, 100, 0)," +
-                        "'mind', IF(INSTR(COALESCE(related_dimensions,''),'mind')>0 OR INSTR(COALESCE(related_dimensions,''),'心')>0, 100, 0)," +
-                        "'wisdom', IF(INSTR(COALESCE(related_dimensions,''),'wisdom')>0 OR INSTR(COALESCE(related_dimensions,''),'智')>0, 100, 0)," +
-                        "'action', IF(INSTR(COALESCE(related_dimensions,''),'action')>0 OR INSTR(COALESCE(related_dimensions,''),'行')>0, 100, 0)," +
-                        "'wealth', IF(INSTR(COALESCE(related_dimensions,''),'wealth')>0 OR INSTR(COALESCE(related_dimensions,''),'富')>0, 100, 0)" +
-                        ") WHERE related_dimensions IS NOT NULL AND related_dimensions != '' AND dimension_weights IS NULL");
-                log.info("已回填{}条articles的dimension_weights", artCount);
-            }
-        } catch (Exception e) {
-            log.warn("回填articles.dimension_weights失败: {}", e.getMessage());
-        }
-
-        // 迁移83: 创建dimension_weights表(管理端保存维度权重使用)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS dimension_weights (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "target_type VARCHAR(20) NOT NULL COMMENT '目标类型: activity/product/article'," +
-                    "target_id BIGINT NOT NULL COMMENT '目标ID'," +
-                    "dimension VARCHAR(20) NOT NULL COMMENT '维度: body/mind/wisdom/action/wealth'," +
-                    "weight INT DEFAULT 0 COMMENT '权重百分比'," +
-                    "enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "INDEX idx_target (target_type, target_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='维度权重表'");
-            log.info("已创建dimension_weights表");
-        } catch (Exception e) {
-            log.warn("创建dimension_weights表失败: {}", e.getMessage());
-        }
-
-// 迁移84: cart表添加skuId和specOptionIds字段(支持SKU选择)
-        ensureColumn("cart", "sku_id", "BIGINT COMMENT '选中的SKU ID'");
-        ensureColumn("cart", "spec_option_ids", "VARCHAR(500) COMMENT '选中的规格选项IDs JSON'");
-
-        // 迁移86: product_orders表添加purchase_info字段(购买信息快照JSON,OrderTimeoutCancelTask查询需要)
-        ensureColumn("product_orders", "purchase_info", "TEXT COMMENT '购买信息JSON: {id_card, hand_signature, ...}'");
-
-        // 迁移87: articles表添加content_type/difficulty_level/dimension_ids/dimension_weights字段
-        ensureColumn("articles", "content_type", "VARCHAR(20) DEFAULT 'text' COMMENT '内容格式:text/html/markdown'");
-        ensureColumn("articles", "difficulty_level", "INT DEFAULT 0 COMMENT '难度等级:1-5'");
-        ensureColumn("articles", "dimension_ids", "VARCHAR(100) DEFAULT '' COMMENT '关联维度IDs JSON'");
-        ensureColumn("articles", "dimension_weights", "TEXT COMMENT '五维能量权重JSON'");
-
-        // 迁移88: activities表添加dimension_weights列(权重感知活动查询)
-        ensureColumn("activities", "dimension_weights", "TEXT COMMENT '五维能量权重JSON'");
-
-        // 迁移89: products表添加dimension_weights列(权重感知商品查询)
-        ensureColumn("products", "dimension_weights", "TEXT COMMENT '五维能量权重JSON'");
-
-        // 迁移85: 创建社交圈子表(珍珠图/圈子系统)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS social_circle (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '圈子名称', " +
-                    "type VARCHAR(50) NOT NULL COMMENT '类型: topic/activity/hobby/ability/product/health/provider', " +
-                    "match_source VARCHAR(50) NOT NULL COMMENT '匹配源', " +
-                    "source_id BIGINT COMMENT '匹配源ID', " +
-                    "member_count INT DEFAULT 0 COMMENT '成员数', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社交圈/珍珠'");
-            log.info("已创建social_circle表");
-        } catch (Exception e) { /* 表已存在忽略 */ }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS social_circle_member (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL, " +
-                    "member_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "member_type VARCHAR(20) NOT NULL COMMENT 'parent/child', " +
-                    "joined_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_circle_member (circle_id, member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子成员'");
-            log.info("已创建social_circle_member表");
-        } catch (Exception e) { /* 表已存在忽略 */ }
-
-        // 迁移96: 创建活动订单评价表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS review_orders (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_id BIGINT NOT NULL COMMENT '订单ID', " +
-                    "reviewer_id BIGINT NOT NULL COMMENT '评价人ID', " +
-                    "rating INT COMMENT '总体评分', " +
-                    "review_text TEXT COMMENT '评价内容', " +
-                    "review_at DATETIME COMMENT '评价时间', " +
-                    "organization_rating INT COMMENT '活动组织评分(0-5)', " +
-                    "content_rating INT COMMENT '活动内容评分(0-5)', " +
-                    "experience_rating INT COMMENT '活动体验评分(0-5)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_order_id (order_id), " +
-                    "INDEX idx_reviewer_id (reviewer_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动订单评价表'");
-            log.info("已创建review_orders表");
-        } catch (Exception e) {
-            log.error("迁移96 失败: " + e.getMessage());
-        }
-
-        // 迁移97: growth_task表扩展 — 支持AI_GENERATED类型 + 五维维度/来源会话字段
-        try {
-            jdbcTemplate.execute("ALTER TABLE growth_task MODIFY COLUMN type "
-                    + "VARCHAR(16) NOT NULL COMMENT 'DAILY/NEWBIE/AI_GENERATED'");
-            log.info("已扩展growth_task.type为支持AI_GENERATED");
-        } catch (Exception e) {
-            log.warn("扩展growth_task.type失败(可能已经扩展): " + e.getMessage());
-        }
-        ensureColumn("growth_task", "dimension", "VARCHAR(20) NULL COMMENT '五维维度(body/mind/wisdom/action/wealth)'");
-        ensureColumn("growth_task", "source_conversation_id", "VARCHAR(100) NULL COMMENT '来源AI会话ID'");
-        log.info("迁移97: growth_task 表扩展完成");
-
-        // 迁移98: health_gut_flora 表扩展 level 字段长度(支持 CLASS/ORDER/FAMILY)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora MODIFY COLUMN level VARCHAR(20) COMMENT '级别: CLASS/ORDER/FAMILY/GENUS/SPECIES'");
-            log.info("已扩展health_gut_flora.level字段长度");
-        } catch (Exception e) {
-            log.warn("扩展health_gut_flora.level失败: {}", e.getMessage());
-        }
-        log.info("迁移 98: health_gut_flora 表扩展完成");
-        
-        // 迁移 100: health_gut_flora 表扩展 population_level 和 detection_rate 字段长度(支持更长百分比)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora MODIFY COLUMN population_level VARCHAR(100) DEFAULT NULL COMMENT '处于人群%水平'");
-            log.info("已扩展 health_gut_flora.population_level 字段长度至 VARCHAR(100)");
-        } catch (Exception e) {
-            log.warn("扩展 health_gut_flora.population_level 失败:{}", e.getMessage());
-        }
-        
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora MODIFY COLUMN detection_rate VARCHAR(100) DEFAULT NULL COMMENT '%正常人有检出'");
-            log.info("已扩展 health_gut_flora.detection_rate 字段长度至 VARCHAR(100)");
-        } catch (Exception e) {
-            log.warn("扩展 health_gut_flora.detection_rate 失败:{}", e.getMessage());
-        }
-        log.info("迁移 100: health_gut_flora 表扩展完成");
-
-        // 迁移99: users.role 从 ENUM 改为 VARCHAR(20)(支持动态角色值)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN role VARCHAR(20) NOT NULL COMMENT '角色: parent/child/teacher'");
-            log.info("已修改users.role为VARCHAR(20)");
-        } catch (Exception e) {
-            log.warn("修改users.role失败(可能已修改): " + e.getMessage());
-        }
-
-        // 迁移100: assessment_appointments表添加assessor_id(测评师角色分离)
-        ensureColumn("assessment_appointments", "assessor_id",
-                "BIGINT COMMENT '测评师ID(供应商体系), 替代guideId语义'");
-        // 迁移100: dan_assessment_executions表添加appointment_id
-        ensureColumn("dan_assessment_executions", "appointment_id",
-                "BIGINT COMMENT '关联assessment_appointments.id'");
-        log.info("迁移100: 已添加assessor_id和appointment_id字段");
-
-        // 迁移101: 创建 micro_actions 表(12个预定义1秒微行动)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS micro_actions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "code VARCHAR(32) NOT NULL COMMENT '行动编码: DRINK_WATER, DEEP_BREATH, ...', " +
-                    "name VARCHAR(50) NOT NULL COMMENT '行动名称', " +
-                    "icon VARCHAR(10) COMMENT '图标emoji', " +
-                    "description VARCHAR(200) COMMENT '行动描述', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序号', " +
-                    "status TINYINT DEFAULT 1 COMMENT '状态: 1启用 0禁用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_code (code), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微行动定义(12个1秒健康行动)'");
-            log.info("已创建micro_actions表");
-
-            // 插入12个预定义微行动
-            jdbcTemplate.execute("INSERT IGNORE INTO micro_actions (code, name, icon, description, sort_order) VALUES " +
-                    "('DRINK_WATER', '喝一杯水', '☕️', '喝一杯温开水,补充水分', 1), " +
-                    "('DEEP_BREATH', '深呼吸3次', '🫁', '深吸慢呼3次,放松身心', 2), " +
-                    "('STRETCH', '站起来伸懒腰', '🧘', '站起来伸个懒腰,活动筋骨', 3), " +
-                    "('LOOK_FAR', '看远处10秒', '🌿', '看远处绿色植物10秒,缓解眼疲劳', 4), " +
-                    "('SMILE', '微笑一下', '😊', '对自己微笑,心情会变好', 5), " +
-                    "('NECK_ROLL', '转转头颈5圈', '🔄', '缓慢转动头颈5圈,放松颈椎', 6), " +
-                    "('FIST_RELAX', '握拳放松3次', '✊', '用力握拳3秒后放松,重复3次', 7), " +
-                    "('SIP_WATER', '喝口水润喉', '💧', '小口喝水润润喉咙', 8), " +
-                    "('BLINK', '眨眨眼5次', '👁️', '快速眨眼5次,湿润眼球', 9), " +
-                    "('ACUPRESSURE', '按揉合谷穴3下', '🖐️', '按揉虎口合谷穴3下,提神醒脑', 10), " +
-                    "('TIPTOE', '踮脚尖5次', '⬆️', '踮起脚尖再放下,重复5次', 11), " +
-                    "('SHRUG', '耸肩放松3次', '↕️', '耸肩至耳朵再放松,重复3次', 12)");
-            log.info("已初始化12个微行动");
-        } catch (Exception e) {
-            log.warn("创建micro_actions表或初始化数据失败: {}", e.getMessage());
-        }
-
-        // 迁移102: 创建 micro_action_records 表(微行动完成记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS micro_action_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "action_id BIGINT NOT NULL COMMENT '行动ID', " +
-                    "completed_date DATETIME NOT NULL COMMENT '完成日期', " +
-                    "earned_energy INT DEFAULT 1 COMMENT '获得能量值', " +
-                    "note VARCHAR(200) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_date (child_id, completed_date), " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微行动完成记录'");
-            log.info("已创建micro_action_records表");
-        } catch (Exception e) {
-            log.warn("创建micro_action_records表失败: {}", e.getMessage());
-        }
-
-        // 迁移103: 创建 daily_feedback 表(AI/预设每日健康反馈)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS daily_feedback (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "feedback_date DATETIME NOT NULL COMMENT '反馈日期', " +
-                    "feedback_type VARCHAR(20) DEFAULT 'daily' COMMENT '反馈类型: daily/weekly/milestone', " +
-                    "content VARCHAR(500) NOT NULL COMMENT 'AI生成的反馈文本', " +
-                    "milestone_event VARCHAR(100) COMMENT '关联的里程碑事件', " +
-                    "is_read TINYINT DEFAULT 0 COMMENT '是否已读: 0未读 1已读', " +
-                    "source VARCHAR(20) DEFAULT 'preset' COMMENT '来源: ai_generated / preset', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_date (child_id, feedback_date), " +
-                    "INDEX idx_feedback_type (feedback_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日健康反馈'");
-            log.info("已创建daily_feedback表");
-        } catch (Exception e) {
-            log.warn("创建daily_feedback表失败: {}", e.getMessage());
-        }
-
-        // 迁移104: 创建 health_alerts 表(健康行为智能预警)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_alerts (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "rule_code VARCHAR(10) NOT NULL COMMENT '规则编码: R001-R006', " +
-                    "alert_text VARCHAR(200) NOT NULL COMMENT '预警文案', " +
-                    "action_suggestion VARCHAR(200) COMMENT '行动建议', " +
-                    "severity VARCHAR(10) DEFAULT 'medium' COMMENT '严重程度: high/medium/low', " +
-                    "dismissed TINYINT DEFAULT 0 COMMENT '是否已关闭: 0未关闭 1已关闭', " +
-                    "dismissed_at DATETIME COMMENT '关闭时间', " +
-                    "alert_date DATETIME NOT NULL COMMENT '预警日期', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_date (child_id, alert_date), " +
-                    "INDEX idx_rule (rule_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康预警记录'");
-            log.info("已创建health_alerts表");
-        } catch (Exception e) {
-            log.warn("创建health_alerts表失败: {}", e.getMessage());
-        }
-
-        // 迁移105: 创建 health_level 表(身份重塑等级定义)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_level (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "level_num INT NOT NULL COMMENT '等级编号 1-5', " +
-                    "title VARCHAR(50) NOT NULL COMMENT '称号', " +
-                    "badge_icon VARCHAR(20) COMMENT '徽章图标', " +
-                    "min_score INT DEFAULT 0 COMMENT '所需最低健康积分', " +
-                    "max_score INT DEFAULT 99999 COMMENT '最高积分上限'" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康等级定义'");
-            log.info("已创建health_level表");
-        } catch (Exception e) {
-            log.warn("创建health_level表失败: {}", e.getMessage());
-        }
-
-        // 迁移106: 创建 health_timeline_event 表(健康故事时间线)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_timeline_event (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "event_type VARCHAR(30) NOT NULL COMMENT '事件类型: streak_7/level_2/first_report', " +
-                    "event_text VARCHAR(200) NOT NULL COMMENT '事件描述', " +
-                    "ref_id VARCHAR(50) COMMENT '关联ID', " +
-                    "event_date DATETIME NOT NULL COMMENT '事件日期', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_date (child_id, event_date), " +
-                    "INDEX idx_event_type (event_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康时间线事件'");
-            log.info("已创建health_timeline_event表");
-        } catch (Exception e) {
-            log.warn("创建health_timeline_event表失败: {}", e.getMessage());
-        }
-
-        // 迁移107: 创建 family_challenge 表(P2-2家庭挑战)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_challenge (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "challenge_type VARCHAR(50) NOT NULL COMMENT 'full_checkin/sports/health_week', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '挑战标题', " +
-                    "description TEXT COMMENT '挑战描述', " +
-                    "duration_days INT DEFAULT 7 COMMENT '持续天数', " +
-                    "reward_points INT DEFAULT 0 COMMENT '奖励积分', " +
-                    "reward_badge VARCHAR(100) COMMENT '奖励徽章', " +
-                    "start_date DATE COMMENT '开始日期', " +
-                    "end_date DATE COMMENT '结束日期', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT 'active/completed/cancelled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_family_id (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战'");
-            log.info("已创建family_challenge表");
-        } catch (Exception e) {
-            log.warn("创建family_challenge表失败: {}", e.getMessage());
-        }
-
-        // 迁移108: 创建 family_challenge_progress 表(P2-2挑战进度)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_challenge_progress (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "challenge_id BIGINT NOT NULL COMMENT '挑战ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "progress_value INT DEFAULT 0 COMMENT '进度值', " +
-                    "completed TINYINT(1) DEFAULT 0 COMMENT '是否完成', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                    "INDEX idx_challenge_id (challenge_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战进度'");
-            log.info("已创建family_challenge_progress表");
-        } catch (Exception e) {
-            log.warn("创建family_challenge_progress表失败: {}", e.getMessage());
-        }
-
-        // 迁移109: 创建 health_interaction 表(P2-2点赞记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_interaction (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "from_user_id BIGINT NOT NULL COMMENT '点赞用户ID', " +
-                    "to_user_id BIGINT NOT NULL COMMENT '被赞用户ID', " +
-                    "action_type VARCHAR(50) NOT NULL COMMENT '行为类型', " +
-                    "action_id BIGINT COMMENT '关联行为记录ID', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_family_action (family_id, action_type, action_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康互动记录(点赞)'");
-            log.info("已创建health_interaction表");
-        } catch (Exception e) {
-            log.warn("创建health_interaction表失败: {}", e.getMessage());
-        }
-
-        // 迁移110: 创建 health_circle 表(P3 健康圈)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_circle (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '圈名称', " +
-                    "description VARCHAR(500) COMMENT '圈描述', " +
-                    "creator_family_id BIGINT COMMENT '创建家庭ID', " +
-                    "invite_code VARCHAR(32) COMMENT '邀请码', " +
-                    "member_limit INT DEFAULT 50 COMMENT '成员上限', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/closed', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_invite_code (invite_code), " +
-                    "INDEX idx_creator (creator_family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康圈'");
-            log.info("已创建health_circle表");
-        } catch (Exception e) {
-            log.warn("创建health_circle表失败: {}", e.getMessage());
-        }
-
-        // 迁移111: 创建 health_circle_member 表(P3 健康圈成员)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_circle_member (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL COMMENT '圈ID', " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "role VARCHAR(20) DEFAULT 'member' COMMENT '角色 member/admin', " +
-                    "joined_at DATETIME COMMENT '加入时间', " +
-                    "left_at DATETIME COMMENT '退出时间', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/inactive', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_circle_id (circle_id), " +
-                    "INDEX idx_family_id (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康圈成员'");
-            log.info("已创建health_circle_member表");
-        } catch (Exception e) {
-            log.warn("创建health_circle_member表失败: {}", e.getMessage());
-        }
-
-        // 迁移112: 创建 circle_challenge 表(P3 圈挑战)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS circle_challenge (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL COMMENT '圈ID', " +
-                    "challenge_type VARCHAR(50) NOT NULL COMMENT '挑战类型 checkin/step/meditation', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '挑战标题', " +
-                    "description VARCHAR(500) COMMENT '挑战描述', " +
-                    "duration_days INT DEFAULT 7 COMMENT '持续天数', " +
-                    "period VARCHAR(20) DEFAULT 'weekly' COMMENT '周期 weekly/monthly', " +
-                    "start_date DATETIME COMMENT '开始日期', " +
-                    "end_date DATETIME COMMENT '结束日期', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/completed/cancelled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_circle_id (circle_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈挑战'");
-            log.info("已创建circle_challenge表");
-        } catch (Exception e) {
-            log.warn("创建circle_challenge表失败: {}", e.getMessage());
-        }
-
-        // 迁移113: 创建 family_commission 表(P2 推广佣金)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_commission (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "promoter_family_id BIGINT NOT NULL COMMENT '推广方家庭ID', " +
-                    "buyer_family_id BIGINT NOT NULL COMMENT '购买方家庭ID', " +
-                    "order_id BIGINT COMMENT '关联订单ID', " +
-                    "amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '订单金额', " +
-                    "commission_rate DECIMAL(5,2) DEFAULT 10.00 COMMENT '佣金比例%', " +
-                    "commission_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '佣金金额', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/paid/cancelled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "paid_at DATETIME COMMENT '支付时间', " +
-                    "INDEX idx_promoter (promoter_family_id), " +
-                    "INDEX idx_buyer (buyer_family_id), " +
-                    "INDEX idx_order (order_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭推广佣金记录'");
-            log.info("已创建family_commission表");
-        } catch (Exception e) {
-            log.warn("创建family_commission表失败: {}", e.getMessage());
-        }
-
-        // 迁移114: 创建 promotion_binding 表(P2 推广绑定)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS promotion_binding (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "promoter_family_id BIGINT NOT NULL COMMENT '推广方家庭ID', " +
-                    "invitee_family_id BIGINT NOT NULL COMMENT '被邀请方家庭ID', " +
-                    "invite_code VARCHAR(32) COMMENT '使用的邀请码', " +
-                    "binding_type VARCHAR(20) DEFAULT 'direct' COMMENT 'direct/indirect', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT 'active/inactive', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "UNIQUE KEY uk_promoter_invitee (promoter_family_id, invitee_family_id), " +
-                    "INDEX idx_promoter (promoter_family_id), " +
-                    "INDEX idx_invitee (invitee_family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广绑定关系'");
-            log.info("已创建promotion_binding表");
-        } catch (Exception e) {
-            log.warn("创建promotion_binding表失败: {}", e.getMessage());
-        }
-
-        // 迁移115: 创建 activity_feedback 表(活动评价功能)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS activity_feedback (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "activity_id BIGINT NOT NULL COMMENT '活动ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "child_id BIGINT COMMENT '孩子ID', " +
-                    "ratings TEXT COMMENT '评分JSON: {\"组织形式\":5,\"会场气氛\":4}', " +
-                    "comment TEXT COMMENT '文字评价', " +
-                    "status TINYINT DEFAULT 0 COMMENT '状态: 0=待审核 1=已发布', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_activity_id (activity_id), " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_child_id (child_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动评价表'");
-            log.info("已创建activity_feedback表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移115b: activity表添加feedback_dimensions字段
-        ensureColumn("activities", "feedback_dimensions", "TEXT COMMENT '评价维度列表JSON: [\"组织形式\",\"会场气氛\",\"主持人\",\"专家\"]'");
-
-        // 迁移116: growth_records表添加family_member_id和family_member_age列(修复/record/list 500错误)
-        ensureColumn("growth_records", "family_member_id", "BIGINT COMMENT '关联家庭成员ID'");
-        ensureColumn("growth_records", "family_member_age", "INT COMMENT '成员年龄快照'");
-
-        // 迁移117: 创建 emotion_checkin 表情绪打卡表(Fix 心理与情绪模块 500 错误)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS emotion_checkin (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "mood_weather VARCHAR(50) COMMENT '心情晴雨表: sunny/cloudy/rainy/stormy', " +
-                    "emotion_tags VARCHAR(200) COMMENT '情绪标签(逗号分隔)', " +
-                    "photo_url VARCHAR(500) COMMENT '配图URL', " +
-                    "note TEXT COMMENT '文字备注', " +
-                    "energy_awarded INT DEFAULT 0 COMMENT '奖励能量值', " +
-                    "checkin_date DATE COMMENT '打卡日期', " +
-                    "mood_score INT COMMENT '心情分数(1-10)', " +
-                    "emotion_type VARCHAR(50) COMMENT '情绪类型', " +
-                    "stress_level INT COMMENT '压力等级(1-10)', " +
-                    "arousal_level INT COMMENT '激活水平(1-10)', " +
-                    "energy_level INT COMMENT '精力水平(1-10)', " +
-                    "sleep_hours DECIMAL(4,1) COMMENT '睡眠时长', " +
-                    "sleep_quality INT COMMENT '睡眠质量(1-10)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_child_date (child_id, checkin_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪打卡记录'");
-            log.info("已创建emotion_checkin表");
-        } catch (Exception e) {
-            log.warn("创建emotion_checkin表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移118: 创建 emotion_alert 表情绪告警表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS emotion_alert (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "child_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "alert_type VARCHAR(50) NOT NULL COMMENT '告警类型: consecutive_low_mood/crisis_keyword/sharp_decline', " +
-                    "severity VARCHAR(20) NOT NULL DEFAULT 'low' COMMENT '严重级别: low/medium/high', " +
-                    "title VARCHAR(200) COMMENT '告警标题', " +
-                    "message TEXT COMMENT '告警具体描述', " +
-                    "related_checkin_id BIGINT COMMENT '关联情绪打卡ID', " +
-                    "resolved TINYINT(1) DEFAULT 0 COMMENT '是否已处理', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "resolved_at DATETIME COMMENT '处理时间', " +
-                    "INDEX idx_child (child_id), " +
-                    "INDEX idx_alert_type (alert_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪告警'");
-            log.info("已创建emotion_alert表");
-        } catch (Exception e) {
-            log.warn("创建emotion_alert表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移119: 创建 membership_levels 表(会员等级配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS membership_levels (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "level_code VARCHAR(50) NOT NULL COMMENT '等级编码: FREE/PROFESSIONAL/ENTERPRISE', " +
-                    "level_name VARCHAR(100) NOT NULL COMMENT '等级名称', " +
-                    "level_desc TEXT COMMENT '等级描述', " +
-                    "price_monthly INT COMMENT '月费(分)', " +
-                    "price_quarterly INT COMMENT '季费(分)', " +
-                    "price_yearly INT COMMENT '年费(分)', " +
-                    "features TEXT COMMENT '功能权限列表(JSON)', " +
-                    "max_children INT DEFAULT 0 COMMENT '可添加孩子数量', " +
-                    "max_tasks_per_day INT DEFAULT 0 COMMENT '每日任务上限', " +
-                    "ai_review_enabled TINYINT(1) DEFAULT 0 COMMENT 'AI审核功能', " +
-                    "priority_support TINYINT(1) DEFAULT 0 COMMENT '优先客服', " +
-                    "teacher_consultation TINYINT(1) DEFAULT 0 COMMENT '老师咨询', " +
-                    "level_order INT DEFAULT 1 COMMENT '级别数字(越小级别越低)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_level_code (level_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员等级配置'");
-            log.info("已创建membership_levels表");
-        } catch (Exception e) {
-            log.warn("创建membership_levels表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移120: 插入 membership_levels 种子数据
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_levels (level_code, level_name, level_desc, price_monthly, price_quarterly, price_yearly, max_children, max_tasks_per_day, ai_review_enabled, priority_support, teacher_consultation) VALUES " +
-                    "('FREE', '免费会员', '基础免费功能', 0, 0, 0, 2, 5, 0, 0, 0), " +
-                    "('FAMILY', '家庭会员', '家庭会员全部功能', 13140, 32850, 131400, 6, 20, 1, 1, 1), " +
-                    "('PROVIDER', '标准会员', '标准会员服务', 13140, 32850, 131400, 10, 50, 1, 1, 1)");
-            log.info("已插入membership_levels种子数据");
-        } catch (Exception e) {
-            log.warn("插入membership_levels种子数据可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移121: 创建 family_memberships 表(家庭会员订阅记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_memberships (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "level_code VARCHAR(50) NOT NULL DEFAULT 'FREE' COMMENT '会员等级编码', " +
-                    "start_date DATETIME COMMENT '开始时间', " +
-                    "end_date DATETIME COMMENT '结束时间', " +
-                    "payment_method VARCHAR(50) COMMENT '支付方式: wechat/alipay/card', " +
-                    "payment_status VARCHAR(20) DEFAULT 'pending' COMMENT '支付状态: pending/paid/expired/refunded', " +
-                    "order_no VARCHAR(100) COMMENT '订单号', " +
-                    "transaction_id VARCHAR(200) COMMENT '交易流水号', " +
-                    "amount INT COMMENT '支付金额(分)', " +
-                    "auto_renew TINYINT(1) DEFAULT 0 COMMENT '自动续费', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_end_date (end_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭会员订阅'");
-            log.info("已创建family_memberships表");
-        } catch (Exception e) {
-            log.warn("创建family_memberships表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移121: 创建 share_events 表(分享事件记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS share_events (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '分享用户ID', " +
-                    "target_type VARCHAR(50) NOT NULL COMMENT '分享目标类型: article/growth/product', " +
-                    "target_id BIGINT NOT NULL COMMENT '分享目标ID', " +
-                    "share_channel VARCHAR(50) COMMENT '分享渠道: wechat/timeline/qq/url', " +
-                    "share_title VARCHAR(200) COMMENT '分享标题', " +
-                    "share_url VARCHAR(500) COMMENT '分享URL', " +
-                    "click_count INT DEFAULT 0 COMMENT '点击次数', " +
-                    "read_count INT DEFAULT 0 COMMENT '阅读次数', " +
-                    "reward_points INT DEFAULT 0 COMMENT '奖励积分', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/expired', " +
-                    "expires_at DATETIME COMMENT '过期时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_target (target_type, target_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享事件'");
-            log.info("已创建share_events表");
-        } catch (Exception e) {
-            log.warn("创建share_events表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移122: 创建 share_reads 表(分享阅读记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS share_reads (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "share_event_id BIGINT NOT NULL COMMENT '分享事件ID', " +
-                    "reader_id BIGINT COMMENT '阅读者用户ID', " +
-                    "reader_ip VARCHAR(50) COMMENT '阅读者IP', " +
-                    "read_duration INT COMMENT '阅读时长(秒)', " +
-                    "read_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '阅读时间', " +
-                    "INDEX idx_share_event (share_event_id), " +
-                    "INDEX idx_reader (reader_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享阅读记录'");
-            log.info("已创建share_reads表");
-        } catch (Exception e) {
-            log.warn("创建share_reads表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移123: 创建 food_recommend_idx 表(饮食推荐指数)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS food_recommend_idx (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "food_id BIGINT NOT NULL COMMENT '食材ID', " +
-                    "food_name VARCHAR(100) COMMENT '食材名称', " +
-                    "index_score INT COMMENT '推荐指数(0-100)', " +
-                    "health_report_id BIGINT COMMENT '关联健康报告ID', " +
-                    "calculated_at DATETIME COMMENT '计算时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_food (food_id), " +
-                    "INDEX idx_report (health_report_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食推荐指数'");
-            log.info("已创建food_recommend_idx表");
-        } catch (Exception e) {
-            log.warn("创建food_recommend_idx表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移124: 创建 points_exchange_products 表(积分兑换商品)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS points_exchange_products (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(200) NOT NULL COMMENT '商品名称', " +
-                    "description TEXT COMMENT '商品描述', " +
-                    "cover_image VARCHAR(500) COMMENT '封面图片', " +
-                    "points_price INT NOT NULL COMMENT '积分价格', " +
-                    "stock INT DEFAULT 0 COMMENT '库存', " +
-                    "product_type VARCHAR(50) COMMENT '商品类型', " +
-                    "category VARCHAR(50) COMMENT '分类', " +
-                    "expiry_days INT COMMENT '有效期(天)', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/disabled', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_category (category)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换商品'");
-            log.info("已创建points_exchange_products表");
-        } catch (Exception e) {
-            log.warn("创建points_exchange_products表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移125: 创建 points_exchange_records 表(积分兑换记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS points_exchange_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID', " +
-                    "child_id BIGINT COMMENT '孩子ID', " +
-                    "family_member_id BIGINT COMMENT '家庭成员ID', " +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID', " +
-                    "product_name VARCHAR(200) COMMENT '商品名称快照', " +
-                    "points_cost INT NOT NULL COMMENT '消耗积分', " +
-                    "quantity INT DEFAULT 1 COMMENT '数量', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/cancelled', " +
-                    "redeem_code VARCHAR(100) COMMENT '兑换码', " +
-                    "expired_at DATETIME COMMENT '过期时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_product (product_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换记录'");
-            log.info("已创建points_exchange_records表");
-        } catch (Exception e) {
-            log.warn("创建points_exchange_records表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移126: emotion_checkin表修复列类型与添加新列
-        ensureColumn("emotion_checkin", "mood_weather", "VARCHAR(20) DEFAULT NULL COMMENT '心情天气: sunny/cloudy/rainy/stormy'");
-        ensureColumn("emotion_checkin", "emotion_tags", "VARCHAR(200) DEFAULT NULL COMMENT '情绪标签,逗号分隔'");
-        ensureColumn("emotion_checkin", "energy_awarded", "INT DEFAULT 0 COMMENT '发放能量值'");
-        ensureColumn("emotion_checkin", "mood_score", "INT DEFAULT NULL COMMENT '心情分数(0-100)'");
-        ensureColumn("emotion_checkin", "stress_level", "INT DEFAULT NULL COMMENT '压力等级(1-5)'");
-        ensureColumn("emotion_checkin", "arousal_level", "INT DEFAULT NULL COMMENT '唤醒等级(1-5)'");
-        ensureColumn("emotion_checkin", "sleep_hours", "DECIMAL(4,1) DEFAULT NULL COMMENT '睡眠时长(小时)'");
-        ensureColumn("emotion_checkin", "sleep_quality", "VARCHAR(20) DEFAULT NULL COMMENT '睡眠质量: good/fair/poor'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin MODIFY COLUMN user_id BIGINT NULL COMMENT '用户ID(旧字段,可为空)'");
-            log.info("已修改emotion_checkin.user_id为可空");
-        } catch (Exception e) {
-            log.warn("修改emotion_checkin.user_id可能已处理: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE emotion_checkin MODIFY COLUMN emotion_type VARCHAR(50) DEFAULT 'custom' COMMENT '情绪类型'");
-            log.info("已修改emotion_checkin.emotion_type为VARCHAR");
-} catch (Exception e) {
-            log.warn("修改emotion_checkin.emotion_type可能已处理: {}", e.getMessage());
-        }
-
-        ensureColumn("family_fortune", "fortune_level_text", "VARCHAR(50) DEFAULT NULL COMMENT '运势等级文字'");
-        ensureColumn("family_fortune", "fortune_description", "VARCHAR(500) DEFAULT NULL COMMENT '运势描述'");
-        ensureColumn("family_fortune", "mood_emoji", "VARCHAR(20) DEFAULT NULL COMMENT '心情表情'");
-        ensureColumn("family_fortune", "mood_text", "VARCHAR(100) DEFAULT NULL COMMENT '心情描述文字'");
-        ensureColumn("family_fortune", "weekly_tip", "VARCHAR(500) DEFAULT NULL COMMENT '本周建议'");
-
-        // 迁移129: membership_levels表添加price_quarterly列
-        ensureColumn("membership_levels", "price_quarterly", "DECIMAL(10,2) DEFAULT NULL COMMENT '季度价格'");
-
-        // 迁移130: share_events表添加缺失列
-        ensureColumn("share_events", "target_type", "VARCHAR(20) DEFAULT NULL COMMENT '分享目标类型'");
-        ensureColumn("share_events", "share_channel", "VARCHAR(20) DEFAULT NULL COMMENT '分享渠道'");
-        ensureColumn("share_events", "share_title", "VARCHAR(200) DEFAULT NULL COMMENT '分享标题'");
-        ensureColumn("share_events", "share_url", "VARCHAR(500) DEFAULT NULL COMMENT '分享URL'");
-        ensureColumn("share_events", "read_count", "INT DEFAULT 0 COMMENT '阅读次数'");
-        ensureColumn("share_events", "reward_points", "INT DEFAULT 0 COMMENT '奖励积分'");
-        ensureColumn("share_events", "status", "VARCHAR(20) DEFAULT 'active' COMMENT '状态'");
-        ensureColumn("share_events", "expires_at", "DATETIME DEFAULT NULL COMMENT '过期时间'");
-        ensureColumn("share_events", "updated_at", "DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'");
-
-        // 迁移131: share_reads表添加缺失列
-        ensureColumn("share_reads", "read_duration", "INT DEFAULT NULL COMMENT '阅读时长(秒)'");
-        ensureColumn("share_reads", "read_at", "DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '阅读时间'");
-
-        // 迁移132: points_exchange_records表确保family_member_id列
-        ensureColumn("points_exchange_records", "family_member_id", "BIGINT COMMENT '家庭成员ID'");
-
-        // 迁移133: products表列对齐 — rename min_quantity→purchase_count_threshold, add missing columns
-        if (columnExists("products", "min_quantity")) {
-            try {
-                jdbcTemplate.execute("ALTER TABLE products CHANGE COLUMN min_quantity purchase_count_threshold INT DEFAULT 0 COMMENT '最小购买数量限制'");
-                log.info("已重命名products.min_quantity→purchase_count_threshold");
-            } catch (Exception e) {
-                log.warn("重命名products列失败(可能已处理): {}", e.getMessage());
-            }
-        }
-
-        // 迁移134: products表添加sort_order列(商品按排序字段排序展示)
-        ensureColumn("products", "sort_order", "INT DEFAULT 0 COMMENT '排序(值越小越靠前)'");
-        ensureColumn("products", "recommendation_tags", "VARCHAR(500) DEFAULT NULL COMMENT '推荐标签'");
-        ensureColumn("products", "is_recommended", "TINYINT(1) DEFAULT 0 COMMENT '是否推荐商品 0否 1是'");
-        ensureColumn("products", "repurchase_interval_days", "INT DEFAULT 30 COMMENT '复购间隔天数'");
-
-        // 迁移134: 创建 category_ppoint 表(品类P点比例配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS category_ppoint (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "category_id BIGINT NOT NULL COMMENT '商品类目ID', " +
-                    "ratio INT DEFAULT 0 COMMENT 'P点比例(千分比)', " +
-                    "start_date DATETIME COMMENT '生效日期', " +
-                    "end_date DATETIME COMMENT '失效日期(null=永不过期)', " +
-                    "created_by BIGINT COMMENT '创建人', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_category_id (category_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='品类P点比例配置'");
-            log.info("已创建category_ppoint表");
-        } catch (Exception e) {
-            log.warn("创建category_ppoint表失败: {}", e.getMessage());
-        }
-
-        // 迁移135: 创建 commission_dist_log 表(P点分润记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS commission_dist_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "buyer_id BIGINT NOT NULL COMMENT '买家用户ID', " +
-                    "order_id BIGINT COMMENT '订单ID', " +
-                    "product_id BIGINT COMMENT '商品ID', " +
-                    "source_ppoint INT DEFAULT 0 COMMENT '本次产生的原始P点数量', " +
-                    "level1_user_id BIGINT COMMENT '一级推荐人用户ID', " +
-                    "level1_ppoint INT DEFAULT 0 COMMENT '一级推荐人获得P点', " +
-                    "level1_wealth_percent INT DEFAULT 0 COMMENT '一级推荐人当时财富等级(profitSharePercent)', " +
-                    "level2_user_id BIGINT COMMENT '二级推荐人用户ID', " +
-                    "level2_ppoint INT DEFAULT 0 COMMENT '二级推荐人获得P点', " +
-                    "level2_wealth_percent INT DEFAULT 0 COMMENT '二级推荐人当时财富等级(profitSharePercent)', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/failed', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                    "INDEX idx_buyer (buyer_id), " +
-                    "INDEX idx_order (order_id), " +
-                    "INDEX idx_level1 (level1_user_id), " +
-                    "INDEX idx_level2 (level2_user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='P点分润记录'");
-            log.info("已创建commission_dist_log表");
-        } catch (Exception e) {
-            log.warn("创建commission_dist_log表失败: {}", e.getMessage());
-        }
-
-        // 迁移136: payment_orders表添加period列(会员订阅周期)
-        ensureColumn("payment_orders", "period", "VARCHAR(20) DEFAULT 'yearly' COMMENT '订阅周期: monthly/quarterly/yearly'");
-
-        // 迁移137: 扩大payment_orders.payment_type列长度(原列可能为VARCHAR(5),存不下"yearly")
-        try {
-            jdbcTemplate.execute("ALTER TABLE payment_orders MODIFY COLUMN payment_type VARCHAR(20) DEFAULT 'yearly' COMMENT '支付类型: yearly/monthly/trial'");
-            log.info("已修改payment_orders.payment_type列长度为VARCHAR(20)");
-        } catch (Exception e) {
-            log.warn("修改payment_orders.payment_type列长度失败: {}", e.getMessage());
-        }
-
-        // 迁移138: tasks表添加dimension_code和dimension_weights列(原migration102内从未被调用)
-        ensureColumn("tasks", "dimension_code", "VARCHAR(20) COMMENT '五维维度: body/mind/wisdom/action/wealth'");
-        ensureColumn("tasks", "dimension_weights", "JSON COMMENT '五维权重: {\"body\":0,\"mind\":0,\"wisdom\":0,\"action\":0,\"wealth\":0}'");
-
-        // 迁移139: products表添加family_scope列(推荐系统-家庭消费去重,原migration102内从未被调用)
-        ensureColumn("products", "family_scope", "TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员消费过即排除, 0=仅按个人消费排除'");
-
-        // 迁移140: activities表添加family_scope列(推荐系统-家庭参与去重,原migration102内从未被调用)
-        ensureColumn("activities", "family_scope", "TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员参与过即排除, 0=仅按个人参与排除'");
-
-        // 迁移141: 修正五维权重维度code体系(后台DimensionWeightPicker曾用mind=智/heart=心,标准体系为wisdom=智/mind=心)
-        // 旧体系写入的数据导致小程序端按wisdom/mind查询JSON_EXTRACT匹配不到,新活动显示不出来
-        try {
-            // 1. dimension_weights 表:仅处理含 heart 的目标(旧体系写入的),mind(智)→wisdom,heart(心)→mind
-            int dwHeartCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM dimension_weights WHERE dimension = 'heart'", Integer.class);
-            if (dwHeartCount > 0) {
-                jdbcTemplate.update("UPDATE dimension_weights dw " +
-                        "JOIN (SELECT DISTINCT target_type, target_id FROM dimension_weights WHERE dimension = 'heart') h " +
-                        "ON dw.target_type = h.target_type AND dw.target_id = h.target_id " +
-                        "SET dw.dimension = 'wisdom' WHERE dw.dimension = 'mind'");
-                jdbcTemplate.update("UPDATE dimension_weights SET dimension = 'mind' WHERE dimension = 'heart'");
-                log.info("已修正dimension_weights表维度code: {}条heart记录", dwHeartCount);
-            }
-        } catch (Exception e) {
-            log.warn("修正dimension_weights表维度code失败: {}", e.getMessage());
-        }
-
-        try {
-            // 2. 主表 dimension_weights JSON 列:含 heart 键的记录,mind键→wisdom键,heart键→mind键
-            String[] jsonTables = {"activities", "products", "articles"};
-            for (String table : jsonTables) {
-                int jsonCount = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM " + table + " WHERE dimension_weights IS NOT NULL " +
-                                "AND JSON_CONTAINS_PATH(dimension_weights, 'one', '$.heart')", Integer.class);
-                if (jsonCount > 0) {
-                    jdbcTemplate.update("UPDATE " + table + " SET dimension_weights = JSON_SET(" +
-                            "JSON_REMOVE(JSON_REMOVE(dimension_weights, '$.mind'), '$.heart'), " +
-                            "'$.wisdom', JSON_EXTRACT(dimension_weights, '$.mind'), " +
-                            "'$.mind', JSON_EXTRACT(dimension_weights, '$.heart')) " +
-                            "WHERE dimension_weights IS NOT NULL " +
-                            "AND JSON_CONTAINS_PATH(dimension_weights, 'one', '$.heart')");
-                    log.info("已修正{}表dimension_weights JSON: {}条", table, jsonCount);
-                }
-            }
-        } catch (Exception e) {
-            log.warn("修正主表dimension_weights JSON失败: {}", e.getMessage());
-        }
-
-        // 迁移142: activities表添加报名截止时间与会员/非会员双收费字段(活动升级:报名时间窗口+孩子/家长双收费+会员区分,需求#3#6)
-        ensureColumn("activities", "registration_deadline", "DATETIME COMMENT '报名截止时间(NULL=不限制, 默认=活动开始时间)'");
-        ensureColumn("activities", "child_fee", "INT DEFAULT 0 COMMENT '孩子·非会员价(分)'");
-        ensureColumn("activities", "child_member_fee", "INT DEFAULT 0 COMMENT '孩子·会员价(分), 0=免费'");
-        ensureColumn("activities", "parent_fee", "INT DEFAULT 0 COMMENT '家长·非会员价(分)'");
-        ensureColumn("activities", "parent_member_fee", "INT DEFAULT 0 COMMENT '家长·会员价(分), 0=免费'");
-        ensureColumn("activities", "creator_id", "BIGINT COMMENT '创建人userId(普通用户发布者, admin创建可为空)'");
-
-        // 迁移143: 创建活动报名订单表(活动付费报名:先支付后报名,需求#4)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS activity_orders (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_no VARCHAR(64) NOT NULL UNIQUE COMMENT '订单号(ACT+时间戳+随机)', " +
-                    "activity_id BIGINT NOT NULL COMMENT '活动ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '下单人userId', " +
-                    "total_amount INT NOT NULL COMMENT '实付金额(分)', " +
-                    "registrants_json TEXT COMMENT '报名人快照JSON: [{name, phone, childId, type: child/parent, fee}]', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/paid/cancelled', " +
-                    "transaction_id VARCHAR(64) COMMENT '微信支付单号', " +
-                    "paid_at DATETIME COMMENT '支付时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_activity (activity_id), " +
-                    "INDEX idx_user (user_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动报名订单表'");
-            log.info("已创建activity_orders表");
-        } catch (Exception e) {
-            log.warn("创建activity_orders表失败: {}", e.getMessage());
-        }
-
-        // 迁移144: 创建活动总结资料表(总结中阶段发布人上传资料,需求#9)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS activity_materials (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "activity_id BIGINT NOT NULL COMMENT '活动ID', " +
-                    "title VARCHAR(200) COMMENT '标题', " +
-                    "file_url VARCHAR(500) NOT NULL COMMENT '文件地址(图片/PDF/外链URL)', " +
-                    "file_type VARCHAR(20) DEFAULT 'image' COMMENT '类型: image/pdf/link', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_activity (activity_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动总结资料表'");
-            log.info("已创建activity_materials表");
-        } catch (Exception e) {
-            log.warn("创建activity_materials表失败: {}", e.getMessage());
-        }
-    }
-
-    private void runMigration82() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS ai_conversation_summary (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "conversation_id VARCHAR(100) NOT NULL COMMENT 'Dify会话ID', " +
-                    "summary_text TEXT COMMENT '对话摘要文本', " +
-                    "summary_tokens INT DEFAULT 0 COMMENT '摘要token数', " +
-                    "message_count INT DEFAULT 0 COMMENT '本次对话消息数', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_conversation (conversation_id), " +
-                    "INDEX idx_user (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI对话摘要'");
-            log.info("已创建ai_conversation_summary表");
-        } catch (Exception e) {
-            log.warn("创建ai_conversation_summary表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS ai_user_facts (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "fact_key VARCHAR(100) NOT NULL COMMENT '事实键', " +
-                    "fact_value VARCHAR(500) COMMENT '事实值', " +
-                    "source_conversation VARCHAR(100) COMMENT '来源会话ID', " +
-                    "confidence DECIMAL(3,2) DEFAULT 1.00 COMMENT '置信度0-1', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                    "INDEX idx_user_key (user_id, fact_key), " +
-                    "INDEX idx_conversation (source_conversation)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI用户关键事实'");
-            log.info("已创建ai_user_facts表");
-        } catch (Exception e) {
-            log.warn("创建ai_user_facts表失败: {}", e.getMessage());
-        }
-    }
-
-    private void runMigration86() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_hierarchy (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL COMMENT '供应商体系ID', " +
-                    "parent_id BIGINT NOT NULL COMMENT '上级供应商ID', " +
-                    "child_id BIGINT NOT NULL COMMENT '下级供应商ID', " +
-                    "level INT DEFAULT 1 COMMENT '层级深度', " +
-                    "status VARCHAR(20) DEFAULT 'active', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_system_parent_child (system_id, parent_id, child_id), " +
-                    "KEY idx_system_child (system_id, child_id), " +
-                    "KEY idx_parent (parent_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商上下级关系表'");
-            log.info("已创建supply_hierarchy表");
-        } catch (Exception e) {
-            log.warn("创建supply_hierarchy表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_hierarchy_change_request (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "system_id BIGINT NOT NULL, " +
-                    "applicant_id BIGINT NOT NULL COMMENT '申请人ID', " +
-                    "target_parent_id BIGINT NOT NULL COMMENT '目标上级ID', " +
-                    "status VARCHAR(20) DEFAULT 'pending', " +
-                    "reason VARCHAR(500), " +
-                    "reject_reason VARCHAR(500), " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "reviewed_at DATETIME, " +
-                    "reviewed_by BIGINT, " +
-                    "KEY idx_system_applicant (system_id, applicant_id), " +
-                    "KEY idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商更换上级申请表'");
-            log.info("已创建supply_hierarchy_change_request表");
-        } catch (Exception e) {
-            log.warn("创建supply_hierarchy_change_request表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS butler_profiles (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL, " +
-                    "tier VARCHAR(10), " +
-                    "status VARCHAR(20) DEFAULT 'pending', " +
-                    "member_count INT DEFAULT 0, " +
-                    "max_members INT DEFAULT 50, " +
-                    "annual_fee_l1 BIGINT, " +
-                    "annual_fee_l2 BIGINT, " +
-                    "description TEXT, " +
-                    "certificates TEXT, " +
-                    "reject_reason VARCHAR(500), " +
-                    "commission_rate_l1 INT DEFAULT 1000, " +
-                    "commission_rate_l2 INT DEFAULT 5000, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "approved_at DATETIME, " +
-                    "UNIQUE KEY uk_user_id (user_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_tier (tier)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家服务提供商档案'");
-            log.info("已创建butler_profiles表");
-        } catch (Exception e) {
-            log.warn("创建butler_profiles表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS butler_service_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "butler_id BIGINT NOT NULL, " +
-                    "member_user_id BIGINT NOT NULL, " +
-                    "subscription_id BIGINT, " +
-                    "service_type VARCHAR(20) NOT NULL, " +
-                    "amount_p BIGINT NOT NULL, " +
-                    "platform_fee_p BIGINT DEFAULT 0, " +
-                    "butler_amount_p BIGINT DEFAULT 0, " +
-                    "member_tier VARCHAR(10), " +
-                    "`year_month` VARCHAR(7), " +
-                    "remark VARCHAR(500), " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_butler_id (butler_id), " +
-                    "INDEX idx_member_user_id (member_user_id), " +
-                    "INDEX idx_year_month (`year_month`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家服务记录'");
-            log.info("已创建butler_service_records表");
-        } catch (Exception e) {
-            log.warn("创建butler_service_records表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS butler_commission_settlements (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "butler_id BIGINT NOT NULL, " +
-                    "`year_month` VARCHAR(7) NOT NULL, " +
-                    "member_count INT DEFAULT 0, " +
-                    "annual_base_amount_p BIGINT DEFAULT 0, " +
-                    "annual_butler_amount_p BIGINT DEFAULT 0, " +
-                    "annual_platform_amount_p BIGINT DEFAULT 0, " +
-                    "per_session_total_p BIGINT DEFAULT 0, " +
-                    "per_session_platform_total_p BIGINT DEFAULT 0, " +
-                    "per_session_butler_total_p BIGINT DEFAULT 0, " +
-                    "total_butler_amount_p BIGINT DEFAULT 0, " +
-                    "status VARCHAR(20) DEFAULT 'pending', " +
-                    "settled_at DATETIME, " +
-                    "settled_by BIGINT, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_butler_month (butler_id, `year_month`), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_year_month (`year_month`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家月度佣金结算单'");
-            log.info("已创建butler_commission_settlements表");
-        } catch (Exception e) {
-            log.warn("创建butler_commission_settlements表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN butler_status VARCHAR(20)");
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN butler_info TEXT");
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN butler_approved_at DATETIME");
-            log.info("已添加 butler 相关列到 users 表");
-        } catch (Exception e) {
-            log.warn("Migration skipped (already exists): {}", e.getMessage());
-        }
-
-        // 迁移 86: 创建 butler_assignments 表(会员 - 管家分配记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS butler_assignments (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭 ID', " +
-                    "butler_user_id BIGINT NOT NULL COMMENT '管家用户 ID', " +
-                    "subscription_id BIGINT COMMENT '关联订阅 ID', " +
-                    "level VARCHAR(10) NOT NULL COMMENT '订阅级别 L1/L2', " +
-                    "assigned_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_family_assignment (family_id), " +
-                    "INDEX idx_butler_user_id (butler_user_id), " +
-                    "INDEX idx_subscription_id (subscription_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员 - 管家分配记录'");
-            log.info("已创建 butler_assignments 表");
-        } catch (Exception e) {
-            log.warn("创建 butler_assignments 表失败:{}", e.getMessage());
-        }
-    }
-
-    private void runMigration88() {
-        // 迁移 88: 创建家庭公共账户体系(family_earnings / family_earnings_member / family_earnings_record)
-        // 表 1: family_earnings(家庭总账)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_earnings (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL UNIQUE COMMENT '家庭 ID', " +
-                    "total_earned BIGINT NOT NULL DEFAULT 0 COMMENT '累计推荐收入(分)', " +
-                    "available_amount BIGINT NOT NULL DEFAULT 0 COMMENT '当前可支配余额(分)', " +
-                    "withdrawn_amount BIGINT NOT NULL DEFAULT 0 COMMENT '已提现金额(分)', " +
-                    "distributed_amount BIGINT NOT NULL DEFAULT 0 COMMENT '已颁发给成员的金额(分)', " +
-                    "updated_at DATETIME, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭公共账户'");
-            log.info("已创建 family_earnings 表");
-        } catch (Exception e) {
-            log.warn("创建 family_earnings 表失败:{}", e.getMessage());
-        }
-
-        // 表 2: family_earnings_member(成员已分配余额)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_earnings_member (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL, " +
-                    "user_id BIGINT NOT NULL, " +
-                    "allocated_amount BIGINT NOT NULL DEFAULT 0 COMMENT '管理员累计分配(分)', " +
-                    "consumed_amount BIGINT NOT NULL DEFAULT 0 COMMENT '已消费金额(分)', " +
-                    "available_amount BIGINT NOT NULL DEFAULT 0 COMMENT '可消费余额=allocated-consumed(分)', " +
-                    "can_use_family_balance TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否允许使用家庭公共池', " +
-                    "updated_at DATETIME, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY idx_family_user (family_id, user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员已分配余额'");
-            log.info("已创建 family_earnings_member 表");
-        } catch (Exception e) {
-            log.warn("创建 family_earnings_member 表失败:{}", e.getMessage());
-        }
-
-        // 表 3: family_earnings_record(收支流水)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_earnings_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL, " +
-                    "type VARCHAR(20) NOT NULL COMMENT 'earn 收入/withdraw 提现/distribute 颁发/consume 消费', " +
-                    "amount BIGINT NOT NULL COMMENT '金额(分)', " +
-                    "from_user_id BIGINT COMMENT '操作人', " +
-                    "to_user_id BIGINT COMMENT '受益人(颁发/消费时填写)', " +
-                    "note VARCHAR(255) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_type (type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭收益收支流水'");
-            log.info("已创建 family_earnings_record 表");
-        } catch (Exception e) {
-            log.warn("创建 family_earnings_record 表失败:{}", e.getMessage());
-        }
-
-        // commission_records 加 family_id 列
-        ensureColumn("commission_records", "family_id", "BIGINT COMMENT '归属家庭 ID'");
-
-        // 迁移90: contacts表添加家庭成员关联字段(联系人→家庭成员升级路径)
-        ensureColumn("contacts", "family_member_id", "BIGINT DEFAULT NULL COMMENT '关联的家庭成员ID'");
-        ensureColumn("contacts", "invited_status", "VARCHAR(16) DEFAULT 'none' COMMENT '邀请加入家庭状态: none/invited/accepted/declined'");
-
-        // 迁移91: 创建family_member_logs表(家庭成员变更日志)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_member_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '成员ID', " +
-                    "action VARCHAR(32) NOT NULL COMMENT '操作: join/leave/update/kick', " +
-                    "old_value VARCHAR(500) COMMENT '旧值', " +
-                    "new_value VARCHAR(500) COMMENT '新值', " +
-                    "operator_id BIGINT COMMENT '操作人用户ID', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员变更日志'");
-            log.info("已创建family_member_logs表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移92: 创建health_meal_record表(饮食打卡记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_meal_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "checkin_id BIGINT COMMENT '关联打卡ID', " +
-                    "meal_type VARCHAR(32) COMMENT '餐次: breakfast/lunch/dinner/snack', " +
-                    "food_items TEXT COMMENT '食物清单JSON', " +
-                    "total_calories INT COMMENT '总卡路里', " +
-                    "protein_g INT COMMENT '蛋白质克数', " +
-                    "fat_g INT COMMENT '脂肪克数', " +
-                    "carbs_g INT COMMENT '碳水克数', " +
-                    "fiber_g INT COMMENT '膳食纤维克数', " +
-                    "meal_time DATETIME COMMENT '用餐时间', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食打卡记录'");
-            log.info("已创建health_meal_record表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移93: 创建health_meditation_record表(冥想打卡记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_meditation_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "checkin_id BIGINT COMMENT '关联打卡ID', " +
-                    "duration_minutes INT COMMENT '时长(分钟)', " +
-                    "type VARCHAR(32) COMMENT '类型: mindfulness/guided/breathing/body_scan', " +
-                    "mood VARCHAR(32) COMMENT '冥想后心情', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='冥想打卡记录'");
-            log.info("已创建health_meditation_record表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移94: 创建ecom_supplier表(电商供应商管理)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS ecom_supplier (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '供应商名称', " +
-                    "contact_name VARCHAR(50) COMMENT '联系人', " +
-                    "contact_phone VARCHAR(20) COMMENT '联系电话', " +
-                    "status TINYINT DEFAULT 1 COMMENT '启用状态 1启用 0禁用', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='电商供应商'");
-            log.info("已创建ecom_supplier表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移95: 创建rebate_commission_config表(佣金返利配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS rebate_commission_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '配置名称', " +
-                    "rate INT COMMENT '佣金比例(万分比)', " +
-                    "rate_type TINYINT DEFAULT 1 COMMENT '比例类型 1百分比 2固定金额', " +
-                    "min_amount INT COMMENT '最低金额(分)', " +
-                    "max_amount INT COMMENT '最高金额(分)', " +
-                    "remark VARCHAR(500) COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='佣金返利配置'");
-            log.info("已创建rebate_commission_config表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-    }
-
-    private void runMigration89() {
-        // 迁移 89: supply_system表添加models字段(AI模型供应商配置)
-        ensureColumn("supply_system", "models", "TEXT COMMENT 'AI模型列表JSON,如[\"agnes-image-2.0-flash\",\"agnes-2.5-flash\"]'");
-        log.info("已添加models列到supply_system表");
-    }
-
-    private void runMigration90() {
-        // 迁移 90: supply_system表添加api_endpoint和api_key字段
-        ensureColumn("supply_system", "api_endpoint", "VARCHAR(512) COMMENT 'API端点'");
-        ensureColumn("supply_system", "api_key", "VARCHAR(256) COMMENT 'API密钥'");
-        log.info("已添加api_endpoint和api_key列到supply_system表");
-    }
-
-    private void runMigration91() {
-        // 迁移 91: users表添加营养师审核字段
-        ensureColumn("users", "nutritionist_status", "VARCHAR(20) DEFAULT NULL COMMENT '营养师审核状态: pending/approved/rejected'");
-        ensureColumn("users", "nutritionist_reject_reason", "VARCHAR(500) DEFAULT NULL COMMENT '营养师审核拒绝原因'");
-        log.info("已添加nutritionist_status和nutritionist_reject_reason列到users表");
-    }
-
-    private void runMigration92() {
-        // 迁移 92: 创建dan_assessment_executions表(DAN测评服务执行记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `dan_assessment_executions` (" +
-                    "`id` BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "`assessment_execution_id` BIGINT NOT NULL COMMENT '执行记录ID', " +
-                    "`assessment_order_id` BIGINT NOT NULL COMMENT '订单ID', " +
-                    "`child_id` BIGINT NOT NULL COMMENT '孩子ID', " +
-                    "`family_id` BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "`quota_id` BIGINT COMMENT '额度ID', " +
-                    "`assessor_id` BIGINT NOT NULL COMMENT '测评师userId', " +
-                    "`assessor_status` ENUM('pending','completed','rejected') DEFAULT 'pending' COMMENT '测评师状态', " +
-                    "`assessor_completed_at` DATETIME COMMENT '测评师完成时间', " +
-                    "`assessor_notes` VARCHAR(200) COMMENT '测评摘要/服务备注', " +
-                    "`planner_id` BIGINT COMMENT '规划师userId', " +
-                    "`planner_status` ENUM('pending','completed','rejected') DEFAULT 'pending' COMMENT '规划师状态', " +
-                    "`planner_completed_at` DATETIME COMMENT '规划师完成时间', " +
-                    "`planner_notes` VARCHAR(200) COMMENT '规划服务备注', " +
-                    "`user_confirmed` TINYINT(1) DEFAULT 0 COMMENT '用户确认:0未确认,1已确认', " +
-                    "`user_confirmed_at` DATETIME COMMENT '用户确认时间', " +
-                    "`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "KEY `idx_assessment_execution_id` (`assessment_execution_id`), " +
-                    "KEY `idx_assessment_order_id` (`assessment_order_id`), " +
-                    "KEY `idx_assessor_id` (`assessor_id`), " +
-                    "KEY `idx_planner_id` (`planner_id`), " +
-                    "KEY `idx_child_id` (`child_id`), " +
-                    "KEY `idx_family_id` (`family_id`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DAN测评服务执行记录'");
-            log.info("已创建dan_assessment_executions表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移 92: 创建service_ratings表(服务评分记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `service_ratings` (" +
-                    "`id` BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "`execution_id` BIGINT NOT NULL COMMENT '执行记录ID', " +
-                    "`assessment_order_id` BIGINT NOT NULL COMMENT '订单ID', " +
-                    "`user_id` BIGINT NOT NULL COMMENT '评分用户ID', " +
-                    "`assessor_id` BIGINT NOT NULL COMMENT '测评师userId', " +
-                    "`assessor_rating` TINYINT DEFAULT 0 COMMENT '测评师评分 1-5', " +
-                    "`assessor_comment` VARCHAR(500) COMMENT '评价内容', " +
-                    "`planner_id` BIGINT COMMENT '规划师userId', " +
-                    "`planner_rating` TINYINT COMMENT '规划师评分 1-5', " +
-                    "`planner_comment` VARCHAR(500) COMMENT '评价内容', " +
-                    "`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY `uniq_execution_user` (`execution_id`, `user_id`)," +
-                    "KEY `idx_assessor_id` (`assessor_id`)," +
-                    "KEY `idx_planner_id` (`planner_id`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务评分记录'");
-            log.info("已创建service_ratings表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移 92: 创建service_settlements表(服务结算记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `service_settlements` (" +
-                    "`id` BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "`execution_id` BIGINT NOT NULL COMMENT '执行记录ID', " +
-                    "`assessment_order_id` BIGINT NOT NULL COMMENT '订单ID', " +
-                    "`provider_id` BIGINT NOT NULL COMMENT '服务提供方userId', " +
-                    "`provider_type` ENUM('assessor','planner') NOT NULL COMMENT '服务方类型', " +
-                    "`service_fee` BIGINT DEFAULT 0 COMMENT '服务费用(分)', " +
-                    "`commission_rate` INT COMMENT '佣金比例(bps)', " +
-                    "`commission_amount` BIGINT DEFAULT 0 COMMENT '结算金额(分)', " +
-                    "`status` ENUM('pending','settled','failed') DEFAULT 'pending' COMMENT '结算状态', " +
-                    "`settled_at` DATETIME COMMENT '结算时间', " +
-                    "`transaction_id` VARCHAR(100) COMMENT '转账交易ID', " +
-                    "`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "KEY `idx_execution_id` (`execution_id`), " +
-                    "KEY `idx_provider_id` (`provider_id`), " +
-                    "KEY `idx_status` (`status`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务结算记录'");
-            log.info("已创建service_settlements表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移 96: product_orders 添加活动provision字段 + activity_provisions 表(活动商品统一管理)
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN activity_id BIGINT DEFAULT NULL COMMENT '关联活动ID(product_type=activity时有效)'");
-            log.info("已添加activity_id列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN provision_status VARCHAR(32) DEFAULT NULL COMMENT '活动provision状态: unprovisioned(待审核)/provisioned(已发货)/signed_in(已签到)/completed(已完成)/cancelled(审核拒绝)'");
-            log.info("已添加provision_status列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN auditor_id BIGINT DEFAULT NULL COMMENT '审核人ID'");
-            log.info("已添加auditor_id列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN audited_at DATETIME DEFAULT NULL COMMENT '审核时间'");
-            log.info("已添加audited_at列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE product_orders ADD COLUMN audit_reason TEXT DEFAULT NULL COMMENT '审核拒绝原因'");
-            log.info("已添加audit_reason列到product_orders表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS activity_provisions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_id BIGINT NOT NULL COMMENT '商品订单ID', " +
-                    "order_no VARCHAR(64) NOT NULL COMMENT '订单编号', " +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID', " +
-                    "activity_id BIGINT NOT NULL COMMENT '活动ID', " +
-                    "buyer_id BIGINT NOT NULL COMMENT '购买者用户ID', " +
-                    "family_id BIGINT COMMENT '家庭ID', " +
-                    "child_id BIGINT COMMENT '报名孩子ID(签到时填写)', " +
-                    "status VARCHAR(32) NOT NULL DEFAULT 'unprovisioned' COMMENT 'unprovisioned/provisioned/signed_in/completed/cancelled', " +
-                    "qr_code VARCHAR(512) COMMENT '签到二维码', " +
-                    "checked_in_at DATETIME COMMENT '签到时间', " +
-                    "completed_at DATETIME COMMENT '完成时间', " +
-                    "refund_amount INT COMMENT '退款金额(分)', " +
-                    "refund_at DATETIME COMMENT '退款时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_order (order_id), " +
-                    "INDEX idx_activity (activity_id), " +
-                    "INDEX idx_buyer (buyer_id), " +
-                    "INDEX idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动provision记录表'");
-            log.info("已创建activity_provisions表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移 97: DAN测评服务佣金配置
-        seedDanCommissionConfig();
-
-        // 迁移 98: 创建 health_knowledge_base 表(菌群/营养知识库)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `health_knowledge_base` (" +
-                    "`id` BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "`item_type` VARCHAR(50) NOT NULL COMMENT '类型: bacteria/nutrient/indicator/vitamin/amino_acid/disease', " +
-                    "`item_name` VARCHAR(200) NOT NULL COMMENT '项目名称(精确匹配)', " +
-                    "`category` VARCHAR(100) COMMENT '分类(如 有益菌/有害菌)', " +
-                    "`normal_range` VARCHAR(200) COMMENT '正常范围参考', " +
-                    "`description` TEXT COMMENT '详细说明', " +
-                    "`suggestion` TEXT COMMENT '相关建议', " +
-                    "`source` VARCHAR(100) COMMENT '数据来源', " +
-                    "`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY `uk_item_type_name` (`item_type`, `item_name`), " +
-                    "KEY `idx_item_type` (`item_type`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康知识库 - 菌属/营养素/指标说明'");
-            log.info("已创建health_knowledge_base表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-    }
-
-    private void seedDanCommissionConfig() {
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO sys_config (config_key, config_value, description, created_at) VALUES " +
-                    "('dan_commission_rate', '10', 'DAN测评服务通用佣金比例(%)', NOW()), " +
-                    "('dan_commission_rate_assessor', '10', 'DAN测评评估师佣金比例(%)', NOW()), " +
-                    "('dan_commission_rate_planner', '10', 'DAN测评规划师佣金比例(%)', NOW())");
-            log.info("已初始化DAN测评佣金配置");
-        } catch (Exception e) {
-            log.warn("DAN佣金配置种子数据可能已存在: " + e.getMessage());
-        }
-
-        // 迁移 98: users 表添加软删除标记(@TableLogic)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN deleted TINYINT DEFAULT 0 COMMENT '软删除标记: 0=未删除, 1=已删除'");
-            log.info("已添加deleted列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移 103: products表添加min_quantity列(商品最小购买数限制)
-        ensureColumn("products", "min_quantity", "INT DEFAULT 1 COMMENT '最小购买数量限制'");
-
-        // 迁移 104: tianpan_daily_fortune表添加缺失字段(FamilyFortune实体对齐)
-        ensureColumn("tianpan_daily_fortune", "lucky_direction", "VARCHAR(20) COMMENT '幸运方向'");
-        ensureColumn("tianpan_daily_fortune", "fortune_level", "VARCHAR(20) COMMENT '运势等级'");
-        ensureColumn("tianpan_daily_fortune", "fortune_level_text", "VARCHAR(100) COMMENT '运势等级描述'");
-        ensureColumn("tianpan_daily_fortune", "fortune_description", "TEXT COMMENT '运势描述'");
-        ensureColumn("tianpan_daily_fortune", "mood_score", "INT DEFAULT 50 COMMENT '心情分数'");
-        ensureColumn("tianpan_daily_fortune", "mood_emoji", "VARCHAR(10) COMMENT '心情emoji'");
-        ensureColumn("tianpan_daily_fortune", "mood_text", "VARCHAR(50) COMMENT '心情文本'");
-        ensureColumn("tianpan_daily_fortune", "weekly_tip", "TEXT COMMENT '每周提示'");
-
-        // 验证迁移104: 确认tianpan_daily_fortune关键列存在
-        try {
-            jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='tianpan_daily_fortune' AND COLUMN_NAME='fortune_level_text'",
-                    Integer.class);
-            log.info("验证通过: tianpan_daily_fortune.fortune_level_text 列存在");
-        } catch (Exception e) {
-            log.error("验证失败: tianpan_daily_fortune.fortune_level_text 列仍然不存在,迁移可能失败: {}", e.getMessage());
-        }
-
-        // 验证迁移103: 确认products.min_quantity列存在
-        try {
-            jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='products' AND COLUMN_NAME='min_quantity'",
-                    Integer.class);
-            log.info("验证通过: products.min_quantity 列存在");
-        } catch (Exception e) {
-            log.error("验证失败: products.min_quantity 列仍然不存在,迁移可能失败: {}", e.getMessage());
-        }
-        // 迁移 105: users表添加article_admin_status和activity_provider_status字段
-        ensureColumn("users", "article_admin_status", "VARCHAR(20) DEFAULT 'pending' COMMENT '文章管理员审核状态'");
-        ensureColumn("users", "activity_provider_status", "VARCHAR(20) DEFAULT 'pending' COMMENT '活动供应商审核状态'");
-    }
-
-    private void runMigration93() {
-        // 迁移 93: 创建 dan_report_uploads 表(DAN PDF报告独立化)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS dan_report_uploads (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "family_member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "uploader_user_id BIGINT NOT NULL COMMENT '上传者用户ID', " +
-                    "dimension VARCHAR(16) NOT NULL COMMENT '维度: mind/wisdom', " +
-                    "report_type VARCHAR(16) COMMENT 'A2/B4', " +
-                    "file_url VARCHAR(500) NOT NULL COMMENT 'PDF文件URL', " +
-                    "file_id VARCHAR(500) COMMENT '媒资文件ID或相对路径', " +
-                    "file_name VARCHAR(200) COMMENT '原始文件名', " +
-                    "file_size BIGINT COMMENT '文件大小(字节)', " +
-                    "uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "parsed_items JSON COMMENT '解析的指标项', " +
-                    "parsed_extra JSON COMMENT '解析的额外信息', " +
-                    "parsed_summary TEXT COMMENT '解析的总结文本', " +
-                    "parsed_suggestions TEXT COMMENT '解析的建议文本', " +
-                    "parser_version VARCHAR(32) COMMENT '解析器版本', " +
-                    "parse_status VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/success/failed', " +
-                    "parse_error VARCHAR(500) COMMENT '解析失败原因', " +
-                    "parsed_at DATETIME COMMENT '解析完成时间', " +
-                    "draft_status VARCHAR(16) DEFAULT 'pending' COMMENT 'pending/confirmed/discarded', " +
-                    "confirmed_at DATETIME COMMENT '确认时间', " +
-                    "confirmed_by BIGINT COMMENT '确认操作人用户ID', " +
-                    "edited_items JSON COMMENT '编辑后的指标项', " +
-                    "edited_extra JSON COMMENT '编辑后的额外信息', " +
-                    "edited_summary TEXT COMMENT '编辑后的总结', " +
-                    "edited_suggestions TEXT COMMENT '编辑后的建议', " +
-                    "edit_count INT DEFAULT 0 COMMENT '编辑次数', " +
-                    "linked_result_id BIGINT COMMENT '关联 dan_assessment_results.id', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "deleted_at DATETIME COMMENT '软删除时间', " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_member_id (family_member_id), " +
-                    "INDEX idx_draft_status (draft_status), " +
-                    "INDEX idx_dimension (dimension), " +
-                    "INDEX idx_parse_status (parse_status), " +
-                    "INDEX idx_linked_result (linked_result_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DAN测评PDF报告独立记录'");
-            log.info("已创建dan_report_uploads表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-    }
-
-    private void runMigration94() {
-        // 迁移 94: dan_assessment_results表添加独立化扩展字段(关联新表)
-        ensureColumn("dan_assessment_results", "source_report_id", "BIGINT DEFAULT NULL COMMENT '关联 dan_report_uploads.id'");
-        ensureColumn("dan_assessment_results", "analysis_status", "VARCHAR(16) DEFAULT 'pending' COMMENT '分析状态: pending/confirmed'");
-        log.info("已添加独立化扩展列到dan_assessment_results表");
-    }
-
-    private void runMigration95() {
-        // 迁移 95: 历史 dan_assessment_results 数据 ETL 回填到 dan_report_uploads
-        // 条件: source='parent_upload' AND source_report_id IS NULL(真正的历史遗留数据)
-        // 注意: 新流程的记录通过 confirmUpload 已正确设置 source_report_id,无需处理
-        try {
-            // Step 1: 插入 dan_report_uploads 记录(来自 dan_assessment_results 的历史数据)
-            jdbcTemplate.execute("INSERT IGNORE INTO dan_report_uploads " +
-                    "(family_id, family_member_id, uploader_user_id, dimension, report_type, " +
-                    "file_url, file_id, draft_status, confirmed_at, confirmed_by, " +
-                    "edited_items, edited_summary, edited_suggestions, linked_result_id, " +
-                    "parsed_status, parse_status, created_at, updated_at) " +
-                    "SELECT " +
-                    "  fm.family_id, " +
-                    "  r.family_member_id, " +
-                    "  r.teacher_id, " +
-                    "  r.dimension, " +
-                    "  r.source, " +
-                    "  COALESCE(r.report_file_id, ''), " +
-                    "  r.report_file_id, " +
-                    "  'confirmed', " +
-                    "  r.created_at, " +
-                    "  r.teacher_id, " +
-                    "  r.structured_analysis, " +
-                    "  r.analysis_report, " +
-                    "  r.growth_suggestions, " +
-                    "  r.id, " +
-                    "  'success', " +
-                    "  'confirmed', " +
-                    "  r.created_at, " +
-                    "  r.updated_at " +
-                    "FROM dan_assessment_results r " +
-                    "LEFT JOIN family_members fm ON fm.id = r.family_member_id " +
-                    "WHERE r.source = 'parent_upload' " +
-                    "  AND r.source_report_id IS NULL " +
-                    "  AND r.draft_status = 'confirmed' " +
-                    "  AND NOT EXISTS (SELECT 1 FROM dan_report_uploads u WHERE u.linked_result_id = r.id)"
-            );
-            log.info("迁移95 Step1: 已将历史 dan_assessment_results 回填到 dan_report_uploads");
-        } catch (Exception e) {
-            log.error("迁移95 Step1 失败: " + e.getMessage());
-        }
-
-        // Step 2: 回填 dan_assessment_results.source_report_id(关联新建的 dan_report_uploads 记录)
-        try {
-            jdbcTemplate.execute("UPDATE dan_assessment_results r " +
-                    "INNER JOIN dan_report_uploads u ON u.linked_result_id = r.id " +
-                    "SET r.source_report_id = u.id " +
-                    "WHERE r.source = 'parent_upload' " +
-                    "  AND r.source_report_id IS NULL " +
-                    "  AND r.draft_status = 'confirmed'"
-            );
-            log.info("迁移95 Step2: 已回填 dan_assessment_results.source_report_id");
-        } catch (Exception e) {
-            log.error("迁移95 Step2 失败: " + e.getMessage());
-        }
-    }
-
-    private void runMigration97() {
-        // 迁移93: users表添加roles字段
-        ensureColumn("users", "roles", "VARCHAR(100) COMMENT '角色列表'");
-    }
-
-    private void runMigration96() {
-        // 迁移96: 修复assessment_appointments.status列类型为TINYINT(原库可能为VARCHAR/ENUM导致Data truncated)
-        try {
-            jdbcTemplate.execute("ALTER TABLE assessment_appointments MODIFY COLUMN status TINYINT DEFAULT 0 COMMENT '0=待确认,1=已确认,2=已完成,3=已取消,4=未到'");
-            log.info("已修复assessment_appointments.status列类型为TINYINT");
-        } catch (Exception e) {
-            log.warn("Migration 96 skipped: {}", e.getMessage());
-        }
-    }
-
-    private void runMigration98() {
-        // 迁移98: family_members表新增辈分字段(TASK-P0-001 辈分重构)
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN generation INT COMMENT '辈分值(0=家庭创建者,+n=向上,-n=向下)'");
-            log.info("已添加generation列到family_members表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN is_spouse TINYINT(1) DEFAULT 0 COMMENT '是否配偶(同辈中)'");
-            log.info("已添加is_spouse列到family_members表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移: products表添加min_quantity列(商品最小购买数限制)
-        ensureColumn("products", "min_quantity", "INT DEFAULT 1 COMMENT '最小购买数量限制'");
-    }
-
-    private void runMigration99() {
-        // 迁移99: 旧关系类型数据回填到辈分字段(TASK-P0-001 辈分重构)
-        try {
-            jdbcTemplate.execute("UPDATE family_members SET generation = 0, is_spouse = 1 WHERE relationship_type = 'spouse'");
-            jdbcTemplate.execute("UPDATE family_members SET generation = 1 WHERE relationship_type = 'parent'");
-            jdbcTemplate.execute("UPDATE family_members SET generation = -1 WHERE relationship_type = 'child'");
-            jdbcTemplate.execute("UPDATE family_members SET generation = 0 WHERE relationship_type = 'sibling'");
-            jdbcTemplate.execute("UPDATE family_members SET generation = 0 WHERE relationship_type IS NULL");
-            log.info("迁移99: 已回填generation/is_spouse旧数据");
-        } catch (Exception e) {
-            log.error("迁移99 失败: " + e.getMessage());
-        }
-
-        ensureColumn("products", "min_quantity", "INT DEFAULT 1 COMMENT '最小购买数量限制'");
-
-        ensureColumn("growth_records", "family_member_id", "BIGINT COMMENT '家庭成员ID'");
-        ensureColumn("growth_records", "family_member_age", "INT COMMENT '家庭成员年龄(月)'");
-        ensureColumn("growth_records", "school", "VARCHAR(100) COMMENT '学校名称'");
-        ensureColumn("growth_records", "grade", "INT COMMENT '年级(数字)'");
-        ensureColumn("growth_records", "academic_performance", "VARCHAR(200) COMMENT '成绩/学业表现'");
-        ensureColumn("growth_records", "school_province", "VARCHAR(50) COMMENT '学校所在省'");
-        ensureColumn("growth_records", "school_city", "VARCHAR(50) COMMENT '学校所在市'");
-        ensureColumn("growth_records", "school_district", "VARCHAR(50) COMMENT '学校所在区'");
-        ensureColumn("growth_records", "school_street", "VARCHAR(100) COMMENT '学校所在街道'");
-    }
-
-    private void runMigration100() {
-        // 迁移100: 删除废弃列和关系类型配置表(TASK-P0-001 辈分重构)
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members DROP COLUMN relationship_type");
-            log.info("已删除family_members.relationship_type列");
-        } catch (Exception e) {
-            // 列已不存在,忽略
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members DROP COLUMN role_override");
-            log.info("已删除family_members.role_override列");
-        } catch (Exception e) {
-            // 列已不存在,忽略
-        }
-    }
-
-    // 迁移 101: product_skus 表添加 min_quantity 列(商品规格最小购买数限制)
-    private void runMigration101() {
-        ensureColumn("product_skus", "min_quantity", "INT DEFAULT 1 COMMENT '最小购买数量限制'");
-    }
-    
-    // 迁移 102: health_gut_flora 表扩大 population_level 和 detection_rate 字段长度
-    private void runMigration102() {
-        // 将 VARCHAR(50) 扩大到 TEXT(处理 AI 解析出的长文本)
-        ensureColumn("health_gut_flora", "population_level",
-                "TEXT DEFAULT NULL COMMENT '处于人群%水平'");
-        ensureColumn("health_gut_flora", "detection_rate",
-                "TEXT DEFAULT NULL COMMENT '%正常人有检出'");
-    }
-
-    private void migration102() {
-        // 迁移 102: health_gut_flora 表扩大 population_level 和 detection_rate 字段长度(TEXT)
-        ensureColumn("health_gut_flora", "population_level",
-                "TEXT DEFAULT NULL COMMENT '处于人群%水平'");
-        ensureColumn("health_gut_flora", "detection_rate",
-                "TEXT DEFAULT NULL COMMENT '%正常人有检出'");
-    
-        // 迁移 102: 创建 health_dimension_scores 表(7 维健康模型)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_dimension_scores (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "dimension VARCHAR(20) NOT NULL COMMENT '维度编码', " +
-                    "score INT NOT NULL COMMENT '评分(0-100)', " +
-                    "percentile INT COMMENT '百分位', " +
-                    "data_source VARCHAR(20) COMMENT '数据来源', " +
-                    "tier INT DEFAULT 3 COMMENT '数据可信度层级', " +
-                    "raw_data TEXT COMMENT '原始数据JSON', " +
-                    "assess_date DATE COMMENT '评估日期', " +
-                    "expire_date DATE COMMENT '过期日期', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_dim (member_id, dimension), " +
-                    "INDEX idx_assess_date (assess_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康维度评分'");
-            log.info("已创建health_dimension_scores表");
-        } catch (Exception e) {
-            log.warn("创建health_dimension_scores表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移102b: 创建 health_data_sources 表(多媒体数据源记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS health_data_sources (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "source_type VARCHAR(20) NOT NULL COMMENT '数据源类型: VOICE/PHOTO/REPORT/MANUAL', " +
-                    "dimension_codes VARCHAR(100) COMMENT '关联维度编码(逗号分隔)', " +
-                    "parsed_result TEXT COMMENT '解析结果JSON', " +
-                    "file_url VARCHAR(500) COMMENT '原始文件URL', " +
-                    "confidence DECIMAL(5,4) COMMENT 'AI解析置信度(0-1)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_source (member_id, source_type), " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康数据源记录'");
-            log.info("已创建health_data_sources表");
-        } catch (Exception e) {
-            log.warn("创建health_data_sources表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移103: health_indicators表添加collection_date列(指标采集日期)
-        ensureColumn("health_indicators", "collection_date", "DATETIME COMMENT '指标采集日期(报告检测日期)'");
-
-        // 迁移104: promotion_tier表确保team_size_1st/2nd/3rd列存在(MyBatis-Plus camelCase映射修正)
-        ensureColumn("promotion_tier", "team_size_1st", "INT DEFAULT 0 COMMENT '一层团队人数'");
-        ensureColumn("promotion_tier", "team_size_2nd", "INT DEFAULT 0 COMMENT '二层团队人数'");
-        ensureColumn("promotion_tier", "team_size_3rd", "INT DEFAULT 0 COMMENT '三层团队人数'");
-
-        // 迁移105: article_reading_records表添加article_id和updated_at列
-        try {
-            jdbcTemplate.execute("ALTER TABLE article_reading_records ADD COLUMN article_id BIGINT DEFAULT NULL COMMENT '文章ID' AFTER id");
-            log.info("已添加article_id列到article_reading_records表");
-        } catch (Exception e) {
-            // 列已存在,忽略
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE article_reading_records ADD COLUMN updated_at DATETIME DEFAULT NULL COMMENT '更新时间' AFTER read_at");
-            log.info("已添加updated_at列到article_reading_records表");
-        } catch (Exception e) {
-            // 列已存在,忽略
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE article_reading_records ADD INDEX idx_article_child_date (article_id, child_id, read_at)");
-            log.info("已添加idx_article_child_date索引");
-        } catch (Exception e) {
-            // 索引已存在,忽略
-        }
-
-        // 迁移106: 创建 report_summary 统一报告汇总表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_summary (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "report_type VARCHAR(32) NOT NULL COMMENT '报告类型', " +
-                    "source_table VARCHAR(32) NOT NULL COMMENT '来源表', " +
-                    "source_id BIGINT NOT NULL COMMENT '来源表记录ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '创建者用户ID', " +
-                    "family_id BIGINT COMMENT '家庭ID', " +
-                    "subject_id BIGINT COMMENT '报告主体ID', " +
-                    "subject_name VARCHAR(50) COMMENT '报告主体名称', " +
-                    "title VARCHAR(200) COMMENT '报告标题', " +
-                    "summary TEXT COMMENT '摘要', " +
-                    "file_url VARCHAR(500) COMMENT '文件URL', " +
-                    "file_size BIGINT COMMENT '文件大小', " +
-                    "file_name VARCHAR(200) COMMENT '文件名', " +
-                    "has_file TINYINT DEFAULT 0 COMMENT '是否有文件', " +
-                    "overall_score INT COMMENT '综合评分', " +
-                    "report_date DATE COMMENT '报告日期', " +
-                    "status VARCHAR(20) COMMENT '状态', " +
-                    "detail_route VARCHAR(100) COMMENT '详情页路由', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_family_id (family_id), " +
-                    "INDEX idx_subject_id (subject_id), " +
-                    "INDEX idx_report_type (report_type), " +
-                    "INDEX idx_report_date (report_date), " +
-                    "INDEX idx_status (status), " +
-                    "UNIQUE KEY uk_source (source_table, source_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一报告汇总表'");
-            log.info("已创建 report_summary 表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移107: tasks表添加dimension_code和dimension_weights列(五维维度支持)
-        try {
-            ensureColumn("tasks", "dimension_code", "VARCHAR(20) COMMENT '五维维度: body/mind/wisdom/action/wealth'");
-            ensureColumn("tasks", "dimension_weights", "JSON COMMENT '五维权重: {\"body\":0,\"mind\":0,\"wisdom\":0,\"action\":0,\"wealth\":0}'");
-            log.info("已完成tasks表维度字段添加");
-        } catch (Exception e) {
-            log.warn("添加tasks表维度字段失败: {}", e.getMessage());
-        }
-
-        // 迁移108: 创建 energy_behavior_config 表(能量行为配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS energy_behavior_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "behavior_code VARCHAR(32) NOT NULL COMMENT '行为编码', " +
-                    "behavior_name VARCHAR(50) NOT NULL COMMENT '行为名称', " +
-                    "description VARCHAR(200) COMMENT '行为描述', " +
-                    "default_amount INT DEFAULT 5 COMMENT '默认能量值', " +
-                    "amount_source VARCHAR(32) DEFAULT 'fixed' COMMENT '能量值来源', " +
-                    "dimension_assign JSON COMMENT '维度分配JSON', " +
-                    "daily_limit INT DEFAULT 0 COMMENT '每日上限', " +
-                    "cooldown_seconds INT DEFAULT 0 COMMENT '冷却时间(秒)', " +
-                    "expire_days INT DEFAULT 0 COMMENT '过期天数', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '是否启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_behavior_code (behavior_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量行为配置表'");
-            log.info("已创建 energy_behavior_config 表");
-
-            // 插入预置数据(仅当表为空时插入)
-            Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM energy_behavior_config", Integer.class);
-            if (count == null || count == 0) {
-                String[][] seedData = {
-                        {"task_complete", "完成任务", "完成任务获得的能量", "5", "points", "[{\"dim\":\"action\",\"ratio\":100}]", "200", "0", "0"},
-                        {"game_finish", "完成游戏", "完成小游戏获得的能量", "5", "points", "[{\"dim\":\"mind\",\"ratio\":30},{\"dim\":\"wisdom\",\"ratio\":50},{\"dim\":\"action\",\"ratio\":20}]", "200", "0", "0"},
-                        {"activity_checkin", "活动签到", "活动签到获得的能量", "5", "fixed", "[{\"dim\":\"body\",\"ratio\":30},{\"dim\":\"action\",\"ratio\":70}]", "100", "0", "0"},
-                        {"article_read", "阅读文章", "阅读文章获得的能量", "5", "points", "[{\"dim\":\"mind\",\"ratio\":30},{\"dim\":\"wisdom\",\"ratio\":50},{\"dim\":\"action\",\"ratio\":20}]", "100", "0", "0"},
-                        {"product_purchase", "商品购买", "购买商品获得的能量", "10", "order_amount", "[{\"dim\":\"wealth\",\"ratio\":100}]", "500", "0", "30"},
-                        {"health_checkin", "健康打卡", "健康打卡获得的能量", "5", "fixed", "[{\"dim\":\"body\",\"ratio\":100}]", "50", "0", "30"},
-                        {"finance_checkin", "理财打卡", "理财打卡获得的能量", "5", "fixed", "[{\"dim\":\"wealth\",\"ratio\":100}]", "50", "0", "0"},
-                        {"emotion_checkin", "情绪打卡", "情绪打卡获得的能量", "5", "fixed", "[{\"dim\":\"mind\",\"ratio\":100}]", "40", "0", "0"},
-                        {"appointment_submit", "提交测评预约", "提交测评预约获得的能量", "10", "fixed", "[{\"dim\":\"action\",\"ratio\":100}]", "50", "0", "0"},
-                        {"appointment_complete", "完成测评", "完成测评获得的能量", "30", "fixed", "[{\"dim\":\"mind\",\"ratio\":50},{\"dim\":\"wisdom\",\"ratio\":50}]", "100", "0", "0"},
-                        {"streak_daily", "连续打卡每日", "每日连续打卡获得的能量", "5", "fixed", "[{\"dim\":\"body\",\"ratio\":30},{\"dim\":\"mind\",\"ratio\":20},{\"dim\":\"action\",\"ratio\":50}]", "50", "86400", "0"},
-                        {"streak_milestone", "打卡里程碑", "达到打卡里程碑获得的能量", "20", "config", "[{\"dim\":\"body\",\"ratio\":30},{\"dim\":\"mind\",\"ratio\":20},{\"dim\":\"action\",\"ratio\":50}]", "100", "0", "0"},
-                        {"growth_task", "成长任务", "完成每日成长任务获得的能量", "10", "config", "[{\"dim\":\"body\",\"ratio\":20},{\"dim\":\"mind\",\"ratio\":20},{\"dim\":\"wisdom\",\"ratio\":20},{\"dim\":\"action\",\"ratio\":20},{\"dim\":\"wealth\",\"ratio\":20}]", "100", "0", "1"},
-                        {"micro_action", "微行动", "完成微行动获得的能量", "1", "fixed", "[{\"dim\":\"action\",\"ratio\":100}]", "20", "60", "30"},
-                        {"onboarding", "新手引导", "完成新手引导任务获得的能量", "10", "config", "[{\"dim\":\"body\",\"ratio\":20},{\"dim\":\"mind\",\"ratio\":20},{\"dim\":\"wisdom\",\"ratio\":20},{\"dim\":\"action\",\"ratio\":20},{\"dim\":\"wealth\",\"ratio\":20}]", "50", "0", "30"},
-                        {"invite_milestone", "邀请里程碑", "达到邀请人数里程碑获得的能量", "30", "config", "[{\"dim\":\"action\",\"ratio\":40},{\"dim\":\"wealth\",\"ratio\":60}]", "200", "0", "30"},
-                        {"dimension_sync", "维度同步", "健康维度数据上传同步获得的能量", "10", "config", "[{\"dim\":\"body\",\"ratio\":100}]", "100", "0", "30"},
-                        {"invite_friend", "邀请好友加入", "邀请好友注册加入获得的能量", "20", "fixed", "[{\"dim\":\"action\",\"ratio\":50},{\"dim\":\"wealth\",\"ratio\":50}]", "200", "0", "0"},
-                        {"invite_family", "邀请家庭成员", "邀请家庭成员加入家庭获得的能量", "10", "fixed", "[{\"dim\":\"mind\",\"ratio\":30},{\"dim\":\"action\",\"ratio\":70}]", "100", "0", "0"},
-                        {"report_upload", "上传体检报告", "上传体检报告获得的能量", "30", "fixed", "[{\"dim\":\"body\",\"ratio\":100}]", "100", "0", "30"},
-                        {"plan_complete", "完成成长计划", "完成成长计划复盘获得的能量", "20", "fixed", "[{\"dim\":\"body\",\"ratio\":20},{\"dim\":\"mind\",\"ratio\":20},{\"dim\":\"wisdom\",\"ratio\":20},{\"dim\":\"action\",\"ratio\":20},{\"dim\":\"wealth\",\"ratio\":20}]", "100", "0", "0"},
-                        {"wisdom_report", "上传智测评报告", "上传智慧测评报告获得的能量", "30", "fixed", "[{\"dim\":\"wisdom\",\"ratio\":100}]", "100", "0", "30"},
-                };
-                String sql = "INSERT INTO energy_behavior_config (behavior_code, behavior_name, description, default_amount, amount_source, dimension_assign, daily_limit, cooldown_seconds, expire_days, enabled) VALUES (?,?,?,?,?,?,?,?,?,1)";
-                for (String[] row : seedData) {
-                    try {
-                        jdbcTemplate.update(sql, row[0], row[1], row[2], Integer.parseInt(row[3]), row[4], row[5], Integer.parseInt(row[6]), Integer.parseInt(row[7]), Integer.parseInt(row[8]));
-                    } catch (Exception e) {
-                        log.warn("插入能量行为配置失败: behavior_code={}, error={}", row[0], e.getMessage());
-                    }
-                }
-                log.info("已插入{}条能量行为配置", seedData.length);
-            }
-        } catch (Exception e) {
-            log.warn("创建 energy_behavior_config 表失败: {}", e.getMessage());
-        }
-
-        // 迁移109: finance_checkins表添加type列(记账类型: income/expense)
-        try {
-            ensureColumn("finance_checkins", "type", "VARCHAR(10) DEFAULT 'expense' COMMENT '类型: income(收入)/expense(支出)'");
-            log.info("已完成finance_checkins.type字段添加");
-        } catch (Exception e) {
-            log.warn("添加finance_checkins.type字段失败: {}", e.getMessage());
-        }
-
-        // 迁移110: 创建 article_comments 表(文章评论)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS article_comments (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "article_id BIGINT NOT NULL COMMENT '文章ID', " +
-                    "parent_id BIGINT COMMENT '父评论ID', " +
-                    "reply_to_id BIGINT COMMENT '引用的评论ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '评论用户ID', " +
-                    "content TEXT NOT NULL COMMENT '评论内容', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/approved/rejected', " +
-                    "audit_by BIGINT COMMENT '审核人ID', " +
-                    "audit_at DATETIME COMMENT '审核时间', " +
-                    "earned_energy INT DEFAULT 0 COMMENT '获得的能量', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_article (article_id), " +
-                    "INDEX idx_article_status (article_id, status), " +
-                    "INDEX idx_parent (parent_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章评论'");
-            log.info("已创建 article_comments 表");
-        } catch (Exception e) {
-            log.warn("创建 article_comments 表失败: {}", e.getMessage());
-        }
-
-        // 迁移111: 创建 service_role_applications 表(服务角色统一申请)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS service_role_applications (" +
-                    "id int(11) NOT NULL AUTO_INCREMENT, " +
-                    "user_id int(11) NOT NULL COMMENT '申请人ID', " +
-                    "roles varchar(255) NOT NULL COMMENT '申请角色,JSON数组', " +
-                    "id_card varchar(18) DEFAULT '' COMMENT '身份证号', " +
-                    "id_card_images text COMMENT '身份证照片,JSON数组', " +
-                    "certificate_images text COMMENT '资质证书照片,JSON数组', " +
-                    "province varchar(50) DEFAULT '' COMMENT '省', " +
-                    "city varchar(50) DEFAULT '' COMMENT '市', " +
-                    "district varchar(50) DEFAULT '' COMMENT '区', " +
-                    "street varchar(50) DEFAULT '' COMMENT '街道', " +
-                    "address_detail varchar(200) DEFAULT '' COMMENT '详细地址', " +
-                    "status tinyint(4) NOT NULL DEFAULT 0 COMMENT '0-pending 1-approved 2-rejected', " +
-                    "reject_reason varchar(500) DEFAULT '' COMMENT '驳回原因', " +
-                    "reviewed_by int(11) DEFAULT NULL COMMENT '审核人ID', " +
-                    "reviewed_at datetime DEFAULT NULL COMMENT '审核时间', " +
-                    "created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "PRIMARY KEY (id), " +
-                    "KEY idx_user_id (user_id), " +
-                    "KEY idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务角色申请表'");
-            log.info("已创建service_role_applications表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移112: users表添加article_admin_status字段(文章管理员状态)
-        log.info("迁移112: 开始添加article_admin_status列到users表");
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN article_admin_status VARCHAR(20) DEFAULT NULL COMMENT '文章管理员状态: pending/approved/rejected'");
-            log.info("迁移112: 已添加article_admin_status列到users表");
-        } catch (Exception e) {
-            // 列已存在,幂等忽略(用warn而非error避免日志噪声)
-            log.warn("迁移112: 添加article_admin_status列失败(可能已存在): {}", e.getMessage());
-        }
-
-        // 迁移113: users表添加activity_provider_status字段(活动提供商状态)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN activity_provider_status VARCHAR(20) DEFAULT NULL COMMENT '活动提供商状态: pending/approved/rejected'");
-            log.info("已添加activity_provider_status列到users表");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-
-        // 迁移114: 创建 periodic_services 表(周期性服务续费配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS periodic_services (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '关联商品ID', " +
-                    "service_name VARCHAR(100) COMMENT '服务名称', " +
-                    "cycle_days INT NOT NULL COMMENT '周期天数(如365=年度服务)', " +
-                    "remind_before_days INT DEFAULT 30 COMMENT '提前提醒天数', " +
-                    "auto_renew TINYINT DEFAULT 0 COMMENT '是否支持自动续费: 0=否 1=是', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '是否启用: 0=禁用 1=启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product (product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='周期性服务续费配置'");
-            log.info("已创建 periodic_services 表");
-        } catch (Exception e) {
-            log.warn("创建 periodic_services 表失败: {}", e.getMessage());
-        }
-
-        // 迁移115: 创建 recommendation_logs 表(推荐行为记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS recommendation_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT COMMENT '用户ID', " +
-                    "family_id BIGINT COMMENT '家庭ID', " +
-                    "child_id BIGINT COMMENT '孩子ID', " +
-                    "content_type VARCHAR(20) NOT NULL COMMENT '内容类型: article/task/product/activity', " +
-                    "content_id BIGINT NOT NULL COMMENT '内容ID', " +
-                    "recommend_score INT COMMENT '推荐分值', " +
-                    "action VARCHAR(20) COMMENT '行为: show/click/consume', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_content (user_id, content_type, content_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐行为记录'");
-            log.info("已创建 recommendation_logs 表");
-        } catch (Exception e) {
-            log.warn("创建 recommendation_logs 表失败: {}", e.getMessage());
-        }
-
-        // 迁移116: products表添加family_scope列(推荐系统-家庭消费去重)
-        try {
-            ensureColumn("products", "family_scope", "TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员消费过即排除, 0=仅按个人消费排除'");
-            log.info("已完成products.family_scope字段添加");
-        } catch (Exception e) {
-            log.warn("添加products.family_scope字段失败: {}", e.getMessage());
-        }
-
-        // 迁移117: activities表添加family_scope列(推荐系统-家庭参与去重)
-        try {
-            ensureColumn("activities", "family_scope", "TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员参与过即排除, 0=仅按个人参与排除'");
-            log.info("已完成activities.family_scope字段添加");
-        } catch (Exception e) {
-            log.warn("添加activities.family_scope字段失败: {}", e.getMessage());
-        }
-
-        // 迁移118: activity_registrations表child_id改为可空 + 添加registrant_name/phone(报名表单-多人报名)
-        try {
-            ensureColumn("activity_registrations", "registrant_name", "VARCHAR(100) COMMENT '报名人姓名'");
-            log.info("已完成activity_registrations.registrant_name字段添加");
-        } catch (Exception e) {
-            log.warn("添加activity_registrations.registrant_name字段失败: {}", e.getMessage());
-        }
-        try {
-            ensureColumn("activity_registrations", "registrant_phone", "VARCHAR(20) COMMENT '报名人联系方式'");
-            log.info("已完成activity_registrations.registrant_phone字段添加");
-        } catch (Exception e) {
-            log.warn("添加activity_registrations.registrant_phone字段失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE activity_registrations MODIFY COLUMN child_id BIGINT COMMENT '孩子ID(手动输入报名人为空)'");
-            log.info("已完成activity_registrations.child_id改为可空");
-        } catch (Exception e) {
-            log.warn("修改activity_registrations.child_id失败: {}", e.getMessage());
-        }
-        // 迁移119: package_orders表添加联系人字段(产品页下单)
-        try {
-            ensureColumn("package_orders", "contact_name", "VARCHAR(50) COMMENT '联系人姓名'");
-            ensureColumn("package_orders", "contact_phone", "VARCHAR(20) COMMENT '联系人手机号'");
-            ensureColumn("package_orders", "contact_address", "VARCHAR(500) COMMENT '收件地址'");
-            log.info("已完成package_orders表联系人字段添加");
-        } catch (Exception e) {
-            log.warn("添加package_orders联系人字段失败: {}", e.getMessage());
-        }
-
-        // 迁移120: activities表添加registration_deadline列(活动中心-报名截止时间展示)
-        try {
-            ensureColumn("activities", "registration_deadline", "DATETIME COMMENT '报名截止时间'");
-            log.info("已完成activities.registration_deadline字段添加");
-        } catch (Exception e) {
-            log.warn("添加activities.registration_deadline字段失败: {}", e.getMessage());
-        }
-
-        // 迁移143: 创建小程序虚拟支付道具映射表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS virtual_goods_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "goods_type VARCHAR(32) NOT NULL COMMENT 'ASSESSMENT_PACKAGE / MEMBERSHIP / SUBSCRIPTION', " +
-                    "biz_key VARCHAR(64) NOT NULL COMMENT '业务SKU标识: 测评套餐ID / 会员等级code / 订阅档位code', " +
-                    "product_id VARCHAR(64) NOT NULL COMMENT '微信商户后台道具ID', " +
-                    "goods_name VARCHAR(128) NOT NULL COMMENT '道具名称', " +
-                    "status TINYINT NOT NULL DEFAULT 1 COMMENT '1=启用 0=停用', " +
-                    "create_time DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_goods_type_biz (goods_type, biz_key)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小程序虚拟支付道具映射'");
-            log.info("已创建virtual_goods_config表");
-        } catch (Exception e) {
-            log.warn("创建virtual_goods_config表失败: {}", e.getMessage());
-        }
-
-        // 迁移144: users表添加session_key列(小程序虚拟支付signature签名会话密钥)
-        try {
-            ensureColumn("users", "session_key", "VARCHAR(64) COMMENT '微信登录会话密钥(虚拟支付签名用)'");
-            log.info("已完成users.session_key字段添加");
-        } catch (Exception e) {
-            log.warn("添加users.session_key字段失败: {}", e.getMessage());
-        }
-
-        // 迁移145: 创建家庭天盘周报导出记录表(ReportSummaryService 全量同步依赖,此前从未建表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_fortune_report (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id INT NOT NULL COMMENT '家庭ID', " +
-                    "element VARCHAR(32) COMMENT '主导五行元素', " +
-                    "lucky_direction VARCHAR(64) COMMENT '本周吉位', " +
-                    "pdf_path VARCHAR(255) COMMENT 'PDF周报文件路径', " +
-                    "file_size BIGINT COMMENT '文件大小(字节)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_id (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭天盘周报导出记录'");
-            log.info("已创建family_fortune_report表");
-        } catch (Exception e) {
-            log.warn("创建family_fortune_report表失败: {}", e.getMessage());
-        }
-
-        // 迁移146: 创建五维家庭自检记录表(P0-1 五维自检问卷,书稿终章15题)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS five_dimension_self_checks (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '答卷人用户ID', " +
-                    "family_member_id BIGINT COMMENT '关联家庭成员ID(可选)', " +
-                    "answers_json TEXT COMMENT '用户答案JSON', " +
-                    "scores_json VARCHAR(512) COMMENT '各维度得分JSON', " +
-                    "total_score INT COMMENT '五维总分(满分45)', " +
-                    "advice_json TEXT COMMENT '五行相生寻源建议JSON', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维家庭自检记录'");
-            log.info("已创建five_dimension_self_checks表");
-        } catch (Exception e) {
-            log.warn("创建five_dimension_self_checks表失败: {}", e.getMessage());
-        }
-
-        // 迁移147: virtual_goods_config 插入会员年卡道具映射(虚拟支付上线准备)
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO virtual_goods_config (goods_type, biz_key, product_id, goods_name, status) " +
-                    "VALUES ('MEMBERSHIP', 'member1314', 'TBD', '会员年卡', 1)");
-            log.info("已插入会员年卡道具映射: member1314");
-        } catch (Exception e) {
-            log.warn("插入会员年卡道具映射失败: {}", e.getMessage());
-        }
-
-        // 迁移148: 修复 membership_levels 表重复行 + 添加 UNIQUE KEY uk_level_code
-        // 原因:早期建表缺少 UNIQUE KEY uk_level_code,加上 INSERT IGNORE 在无唯一键时反复插入,
-        //       导致生产环境 FREE/FAMILY/PROVIDER 三个等级各 69 行重复,
-        //       MembershipService.createOrder() 调用 selectOne(level_code) 触发 TooManyResultsException。
-        try {
-            // 1) 删除重复行:保留每个 level_code 最早插入的(id 最小),其余删除
-            int deleted = jdbcTemplate.update(
-                    "DELETE m1 FROM membership_levels m1 " +
-                            "INNER JOIN membership_levels m2 " +
-                            "ON m1.level_code = m2.level_code AND m1.id > m2.id");
-            log.info("已清理 membership_levels 重复行: 删除{}条", deleted);
-        } catch (Exception e) {
-            log.warn("清理 membership_levels 重复行失败: {}", e.getMessage());
-        }
-        try {
-            // 2) 添加 UNIQUE KEY(幂等:先查再 ADD)
-            Integer idxCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.statistics " +
-                            "WHERE table_schema = DATABASE() AND table_name = 'membership_levels' AND index_name = 'uk_level_code'",
-                    Integer.class);
-            if (idxCount == null || idxCount == 0) {
-                jdbcTemplate.execute("ALTER TABLE membership_levels ADD UNIQUE KEY uk_level_code (level_code)");
-                log.info("已添加 uk_level_code 唯一索引到 membership_levels 表");
-            } else {
-                log.info("uk_level_code 唯一索引已存在,跳过添加");
-            }
-        } catch (Exception e) {
-            log.warn("添加 uk_level_code 唯一索引失败: {}", e.getMessage());
-        }
-
-        // 迁移149: payment_orders表添加user_coupon_id列(VirtualPayTimeoutTask selectList 触发 Unknown column)
-        // 原因:旧库建表时缺少此列,entity PaymentOrder 已声明 userCouponId,导致 MyBatis-Plus 全列查询失败。
-        //      本地与远端新库已有,本迁移对它们幂等。
-        try {
-            ensureColumn("payment_orders", "user_coupon_id", "BIGINT COMMENT '使用的用户优惠券ID'");
-            log.info("已确保payment_orders.user_coupon_id列存在");
-        } catch (Exception e) {
-            log.warn("添加payment_orders.user_coupon_id列失败: {}", e.getMessage());
-        }
-
-        // 迁移150: activities表添加member_price列(会员价支持)
-        try {
-            ensureColumn("activities", "member_price", "INT COMMENT '会员价(分)' AFTER price");
-            log.info("已确保activities.member_price列存在");
-        } catch (Exception e) {
-            log.warn("添加activities.member_price列失败: {}", e.getMessage());
-        }
-
-        // 迁移151: growth_records表补齐学校/年级字段(GrowthRecord 实体全列查询 Unknown column 'school')
-        // 原因:实体已声明 school/grade/academicPerformance/schoolProvince/schoolCity/schoolDistrict/schoolStreet,
-        //      且 @TableField 为 camelCase 列名,但旧库建表时缺失这些列;
-        //      runMigration99() 为死代码从未执行,且其 snake_case 列名与实体 camelCase 不匹配。
-        ensureColumn("growth_records", "school", "VARCHAR(100) COMMENT '学校名称'");
-        ensureColumn("growth_records", "grade", "INT COMMENT '年级(数字)'");
-        ensureColumn("growth_records", "academicPerformance", "VARCHAR(200) COMMENT '成绩/学业表现'");
-        ensureColumn("growth_records", "schoolProvince", "VARCHAR(50) COMMENT '学校所在省'");
-        ensureColumn("growth_records", "schoolCity", "VARCHAR(50) COMMENT '学校所在市'");
-        ensureColumn("growth_records", "schoolDistrict", "VARCHAR(50) COMMENT '学校所在区'");
-        ensureColumn("growth_records", "schoolStreet", "VARCHAR(100) COMMENT '学校所在街道'");
-        log.info("已确保growth_records学校/年级相关列存在");
-
-        // 迁移152: 创建 product_gift_rules 表(商品赠送会员规则)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_gift_rules (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '关联products表', " +
-                    "level_code VARCHAR(50) NOT NULL COMMENT '赠送会员等级编码(FAMILY/PREMIUM等)', " +
-                    "status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_product_level (product_id, level_code), " +
-                    "INDEX idx_product_id (product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠送会员规则'");
-            log.info("创建product_gift_rules表成功");
-        } catch (Exception e) {
-            log.warn("创建product_gift_rules表失败: {}", e.getMessage());
-        }
-
-        // 迁移153: 创建 growth_archive_products 表(成长档案关联商品配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS growth_archive_products (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '关联products表', " +
-                    "status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用', " +
-                    "sort_order INT DEFAULT 0 COMMENT '展示排序(升序)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                    "UNIQUE KEY uk_product_id (product_id), " +
-                    "KEY idx_status (status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长档案关联商品配置'");
-            log.info("已创建growth_archive_products表");
-        } catch (Exception e) {
-            log.warn("创建growth_archive_products表失败: {}", e.getMessage());
-        }
-
-        // 迁移154: membership_levels 表插入 PREMIUM 等级种子数据(前端升级页可选"高级家庭会员",createOrder 查表为 null 抛"会员等级不存在")
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_levels (level_code, level_name, level_desc, price_monthly, price_quarterly, price_yearly, max_children, max_tasks_per_day, ai_review_enabled, priority_support, teacher_consultation) VALUES " +
-                    "('PREMIUM', '高级家庭会员', '高级家庭会员专属功能', 131400, NULL, 1316800, 10, 50, 1, 1, 1)");
-            log.info("已插入PREMIUM等级种子数据");
-        } catch (Exception e) {
-            log.warn("插入PREMIUM等级种子数据失败: {}", e.getMessage());
-        }
-
-        // 迁移155: 创建 interaction_logs 表(关系互动记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS interaction_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '所属家庭ID', " +
-                    "from_member_id BIGINT NOT NULL COMMENT '互动发起方成员ID', " +
-                    "to_member_id BIGINT NOT NULL COMMENT '互动接收方成员ID', " +
-                    "interaction_type VARCHAR(20) NOT NULL COMMENT '互动类型: dining/outgoing/call/video/chat/play/gift', " +
-                    "description VARCHAR(500) COMMENT '互动描述', " +
-                    "happened_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '互动发生时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_ilog_family (family_id), " +
-                    "INDEX idx_ilog_to_member (to_member_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员互动记录'");
-            log.info("已创建interaction_logs表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移156: 创建 relationship_questionnaire_snapshots 表(关系问卷快照)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS relationship_questionnaire_snapshots (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "respondent_id BIGINT NOT NULL COMMENT '答卷人用户ID', " +
-                    "member_name VARCHAR(50) COMMENT '成员名称', " +
-                    "relationship_type VARCHAR(20) COMMENT '关系类型: parent/child', " +
-                    "ai_generated_json TEXT COMMENT 'AI生成的题目JSON', " +
-                    "version VARCHAR(20) COMMENT '版本号', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_q_snap_member (family_member_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关系问卷快照'");
-            log.info("已创建relationship_questionnaire_snapshots表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移158: users.family_id 允许 NULL(新用户微信登录时无家庭)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users MODIFY COLUMN family_id BIGINT COMMENT '家庭ID'");
-            log.info("已修改users.family_id允许NULL");
-        } catch (Exception e) {
-            // 忽略错误
-        }
-
-        // 迁移157: 创建 relationship_questionnaire_responses 表(关系问卷回答)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS relationship_questionnaire_responses (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "snapshot_id BIGINT NOT NULL COMMENT '问卷快照ID', " +
-                    "respondent_id BIGINT NOT NULL COMMENT '答卷人用户ID', " +
-                    "answers_json TEXT COMMENT '用户回答JSON', " +
-                    "trust_score DECIMAL(5,2) DEFAULT 0 COMMENT '信任度得分', " +
-                    "intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度得分', " +
-                    "communication_score DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量得分', " +
-                    "interaction_bonus DECIMAL(5,2) DEFAULT 0 COMMENT '互动记录加分', " +
-                    "total_score DECIMAL(5,2) DEFAULT 0 COMMENT '综合得分', " +
-                    "calculated_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_q_resp_snap (snapshot_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关系问卷回答记录'");
-            log.info("已创建relationship_questionnaire_responses表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移158: family_challenge 添加 creator_id 列(用户自定义挑战)
-        ensureColumn("family_challenge", "creator_id", "BIGINT COMMENT '创建者ID(NULL=系统创建)'");
-
-        // 迁移159: guide_orders表order_no加唯一约束(防重复下单,整改R1)
-        try {
-            // 先清理历史重复数据:每组order_no保留id最小的一行
-            jdbcTemplate.execute("DELETE g1 FROM guide_orders g1 INNER JOIN guide_orders g2 " +
-                    "ON g1.order_no = g2.order_no AND g1.id > g2.id");
-            log.info("已清理guide_orders重复order_no");
-        } catch (Exception e) {
-            // 忽略:无重复数据时删除0行,不报错
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE guide_orders ADD UNIQUE KEY uk_order_no (order_no)");
-            log.info("已为guide_orders.order_no添加唯一约束");
-        } catch (Exception e) {
-            // 约束已存在,忽略
-        }
-
-        // 迁移160: payment_orders表order_no升级为唯一约束(防支付回调重复,整改R2)
-        try {
-            jdbcTemplate.execute("DELETE p1 FROM payment_orders p1 INNER JOIN payment_orders p2 " +
-                    "ON p1.order_no = p2.order_no AND p1.id > p2.id");
-            log.info("已清理payment_orders重复order_no");
-        } catch (Exception e) {
-            // 忽略
-        }
-        try {
-            // 先删除原普通索引,再加唯一索引(同名列不可并存)
-            jdbcTemplate.execute("ALTER TABLE payment_orders DROP INDEX idx_order_no");
-            jdbcTemplate.execute("ALTER TABLE payment_orders ADD UNIQUE KEY uk_order_no (order_no)");
-            log.info("已为payment_orders.order_no添加唯一约束");
-        } catch (Exception e) {
-            // 索引已存在或已处理,忽略
-        }
-
-        // 迁移161: 创建 daily_checkin 表(每日健康综合打卡,含饮食/运动/睡眠/饮水/心情评分)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS daily_checkin (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "checkin_date DATE COMMENT '打卡日期', " +
-                    "diet_score INT COMMENT '饮食评分', " +
-                    "exercise_score INT COMMENT '运动评分', " +
-                    "sleep_score INT COMMENT '睡眠评分', " +
-                    "water_intake INT COMMENT '饮水量(ml)', " +
-                    "mood_score INT COMMENT '心情评分', " +
-                    "weight_kg DECIMAL(5,2) COMMENT '体重(kg)', " +
-                    "height_cm DECIMAL(5,2) COMMENT '身高(cm)', " +
-                    "remark TEXT COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日健康打卡表'");
-            log.info("已创建daily_checkin表");
-        } catch (Exception ex) {
-            log.warn("创建daily_checkin表失败: {}", ex.getMessage());
-        }
-
-        // 迁移162: 创建 exercise_record 表(运动打卡记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS exercise_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "checkin_id BIGINT COMMENT '关联打卡ID', " +
-                    "exercise_type VARCHAR(50) COMMENT '运动类型', " +
-                    "duration_minutes INT COMMENT '时长(分钟)', " +
-                    "intensity VARCHAR(20) COMMENT '强度: low/medium/high', " +
-                    "calories_burned INT COMMENT '消耗卡路里', " +
-                    "heart_rate_avg INT COMMENT '平均心率', " +
-                    "heart_rate_max INT COMMENT '最大心率', " +
-                    "step_count INT COMMENT '微信运动步数', " +
-                    "start_time DATETIME COMMENT '开始时间', " +
-                    "end_time DATETIME COMMENT '结束时间', " +
-                    "remark TEXT COMMENT '备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运动打卡记录'");
-            log.info("已创建exercise_record表");
-        } catch (Exception ex) {
-            log.warn("创建exercise_record表失败: {}", ex.getMessage());
-        }
-
-        // 迁移163: family_challenge 添加 creator_id 列(用户自定义挑战,原迁移158在runMigration100死代码中从未执行)
-        ensureColumn("family_challenge", "creator_id", "BIGINT COMMENT '创建者ID(NULL=系统创建)'");
-
-        // 迁移164: coupon表扩展会员券字段 + 创建coupon_grant_log表(会员体系重构: 统一价+优惠券发放/积分兑换)
-        try {
-            ensureColumn("coupon", "discount_rate", "INT COMMENT '折扣券折扣率(千分比,9000=9折)'");
-            ensureColumn("coupon", "product_id", "BIGINT COMMENT '绑定商品ID,NULL=全场通用'");
-            ensureColumn("coupon", "points_price", "INT DEFAULT 0 COMMENT '积分兑换价,0=不可积分兑换'");
-            ensureColumn("coupon", "grant_type", "VARCHAR(16) COMMENT '发放规则:JOIN/PERIODIC/POPULATION,NULL=不自动发放'");
-            ensureColumn("coupon", "grant_level_code", "VARCHAR(32) COMMENT '发放规则对应会员等级'");
-            ensureColumn("coupon", "grant_period", "VARCHAR(16) COMMENT 'PERIODIC周期:MONTHLY/QUARTERLY'");
-            ensureColumn("coupon", "grant_quantity", "INT DEFAULT 1 COMMENT '每次发放数量'");
-            log.info("已为coupon表添加会员券字段");
-        } catch (Exception e) {
-            log.warn("添加coupon表会员券字段失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS coupon_grant_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '收券用户ID', " +
-                    "coupon_id BIGINT NOT NULL COMMENT '券模板ID', " +
-                    "grant_type VARCHAR(16) NOT NULL COMMENT 'JOIN/PERIODIC/POPULATION/EXCHANGE', " +
-                    "period VARCHAR(16) COMMENT '周期标识(YYYY-MM或YYYY-Qn),PERIODIC防重用', " +
-                    "quantity INT DEFAULT 1 COMMENT '发放数量', " +
-                    "source VARCHAR(64) COMMENT '触发来源(订单号/成员ID等)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_grant (user_id, coupon_id, grant_type, period), " +
-                    "INDEX idx_coupon (coupon_id), " +
-                    "INDEX idx_user (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券发放流水表'");
-            log.info("已创建coupon_grant_log表");
-        } catch (Exception e) {
-            log.warn("创建coupon_grant_log表失败: {}", e.getMessage());
-        }
-
-        // 迁移165: virtual_goods_config 添加 goods_price 列(会员道具价格,用于拆单判断)
-        ensureColumn("virtual_goods_config", "goods_price", "INT COMMENT '道具价格(分), 用于拆单判断'");
-
-        // 迁移166: payment_orders 添加 group_no/period_no 列(会员拆单支付,配置驱动拆单)
-        ensureColumn("payment_orders", "group_no", "VARCHAR(64) COMMENT '拆单组号(同一拆单组共享)'");
-        ensureColumn("payment_orders", "period_no", "INT DEFAULT 1 COMMENT '期数序号(1开始)'");
-        // 迁移167: 回填 families.creator_id(早期版本从未写入,导致会员开通/虚拟支付兜底失败)
-        // 优先 is_family_admin=true 的用户
-        try {
-            jdbcTemplate.execute("UPDATE families f JOIN users u ON f.id = u.family_id AND u.is_family_admin = 1 " +
-                    "SET f.creator_id = u.id WHERE f.creator_id IS NULL");
-            log.info("已回填families.creator_id(优先家庭管理员)");
-        } catch (Exception e) {
-            log.warn("回填families.creator_id(管理员)失败: {}", e.getMessage());
-        }
-        // 剩余家庭:任一 openid 非空用户(子查询确定性取一条)
-        try {
-            jdbcTemplate.execute("UPDATE families f SET f.creator_id = (" +
-                    "SELECT u.id FROM users u WHERE u.family_id = f.id " +
-                    "AND u.openid IS NOT NULL AND u.openid <> '' " +
-                    "ORDER BY (u.is_family_admin = 1) DESC, u.id ASC LIMIT 1" +
-                    ") WHERE f.creator_id IS NULL");
-            log.info("已回填families.creator_id(任一成员)");
-        } catch (Exception e) {
-            log.warn("回填families.creator_id(任一成员)失败: {}", e.getMessage());
-        }
-
-        // 迁移168: 修复文章表 null status 为 'draft'(旧版新建文章未设默认值导致无法编辑)
-        try {
-            jdbcTemplate.execute("UPDATE articles SET status = 'draft' WHERE status IS NULL");
-            log.info("已修复articles表中status为null的记录为draft");
-        } catch (Exception e) {
-            log.warn("修复articles表null status失败: {}", e.getMessage());
-        }
-
-        // 迁移169: 清理已废弃的 relationship_types 表(schema.sql 已移除,迁移代码中 ALTER 语句已清理)
-        try {
-            jdbcTemplate.execute("DROP TABLE IF EXISTS relationship_types");
-            log.info("已清理废弃的relationship_types表");
-        } catch (Exception e) {
-            log.warn("清理relationship_types表失败: {}", e.getMessage());
-        }
-
-        // 迁移170: 创建 family_join_requests 表(家庭加入请求待审批)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_join_requests (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "requester_user_id BIGINT NOT NULL COMMENT '申请加入的用户ID', " +
-                    "target_family_id BIGINT NOT NULL COMMENT '目标家庭ID', " +
-                    "join_method VARCHAR(20) NOT NULL COMMENT '加入方式: by_code/by_token', " +
-                    "invite_ref VARCHAR(50) COMMENT '邀请码或令牌', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected/cancelled', " +
-                    "approver_user_id BIGINT COMMENT '审批人ID', " +
-                    "comment TEXT COMMENT '审批备注', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_requester (requester_user_id), " +
-                    "INDEX idx_target_family (target_family_id), " +
-                    "INDEX idx_status (status) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭加入请求(待审批)'");
-            log.info("已创建family_join_requests表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移171: 创建 knowledge_base_section 表(统一知识库按模块存储JSON,DB为查询源,classpath种子兜底)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS knowledge_base_section (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "module_key VARCHAR(100) NOT NULL COMMENT '模块键(如 食物营养库/菌属功能库/报告指标分级标准)', " +
-                    "module_name VARCHAR(200) COMMENT '模块中文名', " +
-                    "content LONGTEXT COMMENT '模块内容(JSON序列化)', " +
-                    "version VARCHAR(50) COMMENT '数据版本(来自元数据.版本)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_module_key (module_key) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一知识库 - 按模块存储JSON'");
-            log.info("已创建knowledge_base_section表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移172: products 添加 min_stock_alert 列(库存预警阈值,配合库存管理模块)
-        // 迁移173: 商品配送与履约扩展(自取/线上服务),需求: 配送方式1=快递 2=自提 3=两者皆可 4=线上-可选人 5=线上-单人
-        // 173a: product_orders 新增履约字段
-        ensureColumn("product_orders", "pickup_location_id", "BIGINT COMMENT '自取地点ID'");
-        ensureColumn("product_orders", "pickup_location_snapshot", "TEXT COMMENT '自取地点快照(JSON)'");
-        ensureColumn("product_orders", "time_slot_id", "BIGINT COMMENT '所选时间段ID'");
-        ensureColumn("product_orders", "time_slot_snapshot", "TEXT COMMENT '时间段快照(JSON)'");
-        ensureColumn("product_orders", "service_person_id", "BIGINT COMMENT '所选服务者ID(deliveryMethod=4)'");
-        ensureColumn("product_orders", "service_person_snapshot", "TEXT COMMENT '服务者快照(JSON)'");
-        ensureColumn("product_orders", "fulfill_status", "VARCHAR(32) DEFAULT 'pending' COMMENT '履约状态: pending/confirmed_by_vendor/received_by_user/completed'");
-        ensureColumn("product_orders", "fulfill_confirmed_at", "DATETIME COMMENT '供应商确认时间'");
-        ensureColumn("product_orders", "received_at", "DATETIME COMMENT '用户确认收货时间'");
-        // 173b: 自取地点表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_pickup_locations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', " +
-                    "product_id BIGINT NOT NULL COMMENT '所属商品ID', " +
-                    "name VARCHAR(100) NOT NULL COMMENT '地点名称', " +
-                    "address VARCHAR(500) NOT NULL COMMENT '详细地址', " +
-                    "longitude DECIMAL(10,7) COMMENT '经度', " +
-                    "latitude DECIMAL(10,7) COMMENT '纬度', " +
-                    "contact_name VARCHAR(50) COMMENT '联系人', " +
-                    "contact_phone VARCHAR(20) COMMENT '联系电话', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '启用: 0/1', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product_id (product_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品自取地点'");
-            log.info("已创建product_pickup_locations表");
-        } catch (Exception ex) {
-            log.warn("创建product_pickup_locations表失败: {}", ex.getMessage());
-        }
-        // 173c: 自取时间段模板表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_pickup_time_slots (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', " +
-                    "location_id BIGINT NOT NULL COMMENT '所属地点ID', " +
-                    "start_time TIME NOT NULL COMMENT '开始时间 HH:MM', " +
-                    "end_time TIME NOT NULL COMMENT '结束时间 HH:MM', " +
-                    "weekday TINYINT COMMENT '周几(1-7), null=按具体日期', " +
-                    "specific_date DATE COMMENT '具体日期, null=按周循环', " +
-                    "max_capacity INT DEFAULT 1 COMMENT '该时段最大接待人数', " +
-                    "booked_count INT DEFAULT 0 COMMENT '已预订数', " +
-                    "enabled TINYINT DEFAULT 1, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_location_id (location_id), " +
-                    "INDEX idx_specific_date (specific_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自取时间段模板'");
-            log.info("已创建product_pickup_time_slots表");
-        } catch (Exception ex) {
-            log.warn("创建product_pickup_time_slots表失败: {}", ex.getMessage());
-        }
-        // 173d: 线上服务者表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_service_persons (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', " +
-                    "product_id BIGINT NOT NULL COMMENT '所属商品ID', " +
-                    "user_id BIGINT NOT NULL COMMENT '服务者用户ID(关联users表)', " +
-                    "name VARCHAR(50) NOT NULL COMMENT '展示名称', " +
-                    "title VARCHAR(100) COMMENT '头衔(如高级营养师)', " +
-                    "intro TEXT COMMENT '个人介绍', " +
-                    "avatar VARCHAR(500) COMMENT '头像URL', " +
-                    "price INT NOT NULL COMMENT '该人专属价格(分)', " +
-                    "original_price INT COMMENT '原价(分)', " +
-                    "sort_order INT DEFAULT 0, " +
-                    "enabled TINYINT DEFAULT 1, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product_id (product_id), " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品线上服务者'");
-            log.info("已创建product_service_persons表");
-        } catch (Exception ex) {
-            log.warn("创建product_service_persons表失败: {}", ex.getMessage());
-        }
-        // 173e: 服务者可预约时间段表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_service_person_slots (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', " +
-                    "person_id BIGINT NOT NULL COMMENT '所属服务者ID', " +
-                    "start_time DATETIME NOT NULL COMMENT '开始时间', " +
-                    "end_time DATETIME NOT NULL COMMENT '结束时间', " +
-                    "max_capacity INT DEFAULT 1 COMMENT '容量', " +
-                    "booked_count INT DEFAULT 0 COMMENT '已预订数', " +
-                    "enabled TINYINT DEFAULT 1, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_person_id (person_id), " +
-                    "INDEX idx_start_time (start_time)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务者可预约时间段'");
-            log.info("已创建product_service_person_slots表");
-        } catch (Exception ex) {
-            log.warn("创建product_service_person_slots表失败: {}", ex.getMessage());
-        }
-        // 173f: 单人线上服务时间段表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_online_slots (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', " +
-                    "product_id BIGINT NOT NULL COMMENT '所属商品ID', " +
-                    "start_time DATETIME NOT NULL COMMENT '开始时间', " +
-                    "end_time DATETIME NOT NULL COMMENT '结束时间', " +
-                    "max_capacity INT DEFAULT 1 COMMENT '容量', " +
-                    "booked_count INT DEFAULT 0 COMMENT '已预订数', " +
-                    "enabled TINYINT DEFAULT 1, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_product_id (product_id), " +
-                    "INDEX idx_start_time (start_time)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='单人线上服务时间段'");
-            log.info("已创建product_online_slots表");
-        } catch (Exception ex) {
-            log.warn("创建product_online_slots表失败: {}", ex.getMessage());
-        }
-
-        // 迁移166: 创建 membership_benefits 表(会员权益配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS membership_benefits (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "level_code VARCHAR(50) NOT NULL COMMENT '会员等级: FREE/PROFESSIONAL/ENTERPRISE', " +
-                    "benefit_code VARCHAR(50) NOT NULL COMMENT '权益编码: AI_CHAT,FAMILY_MEMBERS等', " +
-                    "benefit_name VARCHAR(100) NOT NULL COMMENT '权益名称', " +
-                    "benefit_desc VARCHAR(500) COMMENT '权益描述', " +
-                    "icon VARCHAR(50) COMMENT '图标emoji', " +
-                    "bg_color VARCHAR(20) COMMENT '背景色', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序顺序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_level_benefit (level_code, benefit_code), " +
-                    "INDEX idx_level (level_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员权益配置'");
-            log.info("已创建membership_benefits表");
-        } catch (Exception ex) {
-            log.warn("创建membership_benefits表失败: {}", ex.getMessage());
-        }
-
-        // 迁移167: membership_benefits 种子数据
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES " +
-                    "('FREE', 'NO_BENEFIT', '暂无会员权益', '开通会员解锁更多权益', '🔒', '#F3F4F6', 0), " +
-                    "('FREE', 'UPGRADE_HINT', '升级会员', '开通会员享专属权益', '👑', '#FEF3C7', 99), " +
-                    "('FAMILY', 'AI_CHAT', 'AI 健康顾问', '7×24 小时不限次数问答', '🤖', '#DBEAFE', 1), " +
-                    "('FAMILY', 'FAMILY_MEMBERS', '家庭档案管理', '管理最多 10 位家庭成员', '👨‍👩‍👧‍👦', '#D1FAE5', 2), " +
-                    "('FAMILY', 'HEALTH_PLAN', '月度健康计划', '个性化健康改善方案', '📋', '#FEF3C7', 3), " +
-                    "('FAMILY', 'REPORT_READING', '报告智能解读', '体检/菌群/测评报告 AI 解读', '📊', '#FCE7F3', 4), " +
-                    "('FAMILY', 'MANAGER_SERVICE', '专属健康教练服务', '认证健康教练月度随访', '👨‍🏫', '#FFEDD5', 5), " +
-                    "('FAMILY', 'PRODUCT_DISCOUNT', '商品会员折扣', '全场商品 8-9 折优惠', '🛒', '#E0E7FF', 6), " +
-                    "('FAMILY', 'COUPON_ACCESS', '优惠券使用权限', '可使用平台优惠券享更多优惠', '🎫', '#FEE2E2', 7), " +
-                    "('PREMIUM', 'AI_CHAT', 'AI 健康顾问', '7×24 小时不限次数问答', '🤖', '#DBEAFE', 1), " +
-                    "('PREMIUM', 'FAMILY_MEMBERS', '家庭档案管理', '管理最多 20 位家庭成员', '👨‍👩‍👧‍👦', '#D1FAE5', 2), " +
-                    "('PREMIUM', 'HEALTH_PLAN', '月度健康计划', '个性化健康改善方案 + 定制营养建议', '📋', '#FEF3C7', 3), " +
-                    "('PREMIUM', 'REPORT_READING', '报告智能解读', '体检/菌群/测评报告 AI 深度解读', '📊', '#FCE7F3', 4), " +
-                    "('PREMIUM', 'MANAGER_SERVICE', '专属健康教练服务', '每周 1 次电话随访 + 在线答疑', '👨‍🏫', '#FFEDD5', 5), " +
-                    "('PREMIUM', 'PRODUCT_DISCOUNT', '商品会员折扣', '全场商品 6-8 折优惠', '🛒', '#E0E7FF', 6), " +
-                    "('PREMIUM', 'COUPON_ACCESS', '优惠券使用权限', '可使用平台优惠券 + 会员专属券', '🎫', '#FEE2E2', 7), " +
-                    "('PREMIUM', 'PRIORITY_SUPPORT', '优先客服', '专属客服通道,快速响应', '🎧', '#EDE9FE', 8), " +
-                    "('PREMIUM', 'TEACHER_CONSULT', '规划师一对一咨询', '每月 1 次成长规划师专业咨询', '👩‍🏫', '#FBCFE8', 9)");
-            log.info("已插入membership_benefits种子数据");
-        } catch (Exception ex) {
-            log.warn("插入membership_benefits种子数据失败: {}", ex.getMessage());
-        }
-
-        // 迁移168: 创建用户同意记录表(法律合规)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_consent_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "consent_type VARCHAR(50) NOT NULL COMMENT '同意类型: privacy/agreement/children_data/ai_processing', " +
-                    "version VARCHAR(20) NOT NULL COMMENT '协议版本号', " +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'agreed' COMMENT 'agreed/withdrawn/archived', " +
-                    "ip_address VARCHAR(45) COMMENT '用户IP地址', " +
-                    "created_at DATETIME NOT NULL, " +
-                    "updated_at DATETIME, " +
-                    "INDEX idx_user_consent (user_id, consent_type), " +
-                    "INDEX idx_consent_type (consent_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户同意记录'");
-            log.info("已创建user_consent_records表");
-        } catch (Exception e) {
-            log.warn("创建user_consent_records表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移169: 创建用户数据授权表(法律合规)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_data_permissions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "allow_ai_analysis TINYINT(1) DEFAULT 0 COMMENT '允许AI分析对话数据', " +
-                    "allow_personalized_recommend TINYINT(1) DEFAULT 1 COMMENT '允许个性化推荐', " +
-                    "allow_share_teacher TINYINT(1) DEFAULT 1 COMMENT '允许向成长规划师共享数据', " +
-                    "allow_third_party_share TINYINT(1) DEFAULT 0 COMMENT '允许与第三方共享数据', " +
-                    "created_at DATETIME NOT NULL, " +
-                    "updated_at DATETIME, " +
-                    "INDEX idx_user_perm (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户数据使用授权'");
-            log.info("已创建user_data_permissions表");
-        } catch (Exception e) {
-            log.warn("创建user_data_permissions表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移174: family_members 添加饮食相关字段(饮食模块需求)
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN is_living_together TINYINT(1) DEFAULT 1 COMMENT '是否同住(0=不同住,不出现在食谱推荐中)'");
-            log.info("已添加is_living_together列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 is_living_together 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_breakfast_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日早餐同餐'");
-            log.info("已添加meal_with_breakfast_weekday列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_breakfast_weekday 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_lunch_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日午餐同餐'");
-            log.info("已添加meal_with_lunch_weekday列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_lunch_weekday 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_dinner_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日晚餐同餐'");
-            log.info("已添加meal_with_dinner_weekday列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_dinner_weekday 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_breakfast_weekend TINYINT(1) DEFAULT 0 COMMENT '周末早餐同餐'");
-            log.info("已添加meal_with_breakfast_weekend列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_breakfast_weekend 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_lunch_weekend TINYINT(1) DEFAULT 0 COMMENT '周末午餐同餐'");
-            log.info("已添加meal_with_lunch_weekend列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_lunch_weekend 列失败(可能已存在): " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_members ADD COLUMN meal_with_dinner_weekend TINYINT(1) DEFAULT 0 COMMENT '周末晚餐同餐'");
-            log.info("已添加meal_with_dinner_weekend列到family_members表");
-        } catch (Exception e) {
-            log.warn("family_members 添加 meal_with_dinner_weekend 列失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移175: 创建 diet_preferences 表(饮食偏好调研表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS diet_preferences (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_member_id BIGINT NOT NULL COMMENT '绑定家庭成员', " +
-                    "allergies JSON COMMENT '过敏原列表', " +
-                    "absolute_avoid JSON COMMENT '绝对忌口列表', " +
-                    "must_eat JSON COMMENT '必吃食物列表', " +
-                    "religious_diet VARCHAR(50) DEFAULT 'none' COMMENT '宗教饮食', " +
-                    "spice_level TINYINT DEFAULT NULL COMMENT '辣度 0-5', " +
-                    "flavor_pref JSON COMMENT '口味偏好', " +
-                    "cuisine_pref JSON COMMENT '菜系偏好', " +
-                    "cooking_methods JSON COMMENT '烹饪方式偏好', " +
-                    "health_goals JSON COMMENT '健康目标', " +
-                    "goal_source VARCHAR(20) DEFAULT NULL COMMENT 'manual/system_recommend', " +
-                    "goal_confirmed TINYINT(1) DEFAULT 0 COMMENT '用户已确认', " +
-                    "filled_at TIMESTAMP NULL COMMENT '首次填写时间', " +
-                    "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_member (family_member_id), " +
-                    "INDEX idx_updated (updated_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食偏好调研表'");
-            log.info("已创建diet_preferences表");
-        } catch (Exception e) {
-            log.warn("创建 diet_preferences 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移176: 创建 meal_configs 表(共餐配置表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS meal_configs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "config_date_type VARCHAR(20) NOT NULL COMMENT '工作日/周末/节假日', " +
-                    "meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner', " +
-                    "participant_member_ids JSON NOT NULL COMMENT '参与成员ID列表', " +
-                    "notes VARCHAR(255) DEFAULT NULL COMMENT '备注', " +
-                    "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_config (family_id, config_date_type, meal_type), " +
-                    "INDEX idx_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共餐配置表'");
-            log.info("已创建meal_configs表");
-        } catch (Exception e) {
-            log.warn("创建 meal_configs 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移177: 创建 diet_recommendations 表(食谱推荐方案表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS diet_recommendations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "recommendation_date DATE NOT NULL COMMENT '推荐日期', " +
-                    "meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner', " +
-                    "participant_member_ids JSON COMMENT '参与成员ID列表', " +
-                    "menu_json MEDIUMTEXT NOT NULL COMMENT '菜品列表JSON', " +
-                    "nutrition_summary JSON COMMENT '营养汇总', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/accepted/adjusted/completed/skipped', " +
-                    "version INT DEFAULT 1 COMMENT '版本号', " +
-                    "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_family_date (family_id, recommendation_date), " +
-                    "INDEX idx_meal (meal_type, recommendation_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱推荐方案表'");
-            log.info("已创建diet_recommendations表");
-        } catch (Exception e) {
-            log.warn("创建 diet_recommendations 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移178: 创建 diet_records 表(饮食记录表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS diet_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '吃的成员ID', " +
-                    "meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner/snack', " +
-                    "record_date DATE NOT NULL COMMENT '记录日期', " +
-                    "record_method VARCHAR(20) DEFAULT NULL COMMENT 'photo/manual/from_recommendation', " +
-                    "image_url VARCHAR(500) DEFAULT NULL COMMENT '原图OSS路径', " +
-                    "ai_recognized_foods JSON DEFAULT NULL COMMENT 'AI识别结果', " +
-                    "user_confirmed_foods JSON NOT NULL COMMENT '用户最终确认食材', " +
-                    "notes VARCHAR(500) DEFAULT NULL COMMENT '备注', " +
-                    "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_date (member_id, record_date), " +
-                    "INDEX idx_family_date (family_id, record_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食记录表'");
-            log.info("已创建diet_records表");
-        } catch (Exception e) {
-            log.warn("创建 diet_records 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移179: 创建 diet_record_items 表(饮食记录食材明细表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS diet_record_items (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "record_id BIGINT NOT NULL COMMENT 'diet_records.id', " +
-                    "food_name VARCHAR(100) NOT NULL COMMENT '食材名称', " +
-                    "food_id BIGINT DEFAULT NULL COMMENT '关联foods表ID', " +
-                    "confidence DECIMAL(3,2) DEFAULT NULL COMMENT 'AI置信度0-1', " +
-                    "source VARCHAR(20) DEFAULT NULL COMMENT 'ai_recognized/manual/from_recommendation', " +
-                    "INDEX idx_record (record_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食记录食材明细表'");
-            log.info("已创建diet_record_items表");
-        } catch (Exception e) {
-            log.warn("创建 diet_record_items 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移180: health_reports 添加代上传字段(规划师/营养师代用户提交报告,修复 Unknown column 'proxy_uploader_id' 错误)
-        ensureColumn("health_reports", "proxy_uploader_id", "BIGINT COMMENT '代上传人ID(规划师/营养师)'");
-        ensureColumn("health_reports", "proxy_upload_note", "TEXT COMMENT '代上传备注'");
-        ensureColumn("health_reports", "ai_analysis", "TEXT COMMENT 'AI解读结果JSON'");
-        // 迁移180b: health_reports 添加报告来源格式(beijing/guhe,两种菌群报告数据结构不兼容,需区分)
-        ensureColumn("health_reports", "report_format", "VARCHAR(32) COMMENT '报告来源格式: beijing(北京菌群)/guhe(谷禾)'");
-
-        // 迁移181: health_report_drafts 添加备注字段(代上传说明文字)
-        ensureColumn("health_report_drafts", "remark", "VARCHAR(500) DEFAULT NULL COMMENT '备注(如代上传时的说明文字)'");
-
-        // 迁移182: 创建 family_challenge_participant 表(挑战参与成员,任意成员发起/可选参与)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_challenge_participant (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "challenge_id BIGINT NOT NULL COMMENT '挑战ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '家庭成员ID', " +
-                    "status VARCHAR(20) NOT NULL COMMENT 'pending/agreed/rejected', " +
-                    "agreed_at DATETIME NULL COMMENT '同意/拒绝时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_challenge_member (challenge_id, member_id), " +
-                    "INDEX idx_member (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战参与成员'");
-            log.info("已创建family_challenge_participant表");
-        } catch (Exception e) {
-            log.warn("创建 family_challenge_participant 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移183: 创建 family_relationship_scores 表(方向性关系分数,A对B ≠ B对A)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_relationship_scores (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "from_member_id BIGINT NOT NULL COMMENT '分数持有方(A对B的行)', " +
-                    "to_member_id BIGINT NOT NULL COMMENT '分数对象方', " +
-                    "trust_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的信任', " +
-                    "intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的亲近', " +
-                    "communication_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的沟通', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_from_to (from_member_id, to_member_id), " +
-                    "INDEX idx_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='方向性关系分数'");
-            log.info("已创建family_relationship_scores表");
-        } catch (Exception e) {
-            log.warn("创建 family_relationship_scores 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移184: 创建 family_challenge_score_config 表(挑战评分配置,后台可配置)+ 默认数据
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_challenge_score_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "action VARCHAR(20) NOT NULL COMMENT 'initiate/agree/reject', " +
-                    "score_type VARCHAR(20) NOT NULL COMMENT 'energy/trust/intimacy/communication', " +
-                    "value INT NOT NULL DEFAULT 0 COMMENT '增减值(可正可负,默认±1)', " +
-                    "enabled TINYINT DEFAULT 1, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_action_type (action, score_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战评分配置'");
-            jdbcTemplate.execute("INSERT IGNORE INTO family_challenge_score_config (action, score_type, value, enabled) VALUES " +
-                    "('initiate','energy',1,1),('initiate','trust',0,1),('initiate','intimacy',1,1),('initiate','communication',1,1)," +
-                    "('agree','energy',1,1),('agree','trust',1,1),('agree','intimacy',1,1),('agree','communication',1,1)," +
-                    "('reject','energy',-1,1),('reject','trust',-1,1),('reject','intimacy',-1,1),('reject','communication',1,1)");
-            log.info("已创建family_challenge_score_config表并写入默认配置");
-        } catch (Exception e) {
-            log.warn("创建 family_challenge_score_config 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移185: 存量挑战补全 participant 行(全员 agreed,兼容旧数据,不破坏)
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO family_challenge_participant (challenge_id, member_id, status, agreed_at) " +
-                    "SELECT fc.id, fm.id, 'agreed', NOW() FROM family_challenge fc " +
-                    "JOIN family_members fm ON fm.family_id = fc.family_id " +
-                    "WHERE NOT EXISTS (SELECT 1 FROM family_challenge_participant fcp WHERE fcp.challenge_id = fc.id)");
-            log.info("已为存量挑战补全participant行");
-        } catch (Exception e) {
-            log.warn("存量挑战补全participant失败(可能已处理): " + e.getMessage());
-        }
-
-        // ===== 报告指纹检测与解析器调度系统 =====
-
-        // 迁移186: 创建 report_type_registry 表(报告类型注册表)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_type_registry (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "type_id VARCHAR(64) NOT NULL COMMENT '类型标识,如 dan_a1/gut_beijing', " +
-                    "family VARCHAR(32) DEFAULT NULL COMMENT '报告家族: dan/gut_flora/其他', " +
-                    "display_name VARCHAR(100) NOT NULL COMMENT '显示名称', " +
-                    "description VARCHAR(500) DEFAULT NULL COMMENT '描述', " +
-                    "parser_path VARCHAR(255) DEFAULT NULL COMMENT 'Python解析器脚本路径', " +
-                    "min_confidence INT DEFAULT 10 COMMENT '识别阈值', " +
-                    "is_active TINYINT(1) DEFAULT 1 COMMENT '启用状态', " +
-                    "source VARCHAR(20) DEFAULT 'prebuilt' COMMENT '来源: prebuilt/imported/auto_generated', " +
-                    "review_status VARCHAR(20) DEFAULT 'approved' COMMENT '审核状态: approved/pending/rejected', " +
-                    "version VARCHAR(20) DEFAULT '1.0' COMMENT '版本', " +
-                    "created_by BIGINT DEFAULT NULL COMMENT '创建人ID', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_type_id (type_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告类型注册表'");
-            log.info("已创建report_type_registry表");
-        } catch (Exception e) {
-            log.warn("创建 report_type_registry 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移187: 创建 report_fingerprint 表(指纹规则)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_fingerprint (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "type_id VARCHAR(64) NOT NULL COMMENT '关联report_type_registry.type_id', " +
-                    "pattern VARCHAR(200) NOT NULL COMMENT '文本特征', " +
-                    "weight INT DEFAULT 10 COMMENT '权重(正=加分,负=排除扣分)', " +
-                    "is_exclusion TINYINT(1) DEFAULT 0 COMMENT '是否为排除规则', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_fp_type (type_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告指纹规则表'");
-            log.info("已创建report_fingerprint表");
-        } catch (Exception e) {
-            log.warn("创建 report_fingerprint 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移188: 创建 report_unknown_cluster 表(未知报告聚类,自学习用)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_unknown_cluster (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "cluster_key VARCHAR(64) NOT NULL COMMENT '聚类哈希键(同类报告分组)', " +
-                    "common_signatures TEXT COMMENT '公共文本特征JSON(用于生成指纹)', " +
-                    "llm_template TEXT COMMENT 'LLM解析结果模板JSON', " +
-                    "report_count INT DEFAULT 0 COMMENT '累计报告数', " +
-                    "status VARCHAR(20) DEFAULT 'collecting' COMMENT '状态: collecting/ready/generated/imported', " +
-                    "generated_type_id VARCHAR(64) DEFAULT NULL COMMENT '生成的类型ID', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_cluster_key (cluster_key)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='未知报告聚类表'");
-            log.info("已创建report_unknown_cluster表");
-        } catch (Exception e) {
-            log.warn("创建 report_unknown_cluster 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移189: 创建 report_unknown_upload 表(未知报告明细)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_unknown_upload (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "cluster_id BIGINT DEFAULT NULL COMMENT '关联report_unknown_cluster.id', " +
-                    "file_url VARCHAR(500) DEFAULT NULL COMMENT '文件路径', " +
-                    "file_hash VARCHAR(64) DEFAULT NULL COMMENT '文件哈希', " +
-                    "llm_result TEXT COMMENT 'LLM解析结果JSON', " +
-                    "uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_unknown_cluster (cluster_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='未知报告上传明细表'");
-            log.info("已创建report_unknown_upload表");
-        } catch (Exception e) {
-            log.warn("创建 report_unknown_upload 表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移190: 创建 report_parser_import 表(外部导入记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_parser_import (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "package_name VARCHAR(100) NOT NULL COMMENT '导入包名称', " +
-                    "package_file_url VARCHAR(500) DEFAULT NULL COMMENT '导入包文件路径', " +
-                    "fingerprint_json TEXT COMMENT '指纹规则JSON', " +
-                    "parser_script TEXT COMMENT '解析器脚本内容', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected', " +
-                    "imported_by BIGINT DEFAULT NULL COMMENT '导入人ID', " +
-                    "reviewed_by BIGINT DEFAULT NULL COMMENT '审核人ID', " +
-                    "review_note VARCHAR(500) DEFAULT NULL COMMENT '审核意见', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告解析器导入记录表'");
-            log.info("已创建report_parser_import表");
-        } catch (Exception e) {
-            log.warn("创建 report_parser_import 表失败(可能已存在): " + e.getMessage());
-        }
-
-// 迁移191: foods 添加 report_id/score 列(Food 实体已含字段,生产库缺列导致 Unknown column 'report_id' 错误)
-        ensureColumn("foods", "report_id", "BIGINT DEFAULT NULL COMMENT '关联报告ID(从PDF解析的食物推荐)'");
-        ensureColumn("foods", "score", "INT DEFAULT NULL COMMENT '食物评分'");
-
-		// 迁移263: foods 补齐 energy_kj/starch/cholesterol/diet_type 列(前三列原迁移在文件重组时丢失、生产靠历史执行残留;
-		//   dietType 为实体孤立字段从未建列,MyBatis-Plus 全字段 SELECT 报 Unknown column)
-		ensureColumn("foods", "energy_kj", "DECIMAL(8,2) DEFAULT NULL COMMENT '能量(kJ/100g)'");
-		ensureColumn("foods", "starch", "DECIMAL(8,2) DEFAULT NULL COMMENT '淀粉(g/100g)'");
-		ensureColumn("foods", "cholesterol", "DECIMAL(8,2) DEFAULT NULL COMMENT '胆固醇(mg/100g)'");
-		ensureColumn("foods", "diet_type", "VARCHAR(50) DEFAULT NULL COMMENT '饮食类型'");
-
-		// 迁移192: verification_codes.type 添加默认值(旧版插入未携带 type 字段,DB 列 NOT NULL 无默认值导致报错)
-		try {
-			jdbcTemplate.execute("ALTER TABLE verification_codes MODIFY COLUMN `type` VARCHAR(20) NOT NULL DEFAULT 'login' COMMENT '验证码类型: login/register/reset'");
-			log.info("已为verification_codes.type添加默认值");
-		} catch (Exception e) {
-			log.warn("verification_codes.type 默认值修改失败(可能已修改): " + e.getMessage());
-		}
-
-        // 迁移193: family_relationships表添加关系质量评分三列(关系条展示增强)
-        ensureColumn("family_relationships", "trust_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '信任度(答卷人视角)'");
-        ensureColumn("family_relationships", "intimacy_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度(答卷人视角)'");
-        ensureColumn("family_relationships", "communication_score", "DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量(答卷人视角)'");
-
-        // 迁移194: family_join_requests 添加 family_role 列(保存申请人角色)
-        ensureColumn("family_join_requests", "family_role", "VARCHAR(20) DEFAULT NULL COMMENT '申请人在家庭中的角色:爸爸/妈妈/爷爷/奶奶等'");
-
-        // 迁移195: tasks 表新增 accept_deadline 列 + 扩展 status 枚举(支持 assigned/in_progress/rejected)
-        ensureColumn("tasks", "accept_deadline", "DATETIME DEFAULT NULL COMMENT '接受截止时间(分配给其他家庭成员的任务)'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks MODIFY COLUMN `status` ENUM('pending','assigned','in_progress','completed','rejected','overdue','cancelled') DEFAULT 'pending' COMMENT '状态: pending=待审核 assigned=待接受 in_progress=进行中 completed=已完成 rejected=已拒绝 overdue=已过期 cancelled=已取消'");
-            log.info("已更新tasks.status枚举值");
-        } catch (Exception e) {
-            log.warn("tasks.status枚举修改失败(可能已修改): " + e.getMessage());
-        }
-
-        // 迁移196: 创建 user_platform_balance 表(CF值余额)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_platform_balance (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "family_id BIGINT COMMENT '归属家庭ID', " +
-                    "total_earned INT DEFAULT 0 COMMENT '累计获得', " +
-                    "available INT DEFAULT 0 COMMENT '可用余额', " +
-                    "frozen INT DEFAULT 0 COMMENT '冻结(提现审核中)', " +
-                    "withdrawn INT DEFAULT 0 COMMENT '已提现', " +
-                    "exchanged INT DEFAULT 0 COMMENT '已兑换', " +
-                    "updated_at DATETIME, " +
-                    "created_at DATETIME, " +
-                    "UNIQUE KEY uk_user (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户CF值余额'");
-            log.info("已创建user_platform_balance表");
-        } catch (Exception e) {
-            log.warn("创建user_platform_balance表失败: " + e.getMessage());
-        }
-
-        // 迁移197: 创建 platform_balance_log 表(CF值流水)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS platform_balance_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "family_id BIGINT COMMENT '归属家庭ID', " +
-                    "type VARCHAR(20) NOT NULL COMMENT 'earn/spend/freeze/unfreeze/withdraw', " +
-                    "amount INT NOT NULL COMMENT '变动数量', " +
-                    "balance_after INT NOT NULL COMMENT '变动后可用余额', " +
-                    "ref_type VARCHAR(30) COMMENT 'product_order/activity/withdrawal/migration', " +
-                    "ref_id BIGINT COMMENT '关联业务ID', " +
-                    "remark VARCHAR(255) COMMENT '备注', " +
-                    "created_at DATETIME, " +
-                    "INDEX idx_user_time (user_id, created_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流水'");
-            log.info("已创建platform_balance_log表");
-        } catch (Exception e) {
-            log.warn("创建platform_balance_log表失败: " + e.getMessage());
-        }
-
-        // 迁移198: 存量佣金迁移为CF值(settled→available, pending→frozen)
-        try {
-            jdbcTemplate.execute("INSERT INTO user_platform_balance (user_id, total_earned, available, created_at, updated_at) " +
-                    "SELECT referrer_id, SUM(commission_amount), SUM(commission_amount), NOW(), NOW() " +
-                    "FROM commission_records WHERE status='settled' GROUP BY referrer_id " +
-                    "ON DUPLICATE KEY UPDATE available=available+VALUES(available), " +
-                    "total_earned=total_earned+VALUES(total_earned), updated_at=NOW()");
-            log.info("已迁移settled佣金为可用CF值");
-        } catch (Exception e) {
-            log.warn("迁移settled佣金失败: " + e.getMessage());
-        }
-
-        // 迁移199: pending 佣金 → 冻结CF
-        try {
-            jdbcTemplate.execute("INSERT INTO user_platform_balance (user_id, total_earned, frozen, created_at, updated_at) " +
-                    "SELECT referrer_id, SUM(commission_amount), SUM(commission_amount), NOW(), NOW() " +
-                    "FROM commission_records WHERE status='pending' GROUP BY referrer_id " +
-                    "ON DUPLICATE KEY UPDATE frozen=frozen+VALUES(frozen), " +
-                    "total_earned=total_earned+VALUES(total_earned), updated_at=NOW()");
-            log.info("已迁移pending佣金为冻结CF值");
-        } catch (Exception e) {
-            log.warn("迁移pending佣金失败: " + e.getMessage());
-        }
-
-        // 迁移200: activities表添加platform_points字段
-        ensureColumn("activities", "platform_points", "INT DEFAULT 0 COMMENT '活动奖励CF值(0=不发)'");
-
-        // 迁移201: 新增CF值配置项
-        insertSysConfigSeed("product_platform_points_share", "1000", "商品CF值利润分成比例(bps)");
-        insertSysConfigSeed("platform_withdraw_rate", "100", "CF值提现汇率(CF数/元)");
-
-        // 迁移202: withdrawal_requests表添加 type 字段(提现来源)
-        ensureColumn("withdrawal_requests", "type", "VARCHAR(20) DEFAULT 'platform_points' COMMENT '提现来源: platform_points(CF值) / commission(历史佣金)'");
-
-// 迁移203: membership_levels 添加原价字段(LIFETIME 需求:价格来源统一迁移至表内)
-        ensureColumn("membership_levels", "original_price_monthly", "INT NULL COMMENT '原价-月费(分)'");
-        ensureColumn("membership_levels", "original_price_quarterly", "INT NULL COMMENT '原价-季费(分)'");
-        ensureColumn("membership_levels", "original_price_yearly", "INT NULL COMMENT '原价-年费(分)'");
-
-        // 迁移203.1: 幂等数据同步(sys_config 原价/现值 → membership_levels,仅当表内为 0/NULL 时)
-        try {
-            // FAMILY 原价年费(sys_config member_fee_family_original_yearly / member_fee_family_original,默认 199900)
-            jdbcTemplate.update("UPDATE membership_levels SET original_price_yearly = 199900 " +
-                    "WHERE level_code = 'FAMILY' AND (original_price_yearly IS NULL OR original_price_yearly = 0)");
-            // PREMIUM 原价年费/月费(sys_config member_fee_premium_original / member_fee_premium_original_monthly)
-            jdbcTemplate.update("UPDATE membership_levels SET original_price_yearly = 1599900, original_price_monthly = 159900 " +
-                    "WHERE level_code = 'PREMIUM' AND (original_price_yearly IS NULL OR original_price_yearly = 0)");
-            // FAMILY 现价补齐(现值 13140/32850/131400)
-            jdbcTemplate.update("UPDATE membership_levels SET price_monthly = 13140, price_quarterly = 32850, price_yearly = 131400 " +
-                    "WHERE level_code = 'FAMILY' AND (price_yearly IS NULL OR price_yearly = 0)");
-            // PREMIUM 现价补齐(现值 131400/1316800;季费保持 NULL=不支持)
-            jdbcTemplate.update("UPDATE membership_levels SET price_monthly = 131400, price_yearly = 1316800 " +
-                    "WHERE level_code = 'PREMIUM' AND (price_yearly IS NULL OR price_yearly = 0)");
-            log.info("已同步会员价格/原价至membership_levels");
-        } catch (Exception e) {
-            log.warn("同步membership_levels价格失败: {}", e.getMessage());
-        }
-
-        // 迁移204: 插入 LIFETIME 终身会员等级行(不可购买,仅管理员授予,价格全 0)
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_levels " +
-                    "(level_code, level_name, level_desc, price_monthly, price_quarterly, price_yearly, " +
-                    "original_price_monthly, original_price_quarterly, original_price_yearly, " +
-                    "features, max_children, max_tasks_per_day, ai_review_enabled, priority_support, teacher_consultation) VALUES " +
-                    "('LIFETIME', '终身会员', '终身家庭会员权益,永久有效无需续费', 0, 0, 0, 0, 0, 0, " +
-                    "'[\"free_activities\",\"free_courses\",\"full_price_purchase\",\"referral_commission\"," +
-                    "\"discount_purchase\",\"member_activities\",\"create_family\",\"invite_family\",\"purchase_commission\"]', " +
-                    "6, 20, 1, 1, 1)");
-            log.info("已插入LIFETIME等级种子数据");
-        } catch (Exception e) {
-            log.warn("插入LIFETIME等级种子数据失败: {}", e.getMessage());
-        }
-
-        // 迁移205: 创建平台公告表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS notices (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "title VARCHAR(200) NOT NULL COMMENT '公告标题', " +
-                            "content TEXT NOT NULL COMMENT '公告内容', " +
-                            "type VARCHAR(20) DEFAULT 'platform' COMMENT '类型: platform=平台公告 activity=活动 promotion=优惠', " +
-                            "status VARCHAR(20) DEFAULT 'active' COMMENT '状态: draft=草稿 active=已发布 deleted=已删除', " +
-                            "admin_id BIGINT DEFAULT NULL COMMENT '发布管理员ID', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='平台公告'"
-            );
-            log.info("已创建notices表");
-        } catch (Exception e) {
-            log.warn("创建notices表失败: " + e.getMessage());
-        }
-
-        // 迁移206: member_upgrade_records 添加审批字段(LIFETIME 授予审批需求,修复升级记录查询 Unknown column 500)
-        ensureColumn("member_upgrade_records", "approve_remark", "VARCHAR(500) DEFAULT NULL COMMENT '审批备注'");
-        ensureColumn("member_upgrade_records", "approve_status", "VARCHAR(20) DEFAULT 'approved' COMMENT '审批状态: approved/rejected'");
-        ensureColumn("member_upgrade_records", "approve_user_id", "BIGINT DEFAULT NULL COMMENT '审批人ID'");
-        ensureColumn("member_upgrade_records", "approve_time", "DATETIME DEFAULT NULL COMMENT '审批时间'");
-
-        // 迁移207: 创建 health_plans 表(健康方案汇总记录)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS health_plans (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                            "member_ids VARCHAR(200) NOT NULL COMMENT '目标成员ID列表(逗号分隔)', " +
-                            "dimensions VARCHAR(100) NOT NULL COMMENT '维度列表(逗号分隔)', " +
-                            "goal TEXT NOT NULL COMMENT '用户输入的目标', " +
-                            "plan_content TEXT COMMENT 'LangGraph生成的方案内容', " +
-                            "member_name VARCHAR(50) COMMENT '成员名称摘要', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "INDEX idx_family (family_id), " +
-                            "INDEX idx_created (created_at)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康方案汇总记录'"
-            );
-            log.info("已创建health_plans表");
-        } catch (Exception e) {
-            log.warn("创建health_plans表失败(可能已存在): " + e.getMessage());
-        }
-
-        // 迁移208: health_gut_flora.detection_rate 列扩容(VARCHAR(50)→VARCHAR(255),源数据超长导致 MysqlDataTruncation)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora MODIFY COLUMN detection_rate VARCHAR(255) DEFAULT NULL COMMENT '检出率'");
-            log.info("health_gut_flora.detection_rate 已扩容为 VARCHAR(255)");
-        } catch (Exception e) {
-            log.warn("health_gut_flora.detection_rate 扩容失败(可能已修改): " + e.getMessage());
-        }
-
-        // 迁移225: articles 添加 growth_category 列(成长分类筛选,Article 实体已含字段,生产库缺列导致 Unknown column 'growth_category')
-        ensureColumn("articles", "growth_category", "VARCHAR(50) DEFAULT NULL COMMENT '成长分类'");
-
-        // 迁移209: 将 ecom_supplier 合并至 supply_system(商品供应商管理 → 供应商体系管理统一)
-        // 1. 给 supply_system 加联系人字段
-        ensureColumn("supply_system", "contact_name", "VARCHAR(50) DEFAULT NULL COMMENT '联系人'");
-        ensureColumn("supply_system", "contact_phone", "VARCHAR(20) DEFAULT NULL COMMENT '联系电话'");
-        ensureColumn("supply_system", "remark", "VARCHAR(500) DEFAULT NULL COMMENT '备注'");
-        log.info("迁移209: supply_system 已添加 contact_name/contact_phone/remark 列");
-
-        // 2. 将 ecom_supplier 存量数据迁移到 supply_system(以平台管理员 id=1 为默认 admin)
-        try {
-            jdbcTemplate.update(
-                    "INSERT INTO supply_system (name, admin_id, settlement_period_days, platform_profit_rate, status, " +
-                            "contact_name, contact_phone, remark, created_at, updated_at) " +
-                            "SELECT name, 1, 30, 0, " +
-                            "CASE WHEN status = 1 THEN 'active' ELSE 'disabled' END, " +
-                            "contact_name, contact_phone, remark, created_at, COALESCE(updated_at, created_at) " +
-                            "FROM ecom_supplier WHERE NOT EXISTS (" +
-                            "  SELECT 1 FROM supply_system ss WHERE ss.name = ecom_supplier.name LIMIT 1)"
-            );
-            log.info("迁移209: ecom_supplier 存量数据已迁移至 supply_system");
-        } catch (Exception e) {
-            log.warn("迁移209: ecom_supplier 迁移失败(可能已存在): {}", e.getMessage());
-        }
-    }
-
-    private void runFullRegionDataMigrations() {
-        // 迁移226: 创建 family_platform_balance 表 + family_platform_balance_log 表 + products.points_multiplier 列
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS family_platform_balance (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "  family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                            "  total_earned INT DEFAULT 0 COMMENT '累计获得', " +
-                            "  available INT DEFAULT 0 COMMENT '可用余额', " +
-                            "  frozen INT DEFAULT 0 COMMENT '冻结(提现审核中)', " +
-                            "  withdrawn INT DEFAULT 0 COMMENT '已提现', " +
-                            "  exchanged INT DEFAULT 0 COMMENT '已兑换', " +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "  UNIQUE KEY uk_family (family_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭平台积分池余额'"
-            );
-            log.info("已创建family_platform_balance表");
-        } catch (Exception e) {
-            log.warn("创建family_platform_balance表失败: " + e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS family_platform_balance_log (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "  family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                            "  type VARCHAR(20) NOT NULL COMMENT 'earn/spend/freeze/unfreeze/withdraw/adjust/migration', " +
-                            "  amount INT NOT NULL COMMENT '变动数量', " +
-                            "  balance_after INT NOT NULL COMMENT '变动后可用余额', " +
-                            "  ref_type VARCHAR(50) COMMENT 'product_order/referral_dist/activity/withdrawal/adjust/migration/refund', " +
-                            "  ref_id BIGINT COMMENT '关联业务ID', " +
-                            "  remark VARCHAR(255) COMMENT '备注', " +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "  INDEX idx_family (family_id), " +
-                            "  INDEX idx_ref (ref_type, ref_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭平台积分流水'"
-            );
-            log.info("已创建family_platform_balance_log表");
-        } catch (Exception e) {
-            log.warn("创建family_platform_balance_log表失败: " + e.getMessage());
-        }
-        ensureColumn("products", "points_multiplier", "DECIMAL(10,2) NOT NULL DEFAULT 1.00 COMMENT '平台积分倍数,1元=1积分×倍数'");
-        log.info("已添加products.points_multiplier列");
-        // 迁移227: 创建 family_platform_exchange_record 表(家庭CF值兑换记录)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS family_platform_exchange_record (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "  user_id BIGINT NOT NULL COMMENT '操作用户ID', " +
-                            "  family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                            "  coupon_id BIGINT NOT NULL COMMENT '关联优惠券ID', " +
-                            "  coupon_name VARCHAR(200) COMMENT '优惠券名称', " +
-                            "  cf_cost INT NOT NULL COMMENT '消耗CF值数量', " +
-                            "  status VARCHAR(20) NOT NULL DEFAULT 'completed' COMMENT 'completed/failed', " +
-                            "  redeem_code VARCHAR(32) COMMENT '兑换码', " +
-                            "  remark VARCHAR(255) COMMENT '备注', " +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "  INDEX idx_family_time (family_id, created_at), " +
-                            "  INDEX idx_user (user_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭CF值兑换记录'"
-            );
-            log.info("已创建family_platform_exchange_record表");
-        } catch (Exception e) {
-            log.warn("创建family_platform_exchange_record表失败: " + e.getMessage());
-        }
-
-        // 迁移228: nutrition_product 添加 ingredients 列 + suitable_for 升级为 TEXT(存放详情页图像提取的成份/配料表与适用说明)
-        ensureColumn("nutrition_product", "ingredients", "TEXT DEFAULT NULL COMMENT '成份/配料表(从详情页图片提取)'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE nutrition_product MODIFY COLUMN suitable_for TEXT DEFAULT NULL COMMENT '适用人群/使用方法'");
-            log.info("已将nutrition_product.suitable_for升级为TEXT类型");
-        } catch (Exception e) {
-            // 修改失败,忽略错误(幂等)
-        }
-
-        // 迁移222: 创建 file_tag 表(文件标签字典)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS file_tag (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "name VARCHAR(50) NOT NULL COMMENT '标签名称', " +
-                            "color VARCHAR(7) DEFAULT '#409EFF' COMMENT '标签颜色', " +
-                            "sort_order INT DEFAULT 0 COMMENT '排序号', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "UNIQUE KEY uk_name (name)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件标签字典'"
-            );
-            log.info("已创建file_tag表");
-        } catch (Exception e) {
-            log.warn("创建file_tag表失败: " + e.getMessage());
-        }
-
-        String[][] presetTags = {
-                {"测评报告", "#409EFF"}, {"健康报告", "#67C23A"}, {"文章配图", "#E6A23C"},
-                {"成长档案", "#909399"}, {"身", "#FF8C42"}, {"智", "#6366F1"},
-                {"富", "#F59E0B"}, {"行", "#10B981"}, {"心", "#FF6B9D"}, {"重要", "#F56C6C"}
-        };
-        for (int i = 0; i < presetTags.length; i++) {
-            try {
-                jdbcTemplate.update("INSERT IGNORE INTO file_tag (name, color, sort_order) VALUES (?, ?, ?)",
-                        presetTags[i][0], presetTags[i][1], i);
-            } catch (Exception e) { /* 忽略重复 */ }
-        }
-        log.info("已预置文件标签");
-
-        // 迁移223: 创建 file_tag_rel 表
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS file_tag_rel (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "file_id BIGINT NOT NULL COMMENT 'file_record.id', " +
-                            "tag_id BIGINT NOT NULL COMMENT 'file_tag.id', " +
-                            "UNIQUE KEY uk_file_tag (file_id, tag_id), " +
-                            "INDEX idx_tag (tag_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件-标签关联'"
-            );
-            log.info("已创建file_tag_rel表");
-        } catch (Exception e) {
-            log.warn("创建file_tag_rel表失败: " + e.getMessage());
-        }
-
-        // 迁移229: 新增GROWTH_COACH权益(7X24小时成长教练)到FAMILY/PREMIUM,及mascot_ai功能开关
-        try {
-            jdbcTemplate.execute("INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES " +
-                    "('FAMILY', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题', '🎯', '#FEF3C7', 10), " +
-                    "('PREMIUM', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题 + 优先响应', '🎯', '#FEF3C7', 10)");
-            log.info("已插入GROWTH_COACH权益种子数据");
-        } catch (Exception ex) {
-            log.warn("插入GROWTH_COACH权益种子数据失败: {}", ex.getMessage());
-        }
-
-
-        // 迁移232: recommendation_logs 追加 recommend_type 字段
-        ensureColumn("recommendation_logs", "recommend_type", "VARCHAR(20) DEFAULT 'tag' COMMENT '推荐方式: profile/dimension/tag'");
-        log.info("已添加recommendation_logs.recommend_type列");
-
-        // 迁移233: 将 Article/Activity 现有 dimension_weights JSON 同步到 dimension_weights 表
-        // (修正:源表名 article→articles、activity→activities;activity与article同为五维JSON对象按维度键展开;
-        //   dimension_weights表无唯一键,INSERT IGNORE不去重,用sys_config一次性标记+自连接去重兜底)
-        try {
-            Integer synced = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM sys_config WHERE config_key = 'dimension_weights_legacy_sync_done'",
-                    Integer.class);
-            if (synced == null || synced == 0) {
-                jdbcTemplate.execute(
-                        "INSERT IGNORE INTO dimension_weights (target_type, target_id, dimension, weight, enabled) " +
-                                "SELECT 'article', a.id, 'body', COALESCE(CAST(JSON_EXTRACT(a.dimension_weights, '$.body') AS SIGNED), 0), 1 " +
-                                "FROM articles a WHERE a.dimension_weights IS NOT NULL AND a.dimension_weights != '' AND JSON_EXTRACT(a.dimension_weights, '$.body') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'article', a.id, 'mind', COALESCE(CAST(JSON_EXTRACT(a.dimension_weights, '$.mind') AS SIGNED), 0), 1 " +
-                                "FROM articles a WHERE a.dimension_weights IS NOT NULL AND a.dimension_weights != '' AND JSON_EXTRACT(a.dimension_weights, '$.mind') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'article', a.id, 'wisdom', COALESCE(CAST(JSON_EXTRACT(a.dimension_weights, '$.wisdom') AS SIGNED), 0), 1 " +
-                                "FROM articles a WHERE a.dimension_weights IS NOT NULL AND a.dimension_weights != '' AND JSON_EXTRACT(a.dimension_weights, '$.wisdom') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'article', a.id, 'action', COALESCE(CAST(JSON_EXTRACT(a.dimension_weights, '$.action') AS SIGNED), 0), 1 " +
-                                "FROM articles a WHERE a.dimension_weights IS NOT NULL AND a.dimension_weights != '' AND JSON_EXTRACT(a.dimension_weights, '$.action') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'article', a.id, 'wealth', COALESCE(CAST(JSON_EXTRACT(a.dimension_weights, '$.wealth') AS SIGNED), 0), 1 " +
-                                "FROM articles a WHERE a.dimension_weights IS NOT NULL AND a.dimension_weights != '' AND JSON_EXTRACT(a.dimension_weights, '$.wealth') IS NOT NULL"
-                );
-                jdbcTemplate.execute(
-                        "INSERT IGNORE INTO dimension_weights (target_type, target_id, dimension, weight, enabled) " +
-                                "SELECT 'activity', act.id, 'body', COALESCE(CAST(JSON_EXTRACT(act.dimension_weights, '$.body') AS SIGNED), 0), 1 " +
-                                "FROM activities act WHERE act.dimension_weights IS NOT NULL AND act.dimension_weights != '' AND JSON_EXTRACT(act.dimension_weights, '$.body') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'activity', act.id, 'mind', COALESCE(CAST(JSON_EXTRACT(act.dimension_weights, '$.mind') AS SIGNED), 0), 1 " +
-                                "FROM activities act WHERE act.dimension_weights IS NOT NULL AND act.dimension_weights != '' AND JSON_EXTRACT(act.dimension_weights, '$.mind') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'activity', act.id, 'wisdom', COALESCE(CAST(JSON_EXTRACT(act.dimension_weights, '$.wisdom') AS SIGNED), 0), 1 " +
-                                "FROM activities act WHERE act.dimension_weights IS NOT NULL AND act.dimension_weights != '' AND JSON_EXTRACT(act.dimension_weights, '$.wisdom') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'activity', act.id, 'action', COALESCE(CAST(JSON_EXTRACT(act.dimension_weights, '$.action') AS SIGNED), 0), 1 " +
-                                "FROM activities act WHERE act.dimension_weights IS NOT NULL AND act.dimension_weights != '' AND JSON_EXTRACT(act.dimension_weights, '$.action') IS NOT NULL " +
-                                "UNION ALL " +
-                                "SELECT 'activity', act.id, 'wealth', COALESCE(CAST(JSON_EXTRACT(act.dimension_weights, '$.wealth') AS SIGNED), 0), 1 " +
-                                "FROM activities act WHERE act.dimension_weights IS NOT NULL AND act.dimension_weights != '' AND JSON_EXTRACT(act.dimension_weights, '$.wealth') IS NOT NULL"
-                );
-                jdbcTemplate.execute(
-                        "DELETE dw1 FROM dimension_weights dw1 INNER JOIN dimension_weights dw2 ON " +
-                                "dw1.target_type = dw2.target_type AND dw1.target_id = dw2.target_id AND dw1.dimension = dw2.dimension " +
-                                "AND dw1.id > dw2.id"
-                );
-                jdbcTemplate.update("INSERT INTO sys_config (config_key, config_value, description) VALUES ('dimension_weights_legacy_sync_done', '1', 'Article/Activity五维权重已同步到dimension_weights表')");
-                log.info("已完成Article/Activity维度权重到dimension_weights表的一次性迁移");
-            } else {
-                log.info("迁移233: 维度权重已同步过,跳过");
-            }
-        } catch (Exception ex) {
-            log.warn("Article/Activity维度权重同步失败: {}", ex.getMessage());
-        }
-
-        // 迁移234: 创建 problem_domains 表(问题域定义,改版v1:需求驱动·逐步解锁)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS problem_domains (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "code VARCHAR(50) NOT NULL COMMENT '唯一编码: weight_loss/sleep/constipation', " +
-                            "name VARCHAR(50) NOT NULL COMMENT '名称: 减肥/睡眠/便秘', " +
-                            "icon VARCHAR(255) DEFAULT '' COMMENT '图标', " +
-                            "description VARCHAR(500) DEFAULT '' COMMENT '一句话描述', " +
-                            "flow_intro_json TEXT COMMENT '服务流程介绍(7步) JSON', " +
-                            "survey_template_id BIGINT DEFAULT NULL COMMENT '专项调研问卷模板ID(SurveyTemplate.id)', " +
-                            "content_tags VARCHAR(500) DEFAULT '' COMMENT '内容标签,逗号分隔(过滤文章/知识库)', " +
-                            "recommended_product_ids VARCHAR(500) DEFAULT '' COMMENT '推荐产品ID,逗号分隔(Product.id)', " +
-                            "task_template_package_ids VARCHAR(500) DEFAULT '' COMMENT '套餐绑定的任务模板包ID(TaskTemplatePackage.id)', " +
-                            "reward_cf_value INT DEFAULT 0 COMMENT '全部完成奖励CF值', " +
-                            "status TINYINT DEFAULT 1 COMMENT '1启用 0停用', " +
-                            "sort_order INT DEFAULT 0, " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "UNIQUE KEY uk_code (code)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题域定义(改版v1)'"
-            );
-            log.info("已创建problem_domains表");
-        } catch (Exception e) {
-            log.warn("创建problem_domains表失败: " + e.getMessage());
-        }
-
-        // 迁移235: 创建 user_intents 表(用户意图与服务旅程)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS user_intents (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                            "intent_type VARCHAR(20) DEFAULT '' COMMENT 'A/B/C 用户类型', " +
-                            "problem_domain_code VARCHAR(50) DEFAULT '' COMMENT '问题域编码(仅C类)', " +
-                            "journey_stage INT DEFAULT 0 COMMENT '旅程阶段 0-7', " +
-                            "stage_updated_at DATETIME DEFAULT NULL COMMENT '最近阶段变化时间', " +
-                            "survey_template_id BIGINT DEFAULT NULL COMMENT '最近作答问卷模板ID', " +
-                            "survey_submitted_at DATETIME DEFAULT NULL COMMENT '最近问卷提交时间', " +
-                            "survey_result_json TEXT COMMENT '问卷答案→推荐结果快照', " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "UNIQUE KEY uk_user (user_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户意图与服务旅程(改版v1)'"
-            );
-            log.info("已创建user_intents表");
-        } catch (Exception e) {
-            log.warn("创建user_intents表失败: " + e.getMessage());
-        }
-
-        // 迁移236: 创建 user_notifications 表(用户级站内主动通知,与notices平台公告并存)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS user_notifications (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "user_id BIGINT NOT NULL COMMENT '接收用户ID', " +
-                            "type VARCHAR(30) DEFAULT 'report_ready' COMMENT 'report_ready/reward_granted/logistics/system', " +
-                            "title VARCHAR(200) NOT NULL, " +
-                            "content VARCHAR(1000) DEFAULT '', " +
-                            "ref_type VARCHAR(30) DEFAULT '' COMMENT '关联对象类型: report/package/task', " +
-                            "ref_id BIGINT DEFAULT NULL COMMENT '关联对象ID', " +
-                            "is_read TINYINT DEFAULT 0, " +
-                            "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "INDEX idx_user_read (user_id, is_read)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内通知(改版v1)'"
-            );
-            log.info("已创建user_notifications表");
-        } catch (Exception e) {
-            log.warn("创建user_notifications表失败: " + e.getMessage());
-        }
-
-        // 迁移237: tasks 表添加 member_only 字段(1=会员任务,仅方案/套餐生成)
-        ensureColumn("tasks", "member_only", "TINYINT DEFAULT 0 COMMENT '1=会员任务(方案/套餐生成),执行需会员; 0=普通任务可免费执行'");
-
-        // 迁移238: package_orders 表添加物流状态字段(试剂盒寄送/样本寄回)
-        ensureColumn("package_orders", "logistics_status", "VARCHAR(20) DEFAULT 'none' COMMENT 'none/kit_shipped/kit_received/sample_shipped/sample_received'");
-        ensureColumn("package_orders", "tracking_no", "VARCHAR(100) DEFAULT '' COMMENT '快递单号'");
-        log.info("已添加package_orders物流字段");
-
-        // 迁移239: 创建 health_status 表(当前状态调研-健康现状档案,SS-2026-08-13)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS health_status (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "user_id BIGINT NOT NULL COMMENT '所属账号(一个账号一份)', " +
-                            "height_cm DECIMAL(5,1) DEFAULT NULL COMMENT '身高(cm)', " +
-                            "weight_kg DECIMAL(5,1) DEFAULT NULL COMMENT '体重(kg)', " +
-                            "blood_pressure VARCHAR(20) DEFAULT NULL COMMENT '血压,如 120/80', " +
-                            "blood_glucose DECIMAL(4,1) DEFAULT NULL COMMENT '空腹血糖(mmol/L)', " +
-                            "blood_lipids JSON DEFAULT NULL COMMENT '血脂 [{name,value,unit,note}]', " +
-                            "disease_history JSON DEFAULT NULL COMMENT '疾病史 [{name,note}]', " +
-                            "medications JSON DEFAULT NULL COMMENT '在服药物/治疗 [{name,note}]', " +
-                            "notes VARCHAR(500) DEFAULT NULL COMMENT '其他补充说明', " +
-                            "filled_at DATETIME DEFAULT NULL COMMENT '首次填写时间', " +
-                            "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                            "UNIQUE KEY uk_user (user_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='当前状态调研-健康现状档案'"
-            );
-            log.info("已创建health_status表");
-        } catch (Exception e) {
-            log.warn("创建health_status表失败: " + e.getMessage());
-        }
-
-        // 迁移240: 创建 system_prompts 表(系统提示词统一管理,cfc-web后台可维护)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS system_prompts (" +
-                            "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "prompt_key VARCHAR(64) NOT NULL COMMENT '提示词键(如 health_coach/analysis/chat)', " +
-                            "title VARCHAR(100) NOT NULL COMMENT '提示词标题', " +
-                            "content TEXT NOT NULL COMMENT '提示词内容', " +
-                            "default_content TEXT COMMENT '出厂默认内容(重置时恢复)', " +
-                            "version INT NOT NULL DEFAULT 1 COMMENT '版本号', " +
-                            "status TINYINT NOT NULL DEFAULT 1 COMMENT '1=启用 0=禁用', " +
-                            "remark VARCHAR(255) COMMENT '备注', " +
-                            "updated_by VARCHAR(64) COMMENT '更新人', " +
-                            "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                            "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "UNIQUE KEY uk_prompt_key (prompt_key)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统提示词管理'"
-            );
-            log.info("已创建system_prompts表");
-        } catch (Exception e) {
-            log.warn("创建system_prompts表失败: " + e.getMessage());
-        }
-
-        // 迁移240b: 插入默认系统提示词(仅当表为空时)
-        try {
-            jdbcTemplate.execute(
-                    "INSERT IGNORE INTO system_prompts (prompt_key, title, content, default_content, version, remark) VALUES " +
-                            "('health_butler', '家庭健康管家', " +
-                            "'你是一个家庭AI健康管家, 为用户提供专业、温暖的个性化健康建议。\\n你的能力:\\n1. 基于健康知识库(菌属功能、指标解读、营养素、食物)提供科学建议\\n2. 解读健康报告数据, 结合知识库给出改善方案\\n3. 根据菌群检测结果推荐精准营养方案\\n4. 提供可执行的健康微行动\\n回答原则:\\n1. 用中文, 像家庭医生一样亲切但专业\\n2. 引用知识库中的菌属/指标/食物信息作为证据\\n3. 优先使用知识库数据, 其次使用通用健康知识\\n4. 需要产品推荐时使用搜索工具\\n5. 生成 [TASK: {\"title\": \"任务名\", \"dimension\": \"身\", \"points\": 10, \"frequency\": \"每天\"}] 标记创建健康行动任务\\n6. 超出知识库范围的慢性病/急症问题, 建议咨询专业医生\\n7. 不要编造医学建议, 不夸大效果', " +
-                            "'你是一个家庭AI健康管家, 为用户提供专业、温暖的个性化健康建议。\\n你的能力:\\n1. 基于健康知识库(菌属功能、指标解读、营养素、食物)提供科学建议\\n2. 解读健康报告数据, 结合知识库给出改善方案\\n3. 根据菌群检测结果推荐精准营养方案\\n4. 提供可执行的健康微行动\\n回答原则:\\n1. 用中文, 像家庭医生一样亲切但专业\\n2. 引用知识库中的菌属/指标/食物信息作为证据\\n3. 优先使用知识库数据, 其次使用通用健康知识\\n4. 需要产品推荐时使用搜索工具\\n5. 生成 [TASK: {\"title\": \"任务名\", \"dimension\": \"身\", \"points\": 10, \"frequency\": \"每天\"}] 标记创建健康行动任务\\n6. 超出知识库范围的慢性病/急症问题, 建议咨询专业医生\\n7. 不要编造医学建议, 不夸大效果', " +
-                            "1, 'AI健康管家对话'), " +
-                            "('health_coach', '儿童健康教练', " +
-                            "'你是一个儿童健康教练,喜欢用提问的方式引导家长发现问题和解决方案。\\n核心原则:\\n1. 先问后答:不要直接给答案,用问题引导家长思考\\n2. 用开放式问题了解情况,再给针对性建议\\n3. 语气温暖,像一个耐心的教练在陪伴家长成长\\n你的职责:\\n1. 儿童体质调理(如挑食、瘦弱、易疲劳、反复生病)—— 用提问了解情况\\n2. 科学喂养和营养建议 —— 先问饮食现状再给建议\\n3. 日常保健(睡眠、运动、季节防护)—— 引导家长发现生活中的问题\\n4. 体质辨识基础咨询 —— 通过提问帮助家长理解孩子体质特点\\n5. 健康问题判断 —— 先收集症状信息再建议是否就医\\n回答结构: 提问-分析-建议-跟进', " +
-                            "'你是一个儿童健康教练,喜欢用提问的方式引导家长发现问题和解决方案。\\n核心原则:\\n1. 先问后答:不要直接给答案,用问题引导家长思考\\n2. 用开放式问题了解情况,再给针对性建议\\n3. 语气温暖,像一个耐心的教练在陪伴家长成长\\n你的职责:\\n1. 儿童体质调理(如挑食、瘦弱、易疲劳、反复生病)—— 用提问了解情况\\n2. 科学喂养和营养建议 —— 先问饮食现状再给建议\\n3. 日常保健(睡眠、运动、季节防护)—— 引导家长发现生活中的问题\\n4. 体质辨识基础咨询 —— 通过提问帮助家长理解孩子体质特点\\n5. 健康问题判断 —— 先收集症状信息再建议是否就医\\n回答结构: 提问-分析-建议-跟进', " +
-                            "1, '儿童健康咨询对话'), " +
-                            "('chat_assistant', '儿童成长助手', " +
-                            "'你是一个儿童成长家庭助手, 回答关于孩子成长、健康、教育的各种问题。', " +
-                            "'你是一个儿童成长家庭助手, 回答关于孩子成长、健康、教育的各种问题。', " +
-                            "1, '通用对话助手')"
-            );
-            log.info("已插入默认系统提示词");
-        } catch (Exception e) {
-            log.warn("插入默认系统提示词失败: " + e.getMessage());
-        }
-        // 迁移242: 创建 sys_menu 表(管理后台侧边栏菜单,数据库驱动 + 角色授权)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS sys_menu (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "  parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID,0=顶级', " +
-                            "  title VARCHAR(50) COMMENT '目录标题(有子菜单时用,对应 el-submenu)', " +
-                            "  label VARCHAR(50) COMMENT '叶子菜单显示名(对应 el-menu-item)', " +
-                            "  path VARCHAR(200) COMMENT '路由路径(叶子菜单必填,如 /families)', " +
-                            "  icon VARCHAR(100) COMMENT 'Element UI 图标类名,如 el-icon-s-custom', " +
-                            "  perm VARCHAR(100) COMMENT '权限标识,如 family:list / task:* / system:config', " +
-                            "  sort INT DEFAULT 0 COMMENT '排序号,小的在前', " +
-                            "  visible TINYINT DEFAULT 1 COMMENT '是否显示 1=显示 0=隐藏', " +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                            "  INDEX idx_parent (parent_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台侧边栏菜单表'"
-            );
-            log.info("已创建sys_menu表");
-        } catch (Exception e) {
-            log.warn("创建sys_menu表失败: " + e.getMessage());
-        }
-
-        // 迁移243: 创建 sys_role_menu 表(角色-菜单授权)
-        try {
-            jdbcTemplate.execute(
-                    "CREATE TABLE IF NOT EXISTS sys_role_menu (" +
-                            "  id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                            "  role VARCHAR(50) NOT NULL COMMENT '角色标识: admin/teacher/nutritionist/article_manager/activity_manager/supplier_admin', " +
-                            "  menu_id BIGINT NOT NULL COMMENT 'sys_menu.id', " +
-                            "  created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                            "  UNIQUE KEY uk_role_menu (role, menu_id)" +
-                            ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色-菜单授权表'"
-            );
-            log.info("已创建sys_role_menu表");
-        } catch (Exception e) {
-            log.warn("创建sys_role_menu表失败: " + e.getMessage());
-        }
-
-        // 迁移244: sys_menu 菜单种子数据(对应 Layout.vue 硬编码 menuItems,表为空才插入,幂等)
-        try {
-            Integer menuCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM sys_menu", Integer.class);
-            if (menuCount == null || menuCount == 0) {
-                seedSysMenus();
-                log.info("sys_menu 种子数据已插入");
-            } else {
-                log.info("sys_menu 已有 {} 条数据,跳过种子插入", menuCount);
-            }
-        } catch (Exception e) {
-            log.warn("初始化sys_menu种子数据失败: " + e.getMessage());
-        }
-
-// 迁移245: 创建 notification_templates 表(通知模板管理 W3)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS notification_templates (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "type VARCHAR(30) NOT NULL COMMENT '通知类型: report_ready/reward_granted/system', " +
-                    "title VARCHAR(200) NOT NULL COMMENT '默认标题(支持占位符)', " +
-                    "content VARCHAR(1000) NOT NULL COMMENT '默认内容模板(支持占位符)', " +
-                    "channels VARCHAR(100) DEFAULT 'in_app' COMMENT '推送通道: in_app,sms,wechat,phone 逗号分隔', " +
-                    "status TINYINT DEFAULT 1 COMMENT '1启用 0停用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_type (type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知模板(改版v1 W3)'");
-            log.info("已创建notification_templates表");
-        } catch (Exception e) {
-            log.warn("创建notification_templates表可能已存在: {}", e.getMessage());
-        }
-        // 迁移245b: notification_templates 种子数据(表为空才插入,幂等)
-        try {
-            Integer tplCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM notification_templates", Integer.class);
-            if (tplCount == null || tplCount == 0) {
-                jdbcTemplate.execute("INSERT INTO notification_templates (type, title, content, channels) VALUES " +
-                        "('report_ready', '健康报告已完成分析', '您的健康报告已完成解析,可前往查看结果与成长方案。', 'in_app,sms'), " +
-                        "('reward_granted', '问题域完成奖励已到账', '恭喜完成「{domainName}」全部任务,奖励 {reward} CF 已发放至家庭账户。', 'in_app,sms,wechat'), " +
-                        "('system', '系统通知', '您有一条新的系统通知,请前往查看。', 'in_app'), " +
-                        "('energy_change', '能量变动', '{description}获得{amount}能量', 'in_app'), " +
-                        "('points_change', '积分变动', '{description}变动{amount}积分', 'in_app'), " +
-                        "('cf_change', 'CF值变动', '{remark}获得{amount} CF值', 'in_app'), " +
-                        "('procurement_completed', '采购任务已完成', '您的【{comboTier}】套餐采购任务已完成,共{productCount}件商品,下单时间:{createTime},产品即将送达,请及时查收。', 'in_app,wechat')");
-                log.info("notification_templates 种子数据已插入");
-            } else {
-                log.info("notification_templates 已有 {} 条数据,跳过种子插入", tplCount);
-            }
-        } catch (Exception e) {
-            log.warn("初始化notification_templates种子数据失败: " + e.getMessage());
-        }
-
-        // 迁移246: product_skus 存量价格 ×100(元→分),sys_config 幂等标记
-        try {
-            Integer migrated = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM sys_config WHERE config_key = 'sku_price_to_cents_done'",
-                    Integer.class);
-            if (migrated == null || migrated == 0) {
-                jdbcTemplate.update("UPDATE product_skus SET price = IFNULL(price, 0) * 100, original_price = IFNULL(original_price, 0) * 100");
-                jdbcTemplate.update("INSERT INTO sys_config (config_key, config_value, description) VALUES ('sku_price_to_cents_done', '1', 'SKU价格已迁移为分单位')");
-                log.info("迁移246: product_skus 价格已×100(元→分)");
-            } else {
-                log.info("迁移246: product_skus 价格已迁移过,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("迁移246失败: {}", e.getMessage());
-        }
-
-        // 迁移247: product_skus 添加 linked_product_id 和 label 列(SKU关联商品选择器)
-        ensureColumn("product_skus", "linked_product_id", "BIGINT COMMENT '关联商品ID,null=Legacy SKU'");
-        ensureColumn("product_skus", "label", "VARCHAR(100) COMMENT '自定义显示标签,null=使用linked_product.name'");
-
-        // 迁移248: families 添加 butler_id(B-5 管家行级隔离)
-        ensureColumn("families", "butler_id", "BIGINT COMMENT '绑定的管家userId'");
-        try {
-            jdbcTemplate.execute("CREATE INDEX idx_families_butler_id ON families(butler_id)");
-            log.info("已创建families.butler_id索引");
-        } catch (Exception e) {
-            String msg = e.getMessage();
-            if (msg == null || !(msg.contains("Duplicate") || msg.contains("exists"))) {
-                log.warn("创建families.butler_id索引失败: {}", msg);
-            }
-        }
-
-        // 迁移249: sys_menu 菜单归类调整 + 权限点拆分(《角色权限与菜单归类整合方案》第二部分/B-3,幂等)
-        migrateSysMenuReorg();
-
-        // 迁移250: 清理测试脏数据(B-7:TEST-Energy-Grant 测试任务、乱码昵称)
-        try {
-            int deletedTasks = jdbcTemplate.update("DELETE FROM tasks WHERE title LIKE 'TEST-Energy-Grant%'");
-            int fixedNicknames = jdbcTemplate.update("UPDATE users SET nickname = '测试家庭' WHERE nickname LIKE '娴嬭瘯%' AND nickname <> '测试家庭'");
-            if (deletedTasks > 0 || fixedNicknames > 0) {
-                log.info("迁移250: 已清理测试任务 {} 条,修复乱码昵称 {} 个", deletedTasks, fixedNicknames);
-            }
-        } catch (Exception e) {
-            log.warn("迁移250失败: {}", e.getMessage());
-        }
-
-        // 迁移251: 健康饮食组挂载 报告管理/报告审核/应季食材(《角色权限与菜单归类整合方案》第二部分,幂等)
-        migrateHealthMenuMount();
-
-        // 迁移252: 创建用户画像表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS profile_snapshot (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL UNIQUE, " +
-                    "dimension_scores JSON DEFAULT NULL, " +
-                    "body_metrics JSON DEFAULT NULL, " +
-                    "mind_metrics JSON DEFAULT NULL, " +
-                    "wisdom_metrics JSON DEFAULT NULL, " +
-                    "action_metrics JSON DEFAULT NULL, " +
-                    "wealth_metrics JSON DEFAULT NULL, " +
-                    "problem_domains VARCHAR(500) DEFAULT NULL, " +
-                    "computed_at DATETIME DEFAULT NULL, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_id (member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建profile_snapshot表");
-        } catch (Exception e) {
-            log.warn("创建profile_snapshot表可能已存在: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS profile_history (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL, " +
-                    "snapshot_date DATE NOT NULL, " +
-                    "all_metrics JSON NOT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_member_date (member_id, snapshot_date)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
-            log.info("已创建profile_history表");
-        } catch (Exception e) {
-            log.warn("创建profile_history表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移254: 创建 report_template 表(报告展示模板配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_template (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "name VARCHAR(100) NOT NULL COMMENT '模板名称', " +
-                    "report_type VARCHAR(50) NOT NULL COMMENT '报告类型: gut_flora/dan/physical_exam/tongue', " +
-                    "config JSON NOT NULL COMMENT '模板配置JSON: fixedBlocks+freeDisplay', " +
-                    "is_active TINYINT DEFAULT 1 COMMENT '0=停用 1=启用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_report_type (report_type)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告展示模板'");
-            log.info("已创建report_template表");
-        } catch (Exception e) {
-            log.warn("report_template表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移255: report_unknown_upload 添加 annotation 列(管理员标注训练数据)
-        ensureColumn("report_unknown_upload", "annotation", "TEXT COMMENT '管理员标注: 手动指定类型+确认提取结果JSON'");
-
-        // 迁移256: social_circle 添加圈子管理字段
-        ensureColumn("social_circle", "description", "VARCHAR(500) NULL COMMENT '圈子描述'");
-        ensureColumn("social_circle", "cover_image", "VARCHAR(500) NULL COMMENT '封面图URL'");
-        ensureColumn("social_circle", "join_condition", "TINYINT(1) DEFAULT 0 COMMENT '加入条件: 0=公开/1=审核/2=邀请'");
-        ensureColumn("social_circle", "review_required", "TINYINT(1) DEFAULT 0 COMMENT '是否需要审核: 0=否/1=是'");
-        ensureColumn("social_circle", "is_public", "TINYINT(1) DEFAULT 1 COMMENT '是否公开可见: 0=否/1=是'");
-
-        // 迁移257: social_circle_member 添加审核状态和角色字段
-        ensureColumn("social_circle_member", "status", "VARCHAR(20) DEFAULT 'approved' COMMENT '申请状态: pending/approved/rejected'");
-        ensureColumn("social_circle_member", "role", "VARCHAR(20) DEFAULT 'member' COMMENT '角色: member/admin'");
-
-        // 迁移258: 创建圈子动态帖子表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS social_circle_post (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL COMMENT '圈子ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '发布者成员ID', " +
-                    "member_type VARCHAR(20) NOT NULL COMMENT 'parent/child', " +
-                    "type VARCHAR(50) NOT NULL COMMENT '帖子类型: checkin/diet/exercise/sleep/water/mood/text', " +
-                    "content TEXT COMMENT '文字内容', " +
-                    "checkin_id BIGINT COMMENT '关联打卡记录ID', " +
-                    "image_urls TEXT COMMENT '图片URL列表JSON', " +
-                    "like_count INT DEFAULT 0 COMMENT '点赞数', " +
-                    "comment_count INT DEFAULT 0 COMMENT '评论数', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "deleted TINYINT(1) DEFAULT 0, " +
-                    "INDEX idx_circle_time (circle_id, created_at), " +
-                    "INDEX idx_member_time (member_id, created_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子动态帖子'");
-            log.info("已创建social_circle_post表");
-        } catch (Exception e) {
-            log.warn("social_circle_post表可能已存在");
-        }
-
-        // 迁移259: 创建圈子点赞表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS social_circle_like (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL, " +
-                    "post_id BIGINT NOT NULL COMMENT '被点赞的帖子ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '点赞成员ID', " +
-                    "member_type VARCHAR(20) NOT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_like (circle_id, post_id, member_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子点赞记录'");
-            log.info("已创建social_circle_like表");
-        } catch (Exception e) {
-            log.warn("social_circle_like表可能已存在");
-        }
-
-        // 迁移260: 创建圈子评论表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS social_circle_comment (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "circle_id BIGINT NOT NULL, " +
-                    "post_id BIGINT NOT NULL COMMENT '所属帖子ID', " +
-                    "parent_id BIGINT DEFAULT NULL COMMENT '回复的评论ID(NULL=一级评论)', " +
-                    "member_id BIGINT NOT NULL COMMENT '评论者成员ID', " +
-                    "member_type VARCHAR(20) NOT NULL, " +
-                    "content TEXT NOT NULL COMMENT '评论内容', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_post_time (post_id, created_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子评论记录'");
-            log.info("已创建social_circle_comment表");
-        } catch (Exception e) {
-            log.warn("social_circle_comment表可能已存在");
-        }
-
-        // 迁移261: butler_profiles 添加停接新单开关(管家自助选择功能)
-        ensureColumn("butler_profiles", "accepting",
-                "TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否接受新家庭绑定: 0=停接/1=接单'");
-        // 迁移262: family_join_requests 添加 inviter_user_id 列(审批人=邀请人,谁分享的卡谁确认)
-        try {
-            jdbcTemplate.execute("ALTER TABLE family_join_requests ADD COLUMN inviter_user_id BIGINT NULL COMMENT '邀请人用户ID(分享邀请令牌的人)' AFTER invite_ref");
-            jdbcTemplate.execute("ALTER TABLE family_join_requests ADD INDEX idx_inviter (inviter_user_id)");
-            log.info("已添加inviter_user_id列到family_join_requests表");
-        } catch (Exception e) {
-            // 列/索引已存在,忽略错误
-            log.warn("family_join_requests.inviter_user_id可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移263: users 表添加 portrait_prompt 列(用户画像 prompt 拼装需求)
-        try {
-            jdbcTemplate.execute("ALTER TABLE users ADD COLUMN portrait_prompt TEXT COMMENT '用户自定义画像 prompt' AFTER mascot");
-            log.info("已添加 portrait_prompt 列到 users 表");
-        } catch (Exception e) {
-            log.warn("users.portrait_prompt可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移264: 方案分解任务补全 family_member_id,修正 deadline 落在次日 00:00 的边界问题
-        try {
-            jdbcTemplate.update(
-                    "UPDATE tasks SET family_member_id = child_id " +
-                    "WHERE source_type = 'plan' AND family_member_id IS NULL AND child_id IS NOT NULL");
-            jdbcTemplate.update(
-                    "UPDATE tasks SET deadline = TIMESTAMP(DATE(deadline)) - INTERVAL 1 SECOND " +
-                    "WHERE source_type = 'plan' AND TIME(deadline) = '00:00:00'");
-            log.info("已修复方案分解任务的 family_member_id 与 deadline 边界");
-        } catch (Exception e) {
-            log.warn("修复方案分解任务字段失败: {}", e.getMessage());
-        }
-
-        // 迁移265: 方案分解任务开启审核,打卡后需规划师/管理员审核通过才发放积分
-        try {
-            jdbcTemplate.update(
-                    "UPDATE tasks SET need_review = 1 " +
-                    "WHERE source_type = 'plan' AND (need_review IS NULL OR need_review = 0) AND status IN ('pending', 'pending_review')");
-            log.info("已开启方案分解任务的审核模式");
-        } catch (Exception e) {
-            log.warn("开启方案分解任务审核失败: {}", e.getMessage());
-        }
-
-        // 迁移266: tasks.status 扩展 pending_review/locked(打卡提交待审核、前置任务锁定)
-        try {
-            jdbcTemplate.execute(
-                    "ALTER TABLE tasks MODIFY COLUMN `status` " +
-                    "ENUM('pending','assigned','in_progress','completed','rejected','overdue','cancelled','locked','pending_review') " +
-                    "DEFAULT 'pending' COMMENT '状态: pending=待完成 assigned=待接受 in_progress=进行中 completed=已完成 rejected=已拒绝 overdue=已过期 cancelled=已取消 locked=前置锁定 pending_review=待审核'");
-            log.info("已扩展 tasks.status 枚举,支持 pending_review/locked");
-        } catch (Exception e) {
-            log.warn("扩展 tasks.status 枚举失败(可能已修改): {}", e.getMessage());
-        }
-
-        // 迁移267: 方案中心菜单(插在家庭运营与任务中心之间)
-        migratePlanCenterMenu();
-        // 迁移268: coupon 表添加 status 列(优惠券停用/启用)
-        migrateCouponStatus();
-// 迁移276: five_dimension_self_checks 表添加 question_ids_json 列(自检轮换用)
-        ensureColumn("five_dimension_self_checks", "question_ids_json", "VARCHAR(255) COMMENT '本次自检使用的题号JSON: [1,5,9,...]'");
-
-        // 迁移277: 创建 self_check_ignores 表(记录用户忽略自检提醒的动作,作为 15 天周期重置依据)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS self_check_ignores (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "check_id BIGINT COMMENT '忽略的自检记录ID(可空)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '忽略时间', " +
-                    "INDEX idx_user_id (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维自检忽略提醒记录'");
-            log.info("已创建 self_check_ignores 表");
-        } catch (Exception e) {
-            log.warn("创建 self_check_ignores 表失败: {}", e.getMessage());
-        }
-
-        // 迁移275: users 表添加 family_inviter_id(家庭邀请追踪)
-        ensureColumn("users", "family_inviter_id", "BIGINT DEFAULT NULL COMMENT '家庭邀请人ID(首次注册时绑定,用于追踪邀请来源)'");
-    }
-
-    /**
-     * 迁移267: 存量库插入「方案中心」一级菜单及子菜单(幂等)
-     * 位置:家庭运营(sort=1) 与 任务中心 之间;任务中心及之后顶级菜单 sort+1
-     */
-    private void migratePlanCenterMenu() {
-        try {
-            Long existed = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=0 AND title='方案中心'");
-            if (existed == null) {
-                // 为任务中心及之后的顶级菜单腾出 sort=2
-                jdbcTemplate.update(
-                        "UPDATE sys_menu SET sort = sort + 1 WHERE parent_id=0 AND sort >= 2 " +
-                        "AND title <> '方案中心'");
-                jdbcTemplate.update(
-                        "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) " +
-                        "VALUES (0, '方案中心', NULL, NULL, 'el-icon-notebook-2', 'plan:*', 2, 1)");
-                existed = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-                log.info("迁移267: 已插入方案中心一级菜单");
-            }
-            if (existed == null) {
-                return;
-            }
-            Long healthPlanId = insertPlanCenterChild(existed, "健康方案管理", "/health-plan-manage",
-                    "el-icon-first-aid-kit", "plan:health", 0);
-            Long assessmentPlanId = insertPlanCenterChild(existed, "测评方案管理", "/assessment-plan-manage",
-                    "el-icon-edit", "plan:assessment", 1);
-            Integer grantCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM sys_role_menu", Integer.class);
-            if (grantCount != null && grantCount > 0) {
-                String[] roles = {"admin", "butler", "nutritionist", "operator"};
-                Long[] menuIds = {existed, healthPlanId, assessmentPlanId};
-                for (String role : roles) {
-                    for (Long menuId : menuIds) {
-                        grantMenuToRole(role, menuId);
-                    }
-                }
-            }
-            log.info("迁移267: 方案中心菜单挂载完成");
-        } catch (Exception e) {
-            log.warn("迁移267失败: {}", e.getMessage());
-        }
-    }
-
-    private Long insertPlanCenterChild(Long parentId, String label, String path, String icon, String perm, int sort) {
-        try {
-            Long existed = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=" + parentId + " AND path='" + path + "'");
-            if (existed != null) {
-                return existed;
-            }
-            jdbcTemplate.update(
-                    "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, NULL, ?, ?, ?, ?, ?, 1)",
-                    parentId, label, path, icon, perm, sort
-            );
-            return jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-        } catch (Exception e) {
-            log.warn("迁移267: 挂载子菜单「{}」失败: {}", label, e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 迁移268: coupon 表添加 status 列(优惠券停用/启用,幂等)
-     * 存量数据 status 为 NULL,查询层按 ACTIVE 处理,不影响现有券。
-     */
-    private void migrateCouponStatus() {
-        try {
-            jdbcTemplate.execute("ALTER TABLE coupon ADD COLUMN status VARCHAR(16) DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE=启用/DISABLED=停用'");
-            log.info("迁移268: 已为 coupon 表添加 status 列");
-        } catch (Exception e) {
-            // 列已存在,忽略错误
-        }
-    }
-
-    /**
-     * 迁移249: 存量库 sys_menu 菜单归类调整 + 权限点拆分(幂等,按 path/title 定位)
-     * 1. 审核中心改为分组,归集:服务角色申请审核/活动审核/待退款管理/收益提现审核
-     * 2. 能量规则/能量行为/周期性服务 → 系统配置·健康配置
-     * 3. LangGraph 管理 → 报告解析系统
-     * 4. 测评管理/测评订单/待分配规划师 → 测评咨询(删除系统配置下原"测评管理"子组)
-     * 5. 菜单组权限统一 模块:* 格式;system:config 拆分为 system:base/config:member/config:dimension/config:health/config:report-parser
-     * 6. 术语统一:七维能量配置 → 五维能量配置
-     */
-    private void migrateSysMenuReorg() {
-        try {
-            // A. 审核中心:顶级叶子 → 分组,并插入"审核中心总览"子项
-            jdbcTemplate.update("UPDATE sys_menu SET title='审核中心', label=NULL, path=NULL, perm='audit', sort=3 WHERE path='/review-center' AND parent_id=0 AND title IS NULL");
-            Long reviewGroup = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=0 AND title='审核中心' AND (path IS NULL OR path='')");
-            if (reviewGroup != null) {
-                Integer childCount = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM sys_menu WHERE parent_id=" + reviewGroup + " AND path='/review-center'", Integer.class);
-                if (childCount == null || childCount == 0) {
-                    jdbcTemplate.update(
-                            "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, NULL, '审核中心总览', '/review-center', 'el-icon-s-check', 'audit', 0, 1)",
-                            reviewGroup);
-                }
-                // 迁入审核中心
-                moveMenu("/service-role-applications", reviewGroup, "audit:service-role", 1);
-                moveMenu("/activity-review", reviewGroup, "audit:activity", 2);
-                moveMenu("/pending-refund", reviewGroup, "audit:refund", 3);
-                moveMenu("/family-earnings-withdraw", reviewGroup, "audit:withdraw", 4);
-            }
-
-            // B. 能量规则/能量行为/周期性服务 → 系统配置·健康配置
-            Long healthConfig = queryMenuId("SELECT id FROM sys_menu WHERE title='健康配置' AND (path IS NULL OR path='')");
-            if (healthConfig != null) {
-                jdbcTemplate.update("UPDATE sys_menu SET perm='config:health' WHERE id=" + healthConfig);
-                moveMenu("/energy-rule", healthConfig, "config:health", 3);
-                moveMenu("/energy-behavior-config", healthConfig, "config:health", 4);
-                moveMenu("/periodic-service-config", healthConfig, "config:health", 5);
-            }
-
-            // C. LangGraph 管理 → 报告解析系统
-            Long reportParser = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=0 AND title='报告解析系统'");
-            if (reportParser != null) {
-                jdbcTemplate.update("UPDATE sys_menu SET perm='config:report-parser' WHERE id=" + reportParser);
-                moveMenu("/langgraph-admin", reportParser, "config:report-parser", 4);
-                updateMenuPermByPath("/report-types", "config:report-parser");
-                updateMenuPermByPath("/report-parser-import", "config:report-parser");
-                updateMenuPermByPath("/report-unknown-clusters", "config:report-parser");
-                updateMenuPermByPath("/report-auto-learn", "config:report-parser");
-            }
-
-            // D. 测评管理/测评订单/待分配规划师 → 测评咨询
-            Long assessment = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=0 AND title='测评咨询'");
-            Long oldAssessmentManage = queryMenuId("SELECT id FROM sys_menu WHERE title='测评管理' AND (path IS NULL OR path='')");
-            if (assessment != null) {
-                moveMenu("/assessment-admin", assessment, "assessment:manage", 0);
-                moveMenu("/assessment-orders", assessment, "assessment:orders", 1);
-                moveMenu("/assessment-assign", assessment, "assessment:assign", 2);
-            }
-            if (oldAssessmentManage != null && assessment != null && !oldAssessmentManage.equals(assessment)) {
-                // 子项已迁走,删除系统配置下空的"测评管理"子组及其授权关联
-                jdbcTemplate.update("DELETE FROM sys_role_menu WHERE menu_id=" + oldAssessmentManage);
-                jdbcTemplate.update("DELETE FROM sys_menu WHERE id=" + oldAssessmentManage);
-            }
-
-            // E. 菜单组权限统一 模块:* 格式(废弃 operation/content/commerce/health 单段写法)
-            jdbcTemplate.update("UPDATE sys_menu SET perm='family:*' WHERE parent_id=0 AND title='家庭运营'");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='articles:*' WHERE parent_id=0 AND title='知识中心'");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='commerce:*' WHERE parent_id=0 AND title='商城营销'");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='health:*' WHERE parent_id=0 AND title='健康饮食'");
-
-            // F. system:config 拆分
-            updateMenuPermByPath("/sys-config", "system:base");
-            updateMenuPermByPath("/gates", "system:base");
-            updateMenuPermByPath("/membership-center", "config:member");
-            updateMenuPermByPath("/badge-manage", "config:member");
-            updateMenuPermByPath("/virtual-goods-config", "config:member");
-            updateMenuPermByPath("/dimension-config", "config:dimension");
-            updateMenuPermByPath("/zodiac-configs", "config:dimension");
-            updateMenuPermByPath("/bazi-configs", "config:dimension");
-            updateMenuPermByPath("/blood-type-configs", "config:dimension");
-            updateMenuPermByPath("/health-norm-config", "config:health");
-            updateMenuPermByPath("/health-data-source", "config:health");
-            // 术语统一:七维能量配置 → 五维能量配置
-            jdbcTemplate.update("UPDATE sys_menu SET label='五维能量配置', perm='config:health' WHERE path='/health-energy-config'");
-            updateMenuPermByPath("/virtual-teams", "system:base");
-            updateMenuPermByPath("/knowledge-base", "knowledge:base");
-            updateMenuPermByPath("/health-knowledge", "knowledge:base");
-            updateMenuPermByPath("/supplier-products", "supply:manage");
-            updateMenuPermByPath("/nutrition-products", "health:products");
-            updateMenuPermByPath("/energy-sandbox", "health:energy");
-            // 子组权限
-            jdbcTemplate.update("UPDATE sys_menu SET perm='system:base' WHERE title='基础管理' AND (path IS NULL OR path='')");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='config:dimension' WHERE title='配置中心' AND (path IS NULL OR path='')");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='config:dimension' WHERE title='人生维度' AND (path IS NULL OR path='')");
-            jdbcTemplate.update("UPDATE sys_menu SET perm='system:base' WHERE title='虚拟团队' AND (path IS NULL OR path='')");
-
-            // G. 商城营销叶子权限统一(B-4 映射可识别)
-            updateMenuPermByPath("/product-manage", "commerce:products,commerce:self");
-            updateMenuPermByPath("/inventory", "inventory:self");
-            updateMenuPermByPath("/order-manage", "commerce:orders,order:self");
-            updateMenuPermByPath("/ecom-supplier", "commerce:supplier");
-            updateMenuPermByPath("/product-profit-rate", "finance:profit-rate");
-            updateMenuPermByPath("/coupon", "commerce:coupon");
-            updateMenuPermByPath("/coupon-grant-log", "commerce:coupon");
-            updateMenuPermByPath("/promotion", "commerce:promotion");
-            updateMenuPermByPath("/family-earnings", "finance:family-earnings");
-            updateMenuPermByPath("/activities", "activity:list,activity:self");
-            updateMenuPermByPath("/activity-registration-review", "activity:registration");
-            updateMenuPermByPath("/families", "family:list,family:read,family:bound");
-            updateMenuPermByPath("/children", "family:children,family:read,family:bound");
-            updateMenuPermByPath("/points-log", "family:points,family:bound");
-            updateMenuPermByPath("/growth-task", "task:growth");
-
-            log.info("迁移249: sys_menu 菜单归类调整与权限拆分完成");
-        } catch (Exception e) {
-            log.warn("迁移249失败: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 按 path 更新菜单权限(找不到时忽略)
-     */
-    private void updateMenuPermByPath(String path, String perm) {
-        try {
-            jdbcTemplate.update("UPDATE sys_menu SET perm=? WHERE path=?", perm, path);
-        } catch (Exception ignored) {
-        }
-    }
-
-    /**
-     * 迁移251: 健康饮食组挂载 报告管理/报告审核/应季食材(存量库 sys_menu 幂等补齐)
-     * 对应页面 ReportManagement.vue / HealthReportAudit.vue / SeasonalFoods.vue 已开发完成但此前未挂载;
-     * 同时将健康饮食组排序对齐《浠艾福后台-角色权限与菜单归类整合方案》最终菜单树。
-     */
-    private void migrateHealthMenuMount() {
-        try {
-            Long healthGroup = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=0 AND title='健康饮食'");
-            if (healthGroup == null) {
-                log.warn("迁移251: 未找到健康饮食分组,跳过");
-                return;
-            }
-            // 1. 存量菜单排序对齐(健康报告0..五维能量11),先更新防止插入冲突
-            jdbcTemplate.update("UPDATE sys_menu SET sort=0 WHERE parent_id=" + healthGroup + " AND path='/health-reports'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=3 WHERE parent_id=" + healthGroup + " AND path='/health-indicators'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=4 WHERE parent_id=" + healthGroup + " AND path='/health-checkins'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=5 WHERE parent_id=" + healthGroup + " AND path='/emotion-alert'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=6 WHERE parent_id=" + healthGroup + " AND path='/nutrition-mappings'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=7 WHERE parent_id=" + healthGroup + " AND path='/foods'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=8 WHERE parent_id=" + healthGroup + " AND path='/recipes'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=10 WHERE parent_id=" + healthGroup + " AND path='/nutrition-products'");
-            jdbcTemplate.update("UPDATE sys_menu SET sort=11 WHERE parent_id=" + healthGroup + " AND path='/energy-sandbox'");
-            // 2. 按 path 幂等插入 3 个新页面
-            Long reportManagementId = insertHealthMenu(healthGroup, "报告管理", "/report-management", "el-icon-document", "health:reports", 1);
-            Long reportAuditId = insertHealthMenu(healthGroup, "报告审核", "/report-audit", "el-icon-document-checked", "report:audit", 2);
-            Long seasonalFoodsId = insertHealthMenu(healthGroup, "应季食材", "/seasonal-foods", "el-icon-apple", "diet:foods", 9);
-            // 3. 条件授权:仅当已配置过角色授权(sys_role_menu 非空)时补授权,
-            //    避免破坏"所有角色均未授权 → 返回全量可见树"的兼容逻辑(SysMenuService.userMenus)
-            Integer grantCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM sys_role_menu", Integer.class);
-            if (grantCount != null && grantCount > 0) {
-                String[] roles = {"admin", "butler", "nutritionist"};
-                Long[] menuIds = {reportManagementId, reportAuditId, seasonalFoodsId};
-                for (String role : roles) {
-                    for (Long menuId : menuIds) {
-                        grantMenuToRole(role, menuId);
-                    }
-                }
-                log.info("迁移251: 已为 admin/butler/nutritionist 补授权新健康菜单");
-            }
-            log.info("迁移251: 健康饮食组挂载 报告管理/报告审核/应季食材完成");
-        } catch (Exception e) {
-            log.warn("迁移251失败: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 按 path 幂等插入健康饮食叶子菜单,返回菜单 id(已存在返回原 id)
-     */
-    private Long insertHealthMenu(Long parentId, String label, String path, String icon, String perm, int sort) {
-        try {
-            Long existed = queryMenuId("SELECT id FROM sys_menu WHERE parent_id=" + parentId + " AND path='" + path + "'");
-            if (existed != null) {
-                return existed;
-            }
-            jdbcTemplate.update(
-                    "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, NULL, ?, ?, ?, ?, ?, 1)",
-                    parentId, label, path, icon, perm, sort
-            );
-            Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-            log.info("迁移251: 已挂载健康饮食菜单「{}」", label);
-            return id;
-        } catch (Exception e) {
-            log.warn("迁移251: 挂载菜单「{}」失败: {}", label, e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 角色-菜单授权(幂等,唯一键 uk_role_menu 冲突忽略)
-     */
-    private void grantMenuToRole(String role, Long menuId) {
-        if (role == null || menuId == null) {
-            return;
-        }
-        try {
-            jdbcTemplate.update("INSERT IGNORE INTO sys_role_menu (role, menu_id) VALUES (?, ?)", role, menuId);
-        } catch (Exception ignored) {
-        }
-    }
-
-    /**
-     * 将菜单(按 path)移动到指定父组并更新权限/排序(幂等)
-     */
-    private void moveMenu(String path, Long parentId, String perm, int sort) {
-        try {
-            jdbcTemplate.update("UPDATE sys_menu SET parent_id=?, perm=?, sort=? WHERE path=?", parentId, perm, sort, path);
-        } catch (Exception ignored) {
-        }
-    }
-
-    /**
-     * 查询单个菜单 id,不存在返回 null
-     */
-    private Long queryMenuId(String sql) {
-        try {
-            List<Long> ids = jdbcTemplate.queryForList(sql, Long.class);
-            return ids.isEmpty() ? null : ids.get(0);
-        } catch (Exception e) {
-            return null;
-        }
-    }
-
-    /**
-     * 迁移244辅助方法: 插入 sys_menu 种子数据
-     * 结构与 cfc-web/src/views/Layout.vue 的 menuItems 硬编码一致
-     * 数组格式: {parentKey(空=顶级), key, title(目录), label(叶子), path, icon, perm, sort}
-     */
-    private void seedSysMenus() {
-        Map<String, Long> keyToId = new HashMap<>();
-        String[][] menus = {
-                // 顶级叶子
-                {"", "home", "", "首页", "/dashboard", "el-icon-s-home", "dashboard", "0"},
-                // 家庭运营(family:*)
-                {"", "operation", "家庭运营", "", "", "el-icon-s-custom", "family:*", "1"},
-                {"operation", "families", "", "家庭列表", "/families", "el-icon-s-custom", "family:list,family:read,family:bound", "0"},
-                {"operation", "children", "", "孩子管理", "/children", "el-icon-user-solid", "family:children,family:read,family:bound", "1"},
-                {"operation", "points", "", "积分管理", "/points", "el-icon-s-finance", "family:points", "2"},
-                {"operation", "pointsLog", "", "积分记录", "/points-log", "el-icon-document", "family:points,family:bound", "3"},
-                {"operation", "wishes", "", "心愿管理", "/wishes", "el-icon-star-off", "family:wishes", "4"},
-                {"operation", "rewards", "", "奖励管理", "/rewards", "el-icon-s-goods", "reward:list", "5"},
-                // 方案中心(plan:*,插在家庭运营与任务中心之间)
-                {"", "planCenter", "方案中心", "", "", "el-icon-notebook-2", "plan:*", "2"},
-                {"planCenter", "healthPlanManage", "", "健康方案管理", "/health-plan-manage", "el-icon-first-aid-kit", "plan:health", "0"},
-                {"planCenter", "assessmentPlanManage", "", "测评方案管理", "/assessment-plan-manage", "el-icon-edit", "plan:assessment", "1"},
-                // 任务中心(task:*)
-                {"", "taskCenter", "任务中心", "", "", "el-icon-s-order", "task:*", "3"},
-                {"taskCenter", "tasks", "", "任务列表", "/tasks", "el-icon-s-order", "task:list", "0"},
-                {"taskCenter", "taskTemplates", "", "任务模板", "/task-templates", "el-icon-document", "task:templates", "1"},
-                {"taskCenter", "growthTask", "", "成长任务管理", "/growth-task", "el-icon-s-management", "task:growth", "2"},
-                // 审核中心(audit,归集各审核页:服务角色申请/活动审核/退款/提现)
-                {"", "reviewCenterGroup", "审核中心", "", "", "el-icon-s-check", "audit", "4"},
-                {"reviewCenterGroup", "reviewCenter", "", "审核中心总览", "/review-center", "el-icon-s-check", "audit", "0"},
-                {"reviewCenterGroup", "serviceRoleApp", "", "服务角色申请审核", "/service-role-applications", "el-icon-s-check", "audit:service-role", "1"},
-                {"reviewCenterGroup", "activityReview", "", "活动审核", "/activity-review", "el-icon-document-checked", "audit:activity", "2"},
-                {"reviewCenterGroup", "pendingRefund", "", "待退款管理", "/pending-refund", "el-icon-warning", "audit:refund", "3"},
-                {"reviewCenterGroup", "earningWithdraw", "", "收益提现审核", "/family-earnings-withdraw", "el-icon-document-checked", "audit:withdraw", "4"},
-                // 商城营销(commerce:*)
-                {"", "commerce", "商城营销", "", "", "el-icon-s-goods", "commerce:*", "5"},
-                {"commerce", "productManage", "", "商品管理", "/product-manage", "el-icon-s-goods", "commerce:products,commerce:self", "0"},
-                {"commerce", "inventory", "", "库存管理", "/inventory", "el-icon-document", "inventory:self", "1"},
-                {"commerce", "orderManage", "", "订单管理", "/order-manage", "el-icon-s-order", "commerce:orders,order:self", "2"},
-                {"commerce", "ecomSupplier", "", "供应商管理", "/supply-system", "el-icon-s-shop", "system:supply", "3"},
-                {"commerce", "productProfitRate", "", "产品利润率", "/product-profit-rate", "el-icon-data-line", "finance:profit-rate", "4"},
-                {"commerce", "coupon", "", "优惠券管理", "/coupon", "el-icon-ticket", "commerce:coupon", "5"},
-                {"commerce", "couponGrantLog", "", "发券记录", "/coupon-grant-log", "el-icon-document", "commerce:coupon", "6"},
-                {"commerce", "discountRules", "", "限时折扣管理", "/discount-rules", "el-icon-timer", "commerce:discount", "7"},
-                {"commerce", "promotion", "", "推广管理", "/promotion", "el-icon-s-marketing", "commerce:promotion", "7"},
-                {"commerce", "familyEarnings", "", "家庭收益", "/family-earnings", "el-icon-s-money", "finance:family-earnings", "8"},
-                // 知识中心(articles:*)
-                {"", "knowledge", "知识中心", "", "", "el-icon-document", "articles:*", "6"},
-                {"knowledge", "articleCategories", "", "知识分类", "/article-categories", "el-icon-folder", "articles:categories", "0"},
-                {"knowledge", "articleManage", "", "知识管理", "/article-manage", "el-icon-document", "articles:manage", "1"},
-                {"knowledge", "commentReview", "", "评论审核", "/comment-review", "el-icon-chat-dot-round", "articles:manage", "2"},
-                {"knowledge", "knowledgeTags", "", "知识标签", "/knowledge-tags", "el-icon-price-tag", "articles:categories", "3"},
-                {"knowledge", "knowledgeBase", "", "知识库", "/knowledge-base", "el-icon-reading", "knowledge:base", "4"},
-                {"knowledge", "healthKnowledge", "", "健康知识库", "/health-knowledge", "el-icon-first-aid-kit", "knowledge:base", "5"},
-                // 活动管理(activity:*,活动审核已移入审核中心)
-                {"", "activity", "活动管理", "", "", "el-icon-date", "activity:*", "7"},
-                {"activity", "activities", "", "活动列表", "/activities", "el-icon-date", "activity:list,activity:self", "0"},
-                {"activity", "activityRegReview", "", "活动报名审核", "/activity-registration-review", "el-icon-document-checked", "activity:registration", "1"},
-                // 健康饮食(health:*,能量规则/行为/周期性服务已移入系统配置·健康配置,LangGraph已移入报告解析系统;报告管理/报告审核/应季食材按方案挂载)
-                {"", "health", "健康饮食", "", "", "el-icon-first-aid-kit", "health:*", "8"},
-                {"health", "healthReports", "", "健康报告", "/health-reports", "el-icon-document", "health:reports", "0"},
-                {"health", "reportManagement", "", "报告管理", "/report-management", "el-icon-document", "health:reports", "1"},
-                {"health", "reportAudit", "", "报告审核", "/report-audit", "el-icon-document-checked", "report:audit", "2"},
-                {"health", "healthIndicators", "", "健康指标", "/health-indicators", "el-icon-data-line", "health:indicators", "3"},
-                {"health", "healthCheckins", "", "健康打卡", "/health-checkins", "el-icon-s-order", "health:checkins", "4"},
-                {"health", "emotionAlert", "", "情绪告警", "/emotion-alert", "el-icon-warning", "health:checkins", "5"},
-                {"health", "nutritionMappings", "", "营养素映射", "/nutrition-mappings", "el-icon-connection", "health:mappings", "6"},
-                {"health", "foods", "", "食材管理", "/foods", "el-icon-apple", "diet:foods", "7"},
-                {"health", "recipes", "", "食谱管理", "/recipes", "el-icon-dish", "diet:recipes", "8"},
-                {"health", "seasonalFoods", "", "应季食材", "/seasonal-foods", "el-icon-apple", "diet:foods", "9"},
-                {"health", "nutritionProducts", "", "营养产品", "/nutrition-products", "el-icon-first-aid-kit", "health:products", "10"},
-                {"health", "energySandbox", "", "五维能量", "/energy-sandbox", "el-icon-data-line", "health:energy", "11"},
-                // 报告解析系统(config:report-parser,LangGraph 管理归入)
-                {"", "reportParser", "报告解析系统", "", "", "el-icon-cpu", "config:report-parser", "9"},
-                {"reportParser", "reportTypes", "", "报告类型管理", "/report-types", "el-icon-collection", "config:report-parser", "0"},
-                {"reportParser", "reportParserImport", "", "解析器导入", "/report-parser-import", "el-icon-upload2", "config:report-parser", "1"},
-                {"reportParser", "reportUnknownClusters", "", "未知报告审核", "/report-unknown-clusters", "el-icon-question", "config:report-parser", "2"},
-                {"reportParser", "reportAutoLearn", "", "报告自学习", "/report-auto-learn", "el-icon-magic-stick", "config:report-parser", "3"},
-                {"reportParser", "langgraphAdmin", "", "LangGraph 管理", "/langgraph-admin", "el-icon-cpu", "config:report-parser", "4"},
-                // 家庭服务(service:*)
-                {"", "familyService", "家庭服务", "", "", "el-icon-s-custom", "service:*", "10"},
-                {"familyService", "myFamilies", "", "我的家庭", "/my-families", "el-icon-s-custom", "service:family", "0"},
-                {"familyService", "teacherTeam", "", "我的团队", "/teacher-team", "el-icon-s-custom", "service:team", "1"},
-                // 业务管理(biz:*)
-                {"", "biz", "业务管理", "", "", "el-icon-s-marketing", "biz:*", "11"},
-                {"biz", "teacherPackages", "", "任务模板管理", "/teacher-packages", "el-icon-s-goods", "biz:packages", "0"},
-                {"biz", "teacherOrders", "", "订单佣金", "/teacher-orders", "el-icon-s-order", "biz:orders", "1"},
-                // 测评咨询(测评管理/测评订单/待分配规划师已从系统配置移入)
-                {"", "assessment", "测评咨询", "", "", "el-icon-edit", "assessment:*", "12"},
-                {"assessment", "assessmentAdmin", "", "测评管理", "/assessment-admin", "el-icon-edit", "assessment:manage", "0"},
-                {"assessment", "assessmentOrders", "", "测评订单", "/assessment-orders", "el-icon-s-order", "assessment:orders", "1"},
-                {"assessment", "assessmentAssign", "", "待分配规划师", "/assessment-assign", "el-icon-user", "assessment:assign", "2"},
-                {"assessment", "teacherAssessment", "", "DAN测评", "/teacher-assessment", "el-icon-edit", "assessment:dan", "3"},
-                {"assessment", "teacherConsult", "", "家长咨询", "/teacher-consult", "el-icon-chat-dot-round", "assessment:consult", "4"},
-                {"assessment", "growthRecords", "", "成长记录", "/growth-records", "el-icon-document", "growth:records", "5"},
-                {"assessment", "growthPlans", "", "成长计划", "/growth-plans", "el-icon-document", "growth:plans", "6"},
-                // 系统配置(system:*,权限拆分 system:base / config:member / config:dimension / config:health)
-                {"", "system", "系统配置", "", "", "el-icon-s-tools", "system:*", "13"},
-                {"system", "baseManage", "基础管理", "", "", "el-icon-s-tools", "system:base", "0"},
-                {"baseManage", "sysConfig", "", "系统配置", "/sys-config", "el-icon-s-tools", "system:base", "0"},
-                {"baseManage", "users", "", "用户管理", "/users", "el-icon-user", "system:users", "1"},
-                {"baseManage", "operationLogs", "", "操作日志", "/operation-logs", "el-icon-s-order", "system:logs", "2"},
-                {"baseManage", "membershipCenter", "", "会员中心", "/membership-center", "el-icon-s-custom", "config:member", "3"},
-                {"baseManage", "badgeManage", "", "勋章管理", "/badge-manage", "el-icon-medal", "config:member", "4"},
-                {"baseManage", "virtualGoodsConfig", "", "虚拟支付道具", "/virtual-goods-config", "el-icon-goods", "config:member", "5"},
-                {"baseManage", "gates", "", "关卡配置", "/gates", "el-icon-key", "system:base", "6"},
-                {"baseManage", "menuManage", "", "菜单管理", "/menu-manage", "el-icon-menu", "system:menu", "7"},
-                {"system", "configCenter", "配置中心", "", "", "el-icon-setting", "config:dimension", "1"},
-                {"configCenter", "dimensionConfig", "", "维度配置", "/dimension-config", "el-icon-data-line", "config:dimension", "0"},
-                {"system", "supplyHierarchy", "供应商体系", "", "", "el-icon-s-management", "system:supply", "2"},
-                {"supplyHierarchy", "supplySystem", "", "供应商体系", "/supply-system", "el-icon-s-management", "system:supply", "0"},
-                {"system", "supplierManage", "供应商管理", "", "", "el-icon-s-shop", "supply:manage", "3"},
-                {"supplierManage", "supplyManage", "", "供应商管理", "/supply-manage", "el-icon-s-shop", "supply:manage", "0"},
-                {"supplierManage", "supplierProducts", "", "商品管理", "/supplier-products", "el-icon-s-goods", "supply:manage", "1"},
-                {"system", "healthConfig", "健康配置", "", "", "el-icon-first-aid-kit", "config:health", "4"},
-                {"healthConfig", "healthNormConfig", "", "健康常模", "/health-norm-config", "el-icon-data-line", "config:health", "0"},
-                {"healthConfig", "healthDataSource", "", "健康数据源", "/health-data-source", "el-icon-data-line", "config:health", "1"},
-                {"healthConfig", "healthEnergyConfig", "", "五维能量配置", "/health-energy-config", "el-icon-data-line", "config:health", "2"},
-                {"healthConfig", "energyRule", "", "能量规则管理", "/energy-rule", "el-icon-setting", "config:health", "3"},
-                {"healthConfig", "energyBehaviorConfig", "", "能量行为配置", "/energy-behavior-config", "el-icon-edit-outline", "config:health", "4"},
-                {"healthConfig", "periodicServiceConfig", "", "周期性服务配置", "/periodic-service-config", "el-icon-refresh", "config:health", "5"},
-                {"system", "lifeDimension", "人生维度", "", "", "el-icon-s-custom", "config:dimension", "5"},
-                {"lifeDimension", "zodiacConfigs", "", "星座配置", "/zodiac-configs", "el-icon-s-management", "config:dimension", "0"},
-                {"lifeDimension", "baziConfigs", "", "八字配置", "/bazi-configs", "el-icon-s-management", "config:dimension", "1"},
-                {"lifeDimension", "bloodTypeConfigs", "", "血型配置", "/blood-type-configs", "el-icon-s-management", "config:dimension", "2"},
-                {"system", "virtualTeam", "虚拟团队", "", "", "el-icon-s-custom", "system:base", "6"},
-                {"virtualTeam", "virtualTeams", "", "虚拟团队", "/virtual-teams", "el-icon-s-custom", "system:base", "0"},
-        };
-
-        for (String[] m : menus) {
-            Long parentId = 0L;
-            if (m[0] != null && !m[0].isEmpty()) {
-                parentId = keyToId.get(m[0]);
-                if (parentId == null) {
-                    parentId = 0L;
-                }
-            }
-            String title = m[2] != null && !m[2].isEmpty() ? m[2] : null;
-            String label = m[3] != null && !m[3].isEmpty() ? m[3] : null;
-            String path = m[4] != null && !m[4].isEmpty() ? m[4] : null;
-            String icon = m[5] != null && !m[5].isEmpty() ? m[5] : null;
-            String perm = m[6] != null && !m[6].isEmpty() ? m[6] : null;
-            int sort = Integer.parseInt(m[7]);
-            jdbcTemplate.update(
-                    "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, ?, ?, ?, ?, ?, ?, 1)",
-                    parentId, title, label, path, icon, perm, sort
-            );
-            Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-            keyToId.put(m[1], id);
-        }
-
-        // ===== 迁移:初始化方案规则数据 (P1) =====
-        try {
-            // 使用 jdbcTemplate 的 DataSource
-            var ds = jdbcTemplate.getDataSource();
-            if (ds instanceof javax.sql.DataSource) {
-                try (Connection conn = ((javax.sql.DataSource) ds).getConnection()) {
-                    PreparedStatement ps = null;
-                    try {
-                        // 插入注意力提升方案规则 1:0-60 分 → 模板 ID=38
-                        ps = conn.prepareStatement("INSERT INTO assessment_plan_rules (id, dimension, score_min, score_max, template_id, priority, is_active, created_at, updated_at) VALUES (NULL, ?, ?, ?, ?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE updated_at=NOW()");
-                        ps.setString(1, "attention");
-                        ps.setInt(2, 0);
-                        ps.setInt(3, 60);
-                        ps.setLong(4, 38L); // 使用现有的模板 ID
-                        ps.setInt(5, 1);
-                        ps.setBoolean(6, true);
-                        ps.executeUpdate();
-                        log.info("已插入注意力方案规则 1(0-60 分)");
-                        ps.close();
-
-                        // 插入注意力提升方案规则 2:61-100 分 → 模板 ID=39
-                        ps = conn.prepareStatement("INSERT INTO assessment_plan_rules (id, dimension, score_min, score_max, template_id, priority, is_active, created_at, updated_at) VALUES (NULL, ?, ?, ?, ?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE updated_at=NOW()");
-                        ps.setString(1, "attention");
-                        ps.setInt(2, 61);
-                        ps.setInt(3, 100);
-                        ps.setLong(4, 39L);
-                        ps.setInt(5, 2);
-                        ps.setBoolean(6, true);
-                        ps.executeUpdate();
-                        log.info("已插入注意力方案规则 2(61-100 分)");
-                        ps.close();
-                    } finally {
-                        if (ps != null) ps.close();
-                    }
-                }
-            }
-        } catch (SQLException e) {
-            log.warn("初始化方案规则失败:{}", e.getMessage());
-        }
-
-        // ===== 迁移:初始化报告类型注册 (R1) =====
-        try {
-            // 使用 jdbcTemplate 的 DataSource
-            var ds = jdbcTemplate.getDataSource();
-            if (ds instanceof javax.sql.DataSource) {
-                try (Connection conn = ((javax.sql.DataSource) ds).getConnection()) {
-                    PreparedStatement ps = null;
-                    try {
-                        // 注册肠道菌群检测报告类型
-                        ps = conn.prepareStatement("INSERT INTO report_type_registry (id, type_id, display_name, parser_path, min_confidence, is_active, source, review_status, version, created_at, updated_at) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW()) ON DUPLICATE KEY UPDATE updated_at=NOW()");
-                        ps.setString(1, "gut_flora");
-                        ps.setString(2, "肠道菌群检测");
-                        ps.setString(3, "dan_reports/gut_flora.py");
-                        ps.setInt(4, 10);
-                        ps.setBoolean(5, true);
-                        ps.setString(6, "prebuilt");
-                        ps.setString(7, "approved");
-                        ps.setString(8, "1.0");
-                        ps.executeUpdate();
-                        log.info("已注册报告类型:gut_flora");
-                        ps.close();
-                    } finally {
-                        if (ps != null) ps.close();
-                    }
-                }
-            }
-        } catch (SQLException e) {
-            log.warn("注册报告类型 gut_flora 失败:{}", e.getMessage());
-        }
-
-        // 迁移278-313: 已移至独立方法 runSystemMigrations()(原误置于本方法仅空表触发)
-    }
-
-    // 迁移278-313: 系统级 DDL/数据迁移(原误置于 seedSysMenus 内,空表才执行,生产永远跳过)
-    // 抽出为独立方法,由 runMigrations() 无条件调用,确保生产库每次启动补齐。
-    private void runSystemMigrations() {
-        // 迁移278: 创建 family_coupon 表 + family_coupon_grant_log 表
-        // (优惠券全链路改为家庭维度:2026-08-31)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_coupon (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '所属家庭ID', " +
-                    "coupon_id BIGINT NOT NULL COMMENT '券模板ID', " +
-                    "status VARCHAR(16) DEFAULT 'AVAILABLE' COMMENT 'AVAILABLE/USED', " +
-                    "received_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "used_at DATETIME, " +
-                    "order_id BIGINT COMMENT '核销时写入的订单号', " +
-                    "INDEX idx_family_coupon (family_id, coupon_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_order_id (order_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭优惠券表'");
-            log.info("已创建 family_coupon 表");
-        } catch (Exception e) {
-            log.warn("family_coupon 表已存在,跳过创建: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS family_coupon_grant_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '受赠家庭ID', " +
-                    "coupon_id BIGINT NOT NULL COMMENT '券模板ID', " +
-                    "grant_type VARCHAR(16) NOT NULL COMMENT 'JOIN/PERIODIC/POPULATION/EXCHANGE/CF_EXCHANGE', " +
-                    "period VARCHAR(16) COMMENT '周期标识(YYYY-MM或YYYY-Qn),PERIODIC防重用', " +
-                    "quantity INT DEFAULT 1 COMMENT '发放数量', " +
-                    "source VARCHAR(64) COMMENT '触发来源(订单号/成员ID等)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_family_grant (family_id, coupon_id, grant_type, period), " +
-                    "INDEX idx_coupon (coupon_id), " +
-                    "INDEX idx_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭优惠券发放流水表'");
-            log.info("已创建 family_coupon_grant_log 表");
-        } catch (Exception e) {
-            log.warn("family_coupon_grant_log 表已存在,跳过创建: {}", e.getMessage());
-        }
-
-        // 迁移279: 创建 cf_rate_tier 表(CF值返佣阶梯配置,替代 promotion_tier_config)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS cf_rate_tier (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "tier_name VARCHAR(50) NOT NULL COMMENT '档位名称', " +
-                    "min_team_size INT NOT NULL DEFAULT 0 COMMENT '团队规模下限(含)', " +
-                    "rate_percent INT NOT NULL DEFAULT 0 COMMENT '返佣比例(%)', " +
-                    "sort_order INT NOT NULL DEFAULT 0 COMMENT '排序,越大越高', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '1启用/0停用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_min_size (min_team_size)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值返佣阶梯配置'");
-            log.info("已创建cf_rate_tier表");
-            Integer cnt = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM cf_rate_tier", Integer.class);
-            if (cnt == null || cnt == 0) {
-                jdbcTemplate.execute("INSERT INTO cf_rate_tier (tier_name, min_team_size, rate_percent, sort_order) VALUES " +
-                        "('铜牌', 0, 5, 1), ('银牌', 3, 10, 2), ('金牌', 10, 15, 3), ('铂金', 30, 20, 4), ('钻石', 100, 25, 5)");
-                log.info("cf_rate_tier 种子数据已初始化");
-            }
-        } catch (Exception e) {
-            log.warn("创建cf_rate_tier表失败: {}", e.getMessage());
-        }
-
-        // 迁移280: 创建 cf_transfer_record 表(CF值流转记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS cf_transfer_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "from_user_id BIGINT COMMENT '转出用户ID(null=平台)', " +
-                    "to_user_id BIGINT COMMENT '转入用户ID', " +
-                    "family_id BIGINT COMMENT '所属家庭ID', " +
-                    "amount INT NOT NULL COMMENT 'CF值数量', " +
-                    "type VARCHAR(16) NOT NULL COMMENT 'transfer/allocate/refund', " +
-                    "ref_type VARCHAR(50) COMMENT '关联业务类型', " +
-                    "ref_id BIGINT COMMENT '关联业务ID', " +
-                    "remark VARCHAR(255), " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_from (from_user_id), " +
-                    "INDEX idx_to (to_user_id), " +
-                    "INDEX idx_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流转记录'");
-            log.info("已创建cf_transfer_record表");
-        } catch (Exception e) {
-            log.warn("创建cf_transfer_record表失败: {}", e.getMessage());
-        }
-
-        // 迁移281: promotion_tier 精简列(删三层,加 rate_percent)
-        try {
-            jdbcTemplate.execute("ALTER TABLE promotion_tier DROP COLUMN team_size_1st, DROP COLUMN team_size_2nd, DROP COLUMN team_size_3rd");
-            log.info("promotion_tier 已删除三层团队列");
-        } catch (Exception e) {
-            log.warn("promotion_tier 三层列删除失败(可能不存在): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE promotion_tier ADD COLUMN rate_percent INT DEFAULT 0 COMMENT '当前返佣比例(%)'");
-            log.info("promotion_tier 已添加 rate_percent");
-        } catch (Exception e) {
-            log.warn("promotion_tier.rate_percent 已存在: {}", e.getMessage());
-        }
-
-        // 迁移282: coupon 表添加 family_id
-        try {
-            jdbcTemplate.execute("ALTER TABLE coupon ADD COLUMN family_id BIGINT DEFAULT NULL COMMENT '绑定家庭ID(NULL=不绑定)'");
-            log.info("coupon 已添加 family_id");
-        } catch (Exception e) {
-            log.warn("coupon.family_id 已存在: {}", e.getMessage());
-        }
-
-        // 迁移283: referral_tree 唯一键改为 (parent_id, child_id) 联合唯一(支持每祖先一行物化)
-        try {
-            jdbcTemplate.execute("ALTER TABLE referral_tree DROP INDEX uk_child_id");
-            log.info("referral_tree 已删除 uk_child_id 唯一键");
-        } catch (Exception e) {
-            log.warn("referral_tree.uk_child_id 删除失败(可能不存在): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE referral_tree ADD UNIQUE KEY uk_parent_child (parent_id, child_id)");
-            log.info("referral_tree 已添加 uk_parent_child 联合唯一键");
-        } catch (Exception e) {
-            log.warn("referral_tree.uk_parent_child 已存在: {}", e.getMessage());
-        }
-
-        // 迁移284: cf_transfer_record 加 (ref_type, ref_id) 唯一索引(幂等兜底,防止并发 earn 重复发放)
-        try {
-            jdbcTemplate.execute("ALTER TABLE cf_transfer_record ADD UNIQUE KEY uk_ref_type_id (ref_type, ref_id)");
-            log.info("cf_transfer_record 已添加 uk_ref_type_id 唯一索引");
-        } catch (Exception e) {
-            log.warn("cf_transfer_record.uk_ref_type_id 已存在: {}", e.getMessage());
-        }
-
-        // 迁移285: 创建 product_gift_configs 表(商品赠品配置,商品×等级)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_gift_configs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "product_id BIGINT NOT NULL COMMENT '关联products表', " +
-                    "level_code VARCHAR(50) NOT NULL COMMENT '会员等级编码(FAMILY/PREMIUM等)', " +
-                    "status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_product_level (product_id, level_code), " +
-                    "INDEX idx_product_id (product_id), " +
-                    "INDEX idx_level_code (level_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠品配置(商品×等级)'");
-            log.info("已创建product_gift_configs表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移286: 创建 product_gift_items 表(商品赠品项)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_gift_items (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "config_id BIGINT NOT NULL COMMENT '关联product_gift_configs.id', " +
-                    "gift_type VARCHAR(20) NOT NULL COMMENT 'product=赠品商品 cf=CF值', " +
-                    "gift_product_id BIGINT COMMENT '赠品商品ID(gift_type=product时必填)', " +
-                    "gift_product_name VARCHAR(200) COMMENT '赠品商品名快照', " +
-                    "gift_product_image VARCHAR(500) COMMENT '赠品商品图快照', " +
-                    "cf_value INT DEFAULT 0 COMMENT 'CF值数量(gift_type=cf时必填,单位分)', " +
-                    "sort_order INT DEFAULT 0 COMMENT '排序(值越小越靠前)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_config_id (config_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠品项'");
-            log.info("已创建product_gift_items表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移287: 创建 product_order_gifts 表(订单赠品记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_order_gifts (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "order_id BIGINT NOT NULL COMMENT '关联product_orders.id', " +
-                    "order_no VARCHAR(64) NOT NULL COMMENT '订单号快照', " +
-                    "gift_type VARCHAR(20) NOT NULL COMMENT 'product=赠品商品 cf=CF值', " +
-                    "gift_product_id BIGINT COMMENT '赠品商品ID', " +
-                    "gift_product_name VARCHAR(200) COMMENT '赠品商品名快照', " +
-                    "gift_product_image VARCHAR(500) COMMENT '赠品商品图快照', " +
-                    "cf_value INT DEFAULT 0 COMMENT 'CF值数量(gift_type=cf时)', " +
-                    "quantity INT DEFAULT 1 COMMENT '数量(默认1)', " +
-                    "fulfilled TINYINT(1) DEFAULT 0 COMMENT '0=已选未发放 1=已发放', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_order_id (order_id), " +
-                    "INDEX idx_order_no (order_no)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单赠品记录'");
-            log.info("已创建product_order_gifts表");
-        } catch (Exception e) {
-            // 表已存在,忽略
-        }
-
-        // 迁移288: health_report_drafts 加异步采集状态列(报告采集流程异步化)
-        // 用途:上传后进入后台异步采集(指纹判定→专用脚本/opencode),前端轮询 parse_status
-        ensureColumn("health_report_drafts", "parse_status",
-                "VARCHAR(20) DEFAULT NULL COMMENT '异步解析状态: collecting/completed/failed(NULL=未触发异步采集)'");
-        ensureColumn("health_report_drafts", "parse_method",
-                "VARCHAR(32) DEFAULT NULL COMMENT '解析方式: fingerprint_script/opencode/langgraph'");
-        ensureColumn("health_report_drafts", "parse_error",
-                "VARCHAR(2000) DEFAULT NULL COMMENT '异步解析失败原因'");
-        log.info("已添加 health_report_drafts 异步采集状态列 (parse_status/parse_method/parse_error)");
-
-        // 迁移289: health_reports 补 report_format 列(HealthReport 实体已含字段,但从未迁移至 DB,全字段 SELECT 报 Unknown column)
-        ensureColumn("health_reports", "report_format",
-                "VARCHAR(32) DEFAULT NULL COMMENT '报告格式: pdf/image'");
-
-        // 迁移290: 补齐实体已含但 DB 从未迁移的真实缺列(全字段 SELECT 防 Unknown column)
-        // 逐表核实(对照 schema.sql + 历史 ADD COLUMN/ensureColumn),仅含确认不存在的列,共 6 表 21 列
-        // 风险预留:promotion_tier_config 实体与 DB 为两套不同晋级模型(已废弃,由 cf_rate_tier 迁移279 替代),
-        // 按用户决定保持现状不迁移,避免与旧种子数据冲突;后续清理旧实体依赖(CommissionService等)时再处理
-        ensureColumn("activities", "visibility", "VARCHAR(20) DEFAULT 'public' COMMENT '浏览权限:public/login/private'");
-        ensureColumn("activities", "visible_to", "TEXT DEFAULT NULL COMMENT '私密指定人群JSON'");
-        ensureColumn("dan_knowledge_base", "file_url", "VARCHAR(500) DEFAULT NULL COMMENT 'fileUrl'");
-        ensureColumn("dan_knowledge_base", "file_name", "VARCHAR(255) DEFAULT NULL COMMENT 'fileName'");
-        ensureColumn("dan_knowledge_base", "source_url", "VARCHAR(500) DEFAULT NULL COMMENT 'sourceUrl'");
-        ensureColumn("dan_knowledge_base", "source_type", "VARCHAR(20) DEFAULT NULL COMMENT 'sourceType'");
-        ensureColumn("distribution_relations", "invite_code", "VARCHAR(64) DEFAULT NULL COMMENT 'inviteCode'");
-        ensureColumn("family_members", "birth_hour", "VARCHAR(10) DEFAULT NULL COMMENT '出生时辰'");
-        ensureColumn("family_members", "birth_weight", "INT DEFAULT NULL COMMENT '出生体重(g)'");
-        ensureColumn("family_members", "birth_place", "VARCHAR(255) DEFAULT NULL COMMENT '出生地'");
-        ensureColumn("family_members", "is_cesarean", "TINYINT(1) DEFAULT 0 COMMENT '是否剖腹产: 0否 1是'");
-        ensureColumn("health_indicators", "symptoms", "TEXT DEFAULT NULL COMMENT '症状描述'");
-        ensureColumn("product_orders", "tracking_number", "VARCHAR(100) DEFAULT NULL COMMENT '快递单号'");
-        ensureColumn("product_orders", "express_company", "VARCHAR(100) DEFAULT NULL COMMENT '快递公司'");
-        ensureColumn("product_orders", "delivery_method", "INT DEFAULT NULL COMMENT '配送方式: 1=快递 2=自提 3=两者皆可 4=线上-可选人 5=线上-单人'");
-        ensureColumn("product_orders", "pickup_code", "VARCHAR(64) DEFAULT NULL COMMENT '自提码'");
-        ensureColumn("product_orders", "confirm_time", "DATETIME DEFAULT NULL COMMENT '确认收货时间'");
-        ensureColumn("product_orders", "refund_status", "INT DEFAULT NULL COMMENT '退款状态'");
-        ensureColumn("product_orders", "refund_reason", "VARCHAR(255) DEFAULT NULL COMMENT '退款原因'");
-        ensureColumn("product_orders", "refund_amount", "INT DEFAULT NULL COMMENT '退款金额(分)'");
-        ensureColumn("product_orders", "refund_time", "DATETIME DEFAULT NULL COMMENT '退款时间'");
-        log.info("已补齐真实缺列 (迁移290, 6表21列)");
-
-        // 迁移291: food_nutrients 列名对齐(amount_per_100g -> amount_per100g)
-        // FoodNutrient 实体字段 amountPer100g 经 MyBatis-Plus camel->snake 映射为 amount_per100g,
-        // 但建表 SQL 误用 amount_per_100g,导致实体全字段 SELECT 报 Unknown column 'amount_per100g'。
-        // 当前 FoodNutrientMapper 无 Service 调用,属潜在隐患;此处统一列名为 amount_per100g。
-        try {
-            Integer cnt = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() " +
-                    "AND TABLE_NAME = 'food_nutrients' AND COLUMN_NAME = 'amount_per_100g'", Integer.class);
-            if (cnt != null && cnt > 0) {
-                jdbcTemplate.execute("ALTER TABLE food_nutrients CHANGE COLUMN amount_per_100g amount_per100g DECIMAL(10,4) NOT NULL COMMENT '每100g含量'");
-                log.info("已重命名 food_nutrients.amount_per_100g -> amount_per100g");
-            }
-        } catch (Exception e) {
-            // 表不存在或列不存在,忽略
-        }
-
-        // 迁移292: health_status 补 member_id 并改为成员级归档(Unknown column 'member_id')
-        // 迁移239 建表只有 user_id,schema.sql 与实体已含 member_id(成员级档案),生产缺列导致 selectOne 报错。
-        // 原 UNIQUE KEY uk_user(user_id) 限制每账号仅一行,与成员级多行归档冲突,改为复合索引 idx_user_member。
-        ensureColumn("health_status", "member_id", "BIGINT DEFAULT NULL COMMENT '家庭成员ID(NULL=账号级,非空=成员级归档)'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_status DROP INDEX uk_user");
-            log.info("已移除 health_status.uk_user 唯一键(允许成员级多行归档)");
-        } catch (Exception e) {
-            // 索引不存在,忽略
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_status ADD INDEX idx_user_member (user_id, member_id)");
-            log.info("已添加 health_status.idx_user_member 复合索引");
-        } catch (Exception e) {
-            // 索引已存在,忽略
-        }
-
-        // 迁移293: family_members 添加 is_admin 列(后台家庭成员仅区分管理员/成员,不再区分家长/孩子)
-        ensureColumn("family_members", "is_admin", "TINYINT(1) DEFAULT 0 COMMENT '是否家庭管理员: 1=管理员, 0=普通成员'");
-        // 回填:将每个家庭的创建者(families.creator_id 匹配 family_members.user_id)设为管理员
-        try {
-            jdbcTemplate.execute("UPDATE family_members fm JOIN families f ON fm.family_id = f.id " +
-                    "SET fm.is_admin = 1 WHERE fm.user_id = f.creator_id AND (fm.is_admin IS NULL OR fm.is_admin = 0)");
-            log.info("迁移293: 已回填家庭创建者为管理员");
-        } catch (Exception e) {
-            log.warn("迁移293: 回填家庭创建者为管理员失败: {}", e.getMessage());
-        }
-
-        // 迁移294: articles 表加 sort_order 列(精选文章推荐排序,越小越靠前)
-        ensureColumn("articles", "sort_order", "INT NOT NULL DEFAULT 0 COMMENT '推荐排序值(越小越靠前)'");
-        log.info("已添加 articles.sort_order 列(迁移294)");
-
-        // 迁移295: task_plan_instances 补齐实体已含但 DB 缺失的审核/确认/激活列(review/activate 写字段报 Unknown column)
-        ensureColumn("task_plan_instances", "source", "VARCHAR(20) DEFAULT NULL COMMENT '来源: manual/assessment/template'");
-        ensureColumn("task_plan_instances", "source_result_id", "BIGINT DEFAULT NULL COMMENT '关联测评结果ID(source=assessment时)'");
-        ensureColumn("task_plan_instances", "remark", "TEXT COMMENT '方案备注(含指导意见摘要)'");
-        ensureColumn("task_plan_instances", "reviewed_by", "BIGINT DEFAULT NULL COMMENT '审核人(规划师ID)'");
-        ensureColumn("task_plan_instances", "reviewed_at", "DATETIME DEFAULT NULL COMMENT '审核时间'");
-        ensureColumn("task_plan_instances", "review_comment", "TEXT COMMENT '审核意见'");
-        ensureColumn("task_plan_instances", "confirmed_by", "BIGINT DEFAULT NULL COMMENT '确认人(家长ID)'");
-        ensureColumn("task_plan_instances", "confirmed_at", "DATETIME DEFAULT NULL COMMENT '确认时间'");
-        ensureColumn("task_plan_instances", "activated_at", "DATETIME DEFAULT NULL COMMENT '激活时间'");
-        log.info("迁移295: 已补齐 task_plan_instances 审核/确认/激活列");
-
-        // 迁移296: 健康方案任务 source_type 'plan' -> 'health_plan'(消除与 task_plan_instances 的 ID 域冲突)
-        try {
-            // 冲突检测:source_id 同时存在于 health_plans 和 task_plan_instances 的任务(需人工确认,不阻断迁移)
-            Integer conflict = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM tasks t WHERE t.source_type = 'plan' " +
-                    "AND EXISTS (SELECT 1 FROM health_plans h WHERE h.id = t.source_id) " +
-                    "AND EXISTS (SELECT 1 FROM task_plan_instances i WHERE i.id = t.source_id)",
-                    Integer.class);
-            if (conflict != null && conflict > 0) {
-                log.warn("迁移296: 检测到{}条冲突任务(source_id同时存在于health_plans和task_plan_instances),需人工确认;无冲突部分仍继续迁移", conflict);
-            }
-            // 始终执行 UPDATE:仅迁移"存在于 health_plans 且不存在于 task_plan_instances"的任务(冲突部分不迁移,避免误改套餐任务)
-            int updated = jdbcTemplate.update(
-                    "UPDATE tasks SET source_type = 'health_plan' " +
-                    "WHERE source_type = 'plan' " +
-                    "AND EXISTS (SELECT 1 FROM health_plans h WHERE h.id = tasks.source_id) " +
-                    "AND NOT EXISTS (SELECT 1 FROM task_plan_instances i WHERE i.id = tasks.source_id)");
-            log.info("迁移296: 已修正{}条健康方案任务 source_type -> health_plan", updated);
-        } catch (Exception e) {
-            log.warn("迁移296执行失败(health_plans 表可能不存在): {}", e.getMessage());
-        }
-
-        // 迁移297: 认知训练方案任务补设 source_type='training_plan'(training_plan_tasks 关联溯源)
-        try {
-            Integer updated = jdbcTemplate.update(
-                    "UPDATE tasks t SET t.source_type = 'training_plan' " +
-                    "WHERE (t.source_type IS NULL OR t.source_type = '') " +
-                    "AND EXISTS (SELECT 1 FROM training_plan_tasks pt WHERE pt.task_id = t.id)");
-            log.info("迁移297: 已补设{}条认知训练方案任务 source_type -> training_plan", updated);
-        } catch (Exception e) {
-            log.warn("迁移297执行失败(training_plan_tasks 表可能不存在): {}", e.getMessage());
-        }
-
-// 迁移298: 存量 role='child' 账号强制迁移为成员模型
-        // 1) 有 openid 的 child → role 改 parent(可登录成员,登录后进成员端界面,不能被切换)
-        // 2) 无 openid 的 child → 保持不可登录,确保有 family_members 记录(仅可被切换)
-        try {
-            Integer updated = jdbcTemplate.update(
-                    "UPDATE users SET role='parent' WHERE role='child' AND openid IS NOT NULL AND openid <> ''");
-            log.info("迁移298: 已迁移{}条有 openid 的 child 账号 role → parent", updated);
-        } catch (Exception e) {
-            log.warn("迁移298第一步失败", e);
-        }
-        try {
-            jdbcTemplate.execute(
-                "INSERT INTO family_members (family_id, user_id, nickname, gender, birthday, generation, show_to_family, total_points, created_at, updated_at) " +
-                "SELECT u.family_id, u.id, u.nickname, u.gender, u.birthday, -1, 1, 0, NOW(), NOW() " +
-                "FROM users u " +
-                "WHERE u.role='child' AND (u.openid IS NULL OR u.openid='') " +
-                "AND u.family_id IS NOT NULL " +
-                "AND NOT EXISTS (SELECT 1 FROM family_members fm WHERE fm.user_id = u.id)");
-log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记录");
-        } catch (Exception e) {
-            log.warn("迁移298第二步失败", e);
-        }
-
-
-// 迁移322: 废弃 children 表 —— 数据迁移到 family_members 后删除表(幂等,表不存在时跳过)
-        try {
-            Integer childrenTableCnt = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'children'",
-                    Integer.class);
-            if (childrenTableCnt == null || childrenTableCnt == 0) {
-                log.info("迁移322: children 表不存在,跳过(已废弃)");
-            } else {
-                // 1. 匹配更新:family_members 已存在该成员记录时补全字段
-                jdbcTemplate.execute(
-                        "UPDATE family_members fm INNER JOIN children c " +
-                        "ON fm.family_id = c.family_id AND fm.nickname = c.nickname AND fm.user_id = c.user_id " +
-                        "SET fm.id_card = c.id_card, fm.penalty_enabled = c.penalty_enabled, fm.theme = c.theme, " +
-                        "fm.system_points = c.system_points, fm.streak_days = c.streak_days, fm.last_task_date = c.last_task_date, " +
-                        "fm.focus_max_daily = c.focus_max_daily, fm.focus_remaining = c.focus_remaining, " +
-                        "fm.focus_reset_date = c.focus_reset_date, fm.total_points = c.total_points, " +
-                        "fm.show_to_family = c.show_to_family, fm.birthday = c.birthday, fm.gender = c.gender, " +
-                        "fm.phone = c.phone, fm.role_override = 'child'");
-                log.info("迁移322: 已更新 family_members 中已存在的 children 匹配记录字段");
-
-                // 2. 不匹配则插入新记录
-                jdbcTemplate.execute(
-                        "INSERT INTO family_members (family_id, user_id, nickname, birthday, gender, phone, " +
-                        "id_card, penalty_enabled, theme, system_points, streak_days, last_task_date, " +
-                        "focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points, " +
-                        "role_override, created_at, updated_at) " +
-                        "SELECT family_id, user_id, nickname, birthday, gender, phone, " +
-                        "id_card, penalty_enabled, theme, system_points, streak_days, last_task_date, " +
-                        "focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points, " +
-                        "'child', created_at, updated_at " +
-                        "FROM children " +
-                        "WHERE NOT EXISTS (SELECT 1 FROM family_members fm2 WHERE fm2.family_id = children.family_id " +
-                        "AND fm2.nickname = children.nickname AND fm2.user_id = children.user_id)");
-                log.info("迁移322: 已从 children 插入不匹配记录到 family_members");
-
-                // 3. 删除 children 表
-                jdbcTemplate.execute("DROP TABLE IF EXISTS children");
-                log.info("迁移322: 已删除 children 表(数据已迁移到 family_members)");
-            }
-        } catch (Exception e) {
-            log.warn("迁移322执行失败(children 表可能不存在或迁移范围内字段缺失): {}", e.getMessage());
-        }
-
-
-        ensureColumn("promotion_tier", "rate_percent", "INT DEFAULT 0 COMMENT '当前返佣比例(%)'");
-
-        // 迁移300: family_members 添加 status 列(成员状态: active/recycled,非微信用户被移出进回收箱)
-        ensureColumn("family_members", "status", "VARCHAR(16) DEFAULT 'active' COMMENT '成员状态: active=正常, recycled=回收箱'");
-
-        // ===== 生产库对账候选风险记录(已核对生产库,2026-09,按用户决定不迁移/暂不动,仅记录)=====
-        // 注:以下为 entity 期望但生产库未对齐.项目,用户已决定保持现状或记为候选,勿重复迁移。
-        
-        //    exportUserData 全字段 SELECT 会报 Unknown column 'phone')。schema.sql 已将 children 标为
-        //    已废除/并入 family_members,用户决定不迁移。
-        // 2. user_trigger_rules:生产表仅剩 user_id(PK,auto_increment)/action_config/last_triggered_at,
-        //    实体期望 id/trigger_type/trigger_action/status/created_at 共 8 列,表 0 行且不在 schema.sql。
-        //    UserSegmentationService.getTriggerRules 会查 status,命中时会报 Unknown column 'status'。候选。
-        // 3. promotion_tier.rate_percent:生产用旧模型(tier/team_size_1st/2nd/3rd/total_*),实体期望新模型,
-        
-        // 4. promotion_tier_config:实体已废弃,改用 cf_rate_tier(迁移279),保持现状。
-        // 5. family_members.member_type:实体为 VO 计算值已加 @TableField(exist=false)(不落库),schema.sql
-        //    无此列;2026-09-06 生产已手动 ALTER 补列(JwtInterceptor/SurveyServiceImpl 查询报 Unknown column
-        //    'member_type' 修复,生产旧代码兼容用),部署含 exist=false 的新代码后该列不再被引用,可留可删。
-
-        // 迁移302: tasks表新增is_daily_progress/target_value字段(统一任务系统;原迁移298用 AFTER source_id,列缺失时会被静默吞掉)
-        ensureColumn("tasks", "is_daily_progress", "TINYINT DEFAULT 0 COMMENT '1=每日进度型任务(无deadline,每日重置)'");
-        ensureColumn("tasks", "target_value", "INT DEFAULT NULL COMMENT '进度目标值(is_daily_progress=1时有效)'");
-        try {
-            jdbcTemplate.execute("ALTER TABLE tasks MODIFY COLUMN source_type VARCHAR(32) DEFAULT NULL COMMENT '来源类型: self/assigned/plan/health_plan/training_plan/onboarding/ai/template/article/activity/purchase'");
-            log.info("已更新tasks.source_type注释");
-        } catch (Exception e) {
-            // 修改失败,忽略
-        }
-
-        // 迁移296: admin_task_templates表新增onboarding_sequence字段(统一任务系统:新人引导复用任务模板表)
-        try {
-            jdbcTemplate.execute("ALTER TABLE admin_task_templates ADD COLUMN onboarding_sequence INT DEFAULT NULL COMMENT '新人引导顺序(source_type=onboarding的模板用)' AFTER teacher_id");
-            log.info("已添加onboarding_sequence列到admin_task_templates表");
-        } catch (Exception e) {
-            // 列已存在,忽略
-        }
-
-        // 迁移297: 统一任务系统数据迁移——growth_task DAILY定义迁入admin_task_templates(仅执行一次,幂等)
-        try {
-            Integer migrated = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM sys_config WHERE config_key = 'TASK_UNIFY_GT_MIGRATED'", Integer.class);
-            if (migrated == null || migrated == 0) {
-                // DAILY 类型 → admin_task_templates(title 拼入 [task_key] 前缀,供 updateProgress 匹配)
-                jdbcTemplate.execute("INSERT INTO admin_task_templates (title, description, points, category, need_review, is_active, task_type, frequency, created_at, updated_at) " +
-                        "SELECT CONCAT('[', task_key, ']', title), description, reward_points, '成长', 0, enabled, 'recurring', 'daily', created_at, created_at " +
-                        "FROM growth_task WHERE type = 'DAILY' AND enabled = 1");
-                jdbcTemplate.update("INSERT INTO sys_config (config_key, config_value, description) VALUES ('TASK_UNIFY_GT_MIGRATED', '1', '统一任务系统: growth_task DAILY定义已迁入admin_task_templates')");
-                log.info("迁移297: growth_task DAILY定义已迁入admin_task_templates");
-            }
-        } catch (Exception e) {
-            log.warn("迁移297: growth_task迁移失败或已执行: {}", e.getMessage());
-        }
-        // 说明:growth_task_log 历史进度、onboarding_task 存量数据仅保留在旧表(只读备份),不回填 tasks(历史数据无法1:1映射到新模型)
-
-        // 迁移299: 插入新人引导任务模板种子数据(统一任务系统:onboarding 复用 admin_task_templates)
-        // title = 原 taskType(REGISTER/COMPLETE_PROFILE/...),onboarding_sequence 定义顺序链
-        try {
-            Integer onboardCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admin_task_templates WHERE onboarding_sequence IS NOT NULL", Integer.class);
-            if (onboardCount == null || onboardCount == 0) {
-                jdbcTemplate.execute("INSERT INTO admin_task_templates (title, description, points, category, need_review, is_active, task_type, frequency, onboarding_sequence, created_at, updated_at) VALUES " +
-                        "('REGISTER', '完成注册', 100, '成长', 0, 1, 'onetime', 'none', 1, NOW(), NOW()), " +
-                        "('COMPLETE_PROFILE', '完善个人资料', 50, '成长', 0, 1, 'onetime', 'none', 2, NOW(), NOW()), " +
-                        "('ADD_CHILD', '添加家庭成员', 100, '成长', 0, 1, 'onetime', 'none', 3, NOW(), NOW()), " +
-                        "('FIRST_CHECKIN', '完成首次健康打卡', 30, '成长', 0, 1, 'onetime', 'none', 4, NOW(), NOW()), " +
-                        "('FIRST_TASK', '完成首次任务', 50, '成长', 0, 1, 'onetime', 'none', 5, NOW(), NOW()), " +
-                        "('BIND_REFERRAL', '绑定推荐人', 50, '成长', 0, 1, 'onetime', 'none', 6, NOW(), NOW()), " +
-                        "('COMPLETE_SELF_CHECK', '完成一次五维自检', 60, '成长', 0, 1, 'onetime', 'none', 7, NOW(), NOW())");
-                log.info("迁移299: 已插入7条新人引导任务模板种子数据");
-            }
-        } catch (Exception e) {
-            log.warn("迁移299: 插入新人引导任务模板失败或已存在: {}", e.getMessage());
-        }
-
-        // 迁移301: platform_balance_log 加 (user_id, ref_type, ref_id) 唯一索引(earn 幂等 DB 兜底,防止并发重复发放)
-        try {
-            jdbcTemplate.execute("DELETE l1 FROM platform_balance_log l1 " +
-                    "INNER JOIN platform_balance_log l2 ON l1.user_id = l2.user_id " +
-                    "AND l1.ref_type = l2.ref_type AND l1.ref_id = l2.ref_id AND l1.id > l2.id " +
-                    "WHERE l1.ref_id IS NOT NULL AND l1.ref_type IS NOT NULL");
-            log.info("迁移301: platform_balance_log 历史重复流水已清理");
-            jdbcTemplate.execute("ALTER TABLE platform_balance_log ADD UNIQUE KEY uk_user_ref (user_id, ref_type, ref_id)");
-            log.info("迁移301: platform_balance_log 已添加 uk_user_ref 唯一索引");
-        } catch (Exception e) {
-            log.warn("迁移301: platform_balance_log 唯一索引处理失败: {}", e.getMessage());
-        }
-
-        // 迁移302: 创建 contact_help_logs 表(章鱼图帮助记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS contact_help_logs (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '被帮助者(当前用户)', " +
-                    "contact_id BIGINT NOT NULL COMMENT '帮助者(联系人)', " +
-                    "help_type VARCHAR(32) COMMENT '帮助类型: MONEY/ITEM/EMOTION/RESOURCE/SKILL/TIME', " +
-                    "amount DECIMAL(10,2) DEFAULT 0 COMMENT '帮助金额(非金钱类为0)', " +
-                    "description VARCHAR(255) COMMENT '帮助内容简述', " +
-                    "happened_at DATETIME COMMENT '帮助发生时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_chl_user (user_id), " +
-                    "INDEX idx_chl_contact (contact_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='联系人帮助记录(章鱼图数据源)'");
-            log.info("已创建contact_help_logs表");
-        } catch (Exception e) {
-            log.warn("创建contact_help_logs表失败: {}", e.getMessage());
-        }
-
-        // 迁移303: 创建 resource_items 表(珍珠图资源登记:信息/场所/技能类资源)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS resource_items (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '资源拥有者(当前用户)', " +
-                    "type VARCHAR(16) NOT NULL COMMENT '资源类型: INFO(信息)/PLACE(场所)/SKILL(技能)', " +
-                    "name VARCHAR(100) NOT NULL COMMENT '资源名称', " +
-                    "description VARCHAR(255) COMMENT '资源描述(可调用方式/说明)', " +
-                    "contact_id BIGINT DEFAULT NULL COMMENT '关联联系人ID(可选)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_ri_user (user_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图资源登记表(信息/场所/技能类资源)'");
-            log.info("已创建resource_items表");
-        } catch (Exception e) {
-            log.warn("创建resource_items表失败: {}", e.getMessage());
-        }
-
-        // 迁移304: health_gut_flora.bacteria_name 改为可空(LLM解析偶发缺菌种名,NOT NULL 导致采集入库失败)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_gut_flora MODIFY COLUMN bacteria_name VARCHAR(100) NULL COMMENT '菌种名称'");
-            log.info("迁移304: health_gut_flora.bacteria_name 已改为可空");
-        } catch (Exception e) {
-            log.warn("迁移304: health_gut_flora.bacteria_name 修改失败: {}", e.getMessage());
-        }
-
-        // 迁移305: health_indicators.status 放宽到 VARCHAR(100)(opencode 回退解析产出自由文本 status,
-        //   超长写入报 Data too long for column 'status',draft 入库失败)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_indicators MODIFY COLUMN status VARCHAR(100) NULL COMMENT '评估状态: 正常/偏低/偏高/过多/注意/低风险/未检出'");
-            log.info("迁移305: health_indicators.status 已放宽到 VARCHAR(100)");
-        } catch (Exception e) {
-            log.warn("迁移305: health_indicators.status 修改失败: {}", e.getMessage());
-        }
-
-        // 迁移306: products表添加visible_roles列(商品类型权限过滤,NULL=全部角色可见)
-        try {
-            jdbcTemplate.execute("ALTER TABLE products ADD COLUMN visible_roles JSON DEFAULT NULL COMMENT '可见角色: [\"parent\",\"child\",\"teacher\",\"admin\"],NULL=全部可见'");
-            log.info("迁移306: products.visible_roles 列已添加");
-        } catch (Exception e) {
-            // ignore
-        }
-
-        // 迁移307: resource_items 表添加社会连接分类字段(珍珠图重构:25 类连接类型 + 价值分级)
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD COLUMN connection_type VARCHAR(50) NOT NULL DEFAULT '' COMMENT '连接类型枚举名(ConnectionType)'");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.connection_type 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD COLUMN priority TINYINT DEFAULT 2 COMMENT '优先级: 1=高 2=中 3=低(手动覆盖)'");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.priority 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD COLUMN value_score INT DEFAULT 0 COMMENT '价值分 0-100(自动计算,可手动覆盖)'");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.value_score 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD COLUMN last_interaction_at DATETIME DEFAULT NULL COMMENT '最近互动时间'");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.last_interaction_at 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD COLUMN interaction_count INT DEFAULT 0 COMMENT '互动总次数'");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.interaction_count 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE resource_items ADD INDEX idx_ri_connection_type (connection_type)");
-        } catch (Exception e) {
-            log.warn("迁移307: resource_items.connection_type 索引已存在或添加失败: {}", e.getMessage());
-        }
-        log.info("迁移307: resource_items 社会连接字段添加完成");
-
-        // 迁移308: 创建珍珠图互动日志表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS pearl_interaction_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '操作人', " +
-                    "resource_item_id BIGINT NOT NULL COMMENT '关联资源', " +
-                    "interaction_type VARCHAR(20) NOT NULL COMMENT 'PHONE/WECHAT/MEETING/OTHER', " +
-                    "content VARCHAR(500) DEFAULT NULL COMMENT '互动内容简记', " +
-                    "happened_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '互动发生时间', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_pil_user (user_id), " +
-                    "INDEX idx_pil_resource (resource_item_id), " +
-                    "INDEX idx_pil_happened (happened_at) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动日志'");
-            log.info("迁移308: 已创建 pearl_interaction_log 表");
-        } catch (Exception e) {
-            log.warn("迁移308: 创建 pearl_interaction_log 表失败: {}", e.getMessage());
-        }
-
-        // 迁移309: 创建珍珠图互动提醒表
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS pearl_interaction_reminder (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL, " +
-                    "resource_item_id BIGINT NOT NULL, " +
-                    "connection_type VARCHAR(50) NOT NULL, " +
-                    "suggest_interval_month INT NOT NULL COMMENT '建议互动周期(月)', " +
-                    "last_interaction_at DATETIME DEFAULT NULL, " +
-                    "days_since_last INT NOT NULL COMMENT '距上次互动天数', " +
-                    "status VARCHAR(20) DEFAULT 'PENDING' COMMENT 'PENDING/DONE/DISMISSED', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_pir_user_status (user_id, status), " +
-                    "INDEX idx_pir_resource (resource_item_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动提醒'");
-            log.info("迁移309: 已创建 pearl_interaction_reminder 表");
-        } catch (Exception e) {
-            log.warn("迁移309: 创建 pearl_interaction_reminder 表失败: {}", e.getMessage());
-        }
-
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS octopus_effect_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '当前用户(租户键)', " +
-                    "member_order_id BIGINT COMMENT '关联 MemberSubscriptionOrder.id(会员订单)', " +
-                    "effect_type TINYINT UNSIGNED NOT NULL COMMENT '成效类型 bitmask:1=金额大,2=频次高,4=新成交(支持多选)', " +
-                    "effect_amount DECIMAL(10,2) DEFAULT 0 COMMENT '成效金额(元)', " +
-                    "effect_desc VARCHAR(500) COMMENT '成效描述', " +
-                    "status TINYINT DEFAULT 1 COMMENT '1=有效,0=无效', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_oer_user (user_id), " +
-                    "INDEX idx_oer_order (member_order_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关键人拓展-成效记录'");
-            log.info("已创建octopus_effect_record表");
-        } catch (Exception e) {
-            log.warn("创建octopus_effect_record表失败: {}", e.getMessage());
-        }
-
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS octopus_key_person (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '当前用户(租户键)', " +
-                    "name VARCHAR(64) NOT NULL COMMENT '关键人姓名', " +
-                    "organization VARCHAR(128) COMMENT '单位/公司', " +
-                    "department VARCHAR(64) COMMENT '部门', " +
-                    "title VARCHAR(64) COMMENT '职务/职位', " +
-                    "first_meet_scene VARCHAR(128) COMMENT '初识场合', " +
-                    "know_way VARCHAR(255) COMMENT '如何认识(认识路径)', " +
-                    "contact_info VARCHAR(255) COMMENT '联系方式(可选)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_okp_user (user_id), " +
-                    "INDEX idx_okp_org (organization) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关键人画像'");
-            log.info("已创建octopus_key_person表");
-        } catch (Exception e) {
-            log.warn("创建octopus_key_person表失败: {}", e.getMessage());
-        }
-
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS octopus_effect_key_person (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "effect_id BIGINT NOT NULL COMMENT '关联 octopus_effect_record.id', " +
-                    "key_person_id BIGINT NOT NULL COMMENT '关联 octopus_key_person.id', " +
-                    "role TINYINT NOT NULL COMMENT '1=引荐,2=决策,3=其他', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_oekp_effect (effect_id), " +
-                    "INDEX idx_oekp_person (key_person_id), " +
-                    "UNIQUE KEY uk_oekp (effect_id,key_person_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成效-关键人关联'");
-            log.info("已创建octopus_effect_key_person表");
-        } catch (Exception e) {
-            log.warn("创建octopus_effect_key_person表失败: {}", e.getMessage());
-        }
-
-        // 迁移310: health_meal_record 表添加 record_date(补打日期)与 is_backfill(是否补打)字段(饮食记录重设计)
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_meal_record ADD COLUMN record_date DATE NULL COMMENT '用餐日期(补打时为实际用餐日,默认等于创建日)'");
-            log.info("迁移310: health_meal_record.record_date 列已添加");
-        } catch (Exception e) {
-            log.warn("迁移310: health_meal_record.record_date 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_meal_record ADD COLUMN is_backfill TINYINT DEFAULT 0 COMMENT '是否补打: 1=补打(无能量值), 0=当日打卡'");
-            log.info("迁移310: health_meal_record.is_backfill 列已添加");
-        } catch (Exception e) {
-            log.warn("迁移310: health_meal_record.is_backfill 已存在或添加失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE health_meal_record ADD INDEX idx_meal_record_date (member_id, record_date)");
-            log.info("迁移310: health_meal_record (member_id, record_date) 索引已添加");
-        } catch (Exception e) {
-            log.warn("迁移310: health_meal_record 索引已存在或添加失败: {}", e.getMessage());
-        }
-
-        // 迁移310: health_reports / health_report_drafts 补 file_hash 列
-        // 实体与 schema.sql 已含该列,但建表迁移从未 ADD;upload-only 按 MD5 去重时 SELECT 报 Unknown column 'file_hash'
-        ensureColumn("health_reports", "file_hash",
-                "VARCHAR(64) DEFAULT NULL COMMENT '文件MD5哈希,用于重复上传检测'");
-        ensureColumn("health_report_drafts", "file_hash",
-                "VARCHAR(64) DEFAULT NULL COMMENT '文件MD5哈希,用于重复上传检测'");
-        log.info("迁移310: 已补齐 health_reports/health_report_drafts.file_hash");
-
-        // 迁移311: report_type_registry 补 script_status 列
-        // 实体/schema 已含;异步采集指纹识别 SELECT 全字段时报 Unknown column 'script_status'
-        ensureColumn("report_type_registry", "script_status",
-                "VARCHAR(20) DEFAULT NULL COMMENT '采集脚本生成状态: generating/ready/failed'");
-        log.info("迁移311: 已补齐 report_type_registry.script_status");
-
-        // 迁移312: 为 gut_flora 补默认指纹规则(空表会导致指纹引擎永远 unknown)
-        seedGutFloraFingerprints();
-
-        // 迁移316-329: 原误置于 seedGutFloraFingerprints 早返回(return)之后,gut_flora 指纹存在时永不执行;
-        // 现移至 runSystemMigrations 无条件执行(recommendation_rules / task_orchestration / onboarding_guide_config / 打卡表照片语音字段)
-        // 迁移316: 创建 recommendation_rules 表(统一推荐规则配置)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS recommendation_rules (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "rule_type TINYINT NOT NULL COMMENT '1-5', " +
-                    "rule_name VARCHAR(100) COMMENT '运营名称', " +
-                    "trigger_product_id BIGINT COMMENT '触发商品ID', " +
-                    "trigger_product_ids VARCHAR(1000) COMMENT '触发商品ID JSON 数组', " +
-                    "target_product_id BIGINT COMMENT '目标商品ID', " +
-                    "priority INT DEFAULT 10 COMMENT '优先级,越大越优', " +
-                    "enabled TINYINT DEFAULT 1 COMMENT '启用 1/0', " +
-                    "time_window_days INT COMMENT '回溯窗口(天)', " +
-                    "delay_days INT COMMENT '复购延迟天数', " +
-                    "scope VARCHAR(20) COMMENT 'family/individual', " +
-                    "scene_codes VARCHAR(500) COMMENT '生效场景 JSON 数组', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐规则配置'");
-            log.info("迁移316: 已创建recommendation_rules表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移317: recommendation_rules 表索引
-        try {
-            jdbcTemplate.execute("CREATE INDEX idx_rules_enabled ON recommendation_rules(enabled)");
-            log.info("迁移317: 已创建idx_rules_enabled索引");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("CREATE INDEX idx_rules_scene ON recommendation_rules(scene_codes)");
-            log.info("迁移317: 已创建idx_rules_scene索引");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("CREATE INDEX idx_rules_priority ON recommendation_rules(priority)");
-            log.info("迁移317: 已创建idx_rules_priority索引");
-        } catch (Exception e) {
-            // 索引已存在,忽略错误
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_flows` (" +
-                    "`id` bigint NOT NULL AUTO_INCREMENT," +
-                    "`name` varchar(100) NOT NULL," +
-                    "`description` text," +
-                    "`creator_id` bigint NOT NULL," +
-                    "`family_id` bigint DEFAULT NULL," +
-                    "`version` int NOT NULL DEFAULT 1," +
-                    "`status` varchar(20) NOT NULL DEFAULT 'draft'," +
-                    "`schedule_cron` varchar(64) DEFAULT NULL," +
-                    "`config_json` json DEFAULT NULL," +
-                    "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
-                    "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "PRIMARY KEY (`id`)," +
-                    "KEY `idx_family_id` (`family_id`)," +
-                    "KEY `idx_status` (`status`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流定义'");
-            log.info("迁移329: 已创建task_orchestration_flows表");
-        } catch (Exception e) {
-            log.warn("迁移329: task_orchestration_flows 已存在或创建失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_edges` (" +
-                    "`id` bigint NOT NULL AUTO_INCREMENT," +
-                    "`flow_id` bigint NOT NULL," +
-                    "`from_node_id` varchar(64) NOT NULL," +
-                    "`to_node_id` varchar(64) NOT NULL," +
-                    "`edge_type` varchar(20) NOT NULL," +
-                    "`operator` varchar(10) NOT NULL DEFAULT 'AND'," +
-                    "`sort_order` int NOT NULL DEFAULT 0," +
-                    "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
-                    "PRIMARY KEY (`id`)," +
-                    "KEY `idx_flow_id` (`flow_id`)," +
-                    "UNIQUE KEY `uk_flow_edge` (`flow_id`, `from_node_id`, `to_node_id`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流边定义'");
-            log.info("迁移329: 已创建task_orchestration_edges表");
-        } catch (Exception e) {
-            log.warn("迁移329: task_orchestration_edges 已存在或创建失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_executions` (" +
-                    "`id` bigint NOT NULL AUTO_INCREMENT," +
-                    "`flow_id` bigint NOT NULL," +
-                    "`flow_version` int NOT NULL DEFAULT 1," +
-                    "`family_id` bigint NOT NULL," +
-                    "`family_member_id` bigint NOT NULL," +
-                    "`trigger_source` varchar(20) NOT NULL DEFAULT 'manual'," +
-                    "`status` varchar(20) NOT NULL DEFAULT 'running'," +
-                    "`started_at` datetime NOT NULL," +
-                    "`finished_at` datetime DEFAULT NULL," +
-                    "`error_reason` varchar(255) DEFAULT NULL," +
-                    "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
-                    "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "PRIMARY KEY (`id`)," +
-                    "KEY `idx_execution_flow` (`flow_id`)," +
-                    "KEY `idx_execution_status` (`status`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流执行记录'");
-            log.info("迁移329: 已创建task_orchestration_executions表");
-        } catch (Exception e) {
-            log.warn("迁移329: task_orchestration_executions 已存在或创建失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS `task_orchestration_node_instances` (" +
-                    "`id` bigint NOT NULL AUTO_INCREMENT," +
-                    "`execution_id` bigint NOT NULL," +
-                    "`node_id` varchar(64) NOT NULL," +
-                    "`task_id` bigint DEFAULT NULL," +
-                    "`status` varchar(20) NOT NULL DEFAULT 'pending'," +
-                    "`generation` int NOT NULL DEFAULT 0," +
-                    "`condition_met_at` datetime DEFAULT NULL COMMENT '条件终止:外部API通知条件达成时间'," +
-                    "`loop_termination_reason` varchar(50) DEFAULT NULL," +
-                    "`started_at` datetime DEFAULT NULL," +
-                    "`completed_at` datetime DEFAULT NULL," +
-                    "`error_reason` varchar(255) DEFAULT NULL," +
-                    "`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP," +
-                    "`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "PRIMARY KEY (`id`)," +
-                    "UNIQUE KEY `uk_node_instance` (`execution_id`, `node_id`, `generation`)," +
-                    "KEY `idx_execution_id` (`execution_id`)," +
-                    "KEY `idx_task_id` (`task_id`)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流节点实例'");
-            log.info("迁移329: 已创建task_orchestration_node_instances表");
-        } catch (Exception e) {
-            log.warn("迁移329: task_orchestration_node_instances 已存在或创建失败: {}", e.getMessage());
-        }
-
-        // 迁移318: sys_config 预置首页引导浮层默认配置(onboarding_guide_config key)
-        try {
-            String defaultConfig = "{"
-                + "\"enabled\":true,"
-                + "\"version\":\"1.0\","
-                + "\"positions\":[\"home\",\"child\"],"
-                + "\"parent\":["
-                    + "{\"icon\":\"🔍\",\"title\":\"你真的了解孩子的状态吗?\",\"desc\":\"情绪低落没察觉、习惯变化没注意、能力短板没发现——很多问题等爆发了才看见。浠艾福帮你在问题发生前,看清孩子真实的身心状态。\",\"isIntro\":true},"
-                    + "{\"icon\":\"🌏\",\"title\":\"五维沙盘,看见全家\",\"desc\":\"身·心·智·行·富,一张全景图看清每个维度。孩子身体好不好、情绪怎么样、能力到哪了——不用猜,看得见.\"},"
-                    + "{\"icon\":\"📋\",\"title\":\"小任务,大改变\",\"desc\":\"布置每日小任务,完成就能攒星星。每天一点点积累,好习惯自然养成.\"},"
-                    + "{\"icon\":\"🎁\",\"title\":\"心愿墙,看得见努力\",\"desc\":\"孩子攒够星星就能兑换心愿。努力有回报,目标感和坚持力一起培养.\"}"
-                + "],"
-                + "\"child\":["
-                    + "{\"icon\":\"🔍\",\"title\":\"你的每一点成长,都被看见\",\"desc\":\"今天完成了几个任务?比昨天进步了多少?浠艾福帮你记录每一点努力,让成长看得见。\",\"isIntro\":true},"
-                    + "{\"icon\":\"🌟\",\"title\":\"赚星星\",\"desc\":\"完成爸爸妈妈布置的任务,就能获得星星积分,越努力越多!\"},"
-                    + "{\"icon\":\"🎮\",\"title\":\"玩中学\",\"desc\":\"完成任务后可以玩小游戏、兑换心愿,学习和快乐两不误!\"},"
-                    + "{\"icon\":\"🏆\",\"title\":\"升级挑战\",\"desc\":\"从星星宝宝到宇宙小英雄,一步步升级,看看你能走多远!\"}"
-                + "]"
-                + "}";
-            jdbcTemplate.update(
-                "INSERT IGNORE INTO sys_config (config_key, config_value, description) VALUES ('onboarding_guide_config', ?, '首页引导浮层配置')",
-                defaultConfig
-            );
-            log.info("迁移318: 已预置onboarding_guide_config默认配置");
-        } catch (Exception e) {
-            log.warn("预置onboarding_guide_config可能已存在: {}", e.getMessage());
-        }
-        // 迁移328: 饮食/运动打卡表补充照片与语音字段(前端已上传 media URL,补上持久化列)
-        try {
-            ensureColumn("health_meal_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
-            ensureColumn("health_meal_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
-            ensureColumn("health_meal_record", "voice_text", "TEXT COMMENT '语音转写文字'");
-            ensureColumn("exercise_record", "photo_urls", "TEXT COMMENT '照片URL列表(逗号分隔)'");
-            ensureColumn("exercise_record", "voice_url", "VARCHAR(500) COMMENT '语音URL'");
-            ensureColumn("exercise_record", "voice_text", "TEXT COMMENT '语音转写文字'");
-            log.info("迁移328: 已为health_meal_record/exercise_record补充照片语音字段");
-        } catch (Exception e) {
-            log.warn("迁移328: 补充照片语音字段失败: {}", e.getMessage());
-        }
-
-        // 迁移333-336: 引导弹窗配置表(guide_popup 系列,原远程版本误置于 seedGutFloraFingerprints 早返回之后,
-        // 现并入 runSystemMigrations 无条件执行;编号 333-336 为本地迁移329(task_orchestration)以后的续号)
-        // 迁移333: 创建 guide_popup 表(弹窗引导页配置化管理)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "slug VARCHAR(64) NOT NULL UNIQUE COMMENT '唯一标识', " +
-                    "title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '弹窗标题', " +
-                    "description TEXT COMMENT '主描述文案', " +
-                    "icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '图标:emoji或图片URL', " +
-                    "icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片', " +
-                    "theme_color VARCHAR(20) NOT NULL DEFAULT '#F97316' COMMENT '主题色', " +
-                    "btn_text VARCHAR(64) NOT NULL DEFAULT '知道了' COMMENT '按钮文案', " +
-                    "btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '点击跳转路径,空=关闭', " +
-                    "status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0=禁用 1=启用', " +
-                    "sort_order INT NOT NULL DEFAULT 0 COMMENT '排序优先级', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', " +
-                    "INDEX idx_status_sort (status, sort_order)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗配置表'");
-            log.info("迁移333: 已创建 guide_popup 表");
-        } catch (Exception e) {
-            log.warn("guide_popup 表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移334: 创建 guide_popup_step 表(引导弹窗步骤)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_step (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
-                    "step_order INT NOT NULL DEFAULT 0 COMMENT '步骤顺序', " +
-                    "title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '步骤标题', " +
-                    "`desc` TEXT COMMENT '步骤描述', " +
-                    "icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '步骤图标', " +
-                    "icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片', " +
-                    "is_intro TINYINT NOT NULL DEFAULT 0 COMMENT '是否为开场身份定义页', " +
-                    "btn_text VARCHAR(64) NOT NULL DEFAULT '下一步' COMMENT '本步骤按钮文案', " +
-                    "btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '最后一步跳转链接', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_popup_order (popup_id, step_order)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗步骤表'");
-            log.info("迁移334: 已创建 guide_popup_step 表");
-        } catch (Exception e) {
-            log.warn("guide_popup_step 表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移335: 创建 guide_popup_trigger 表(引导弹窗触发条件)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_trigger (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
-                    "trigger_type VARCHAR(32) NOT NULL COMMENT '触发类型:page_enter/task_complete/assessment_done/first_login/daily_active/role_change', " +
-                    "target_page VARCHAR(128) DEFAULT '' COMMENT '目标页面路径', " +
-                    "target_action VARCHAR(128) DEFAULT '' COMMENT '触发行为标识', " +
-                    "min_role VARCHAR(32) DEFAULT 'parent' COMMENT '最低角色要求', " +
-                    "extra_config JSON DEFAULT NULL COMMENT '扩展条件', " +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', " +
-                    "INDEX idx_popup_trigger (popup_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗触发条件表'");
-            log.info("迁移335: 已创建 guide_popup_trigger 表");
-        } catch (Exception e) {
-            log.warn("guide_popup_trigger 表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移336: 创建 guide_popup_log 表(引导弹窗用户消费记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS guide_popup_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID', " +
-                    "popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id', " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID users.id', " +
-                    "member_id BIGINT DEFAULT NULL COMMENT '家庭成员ID family_members.id', " +
-                    "role VARCHAR(32) NOT NULL COMMENT '弹出时所在角色', " +
-                    "consumed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '消费时间', " +
-                    "button_clicked TINYINT NOT NULL DEFAULT 0 COMMENT '是否点击按钮', " +
-                    "INDEX idx_user_popup (user_id, popup_id), " +
-                    "INDEX idx_consume_time (consumed_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗用户消费记录表'");
-            log.info("迁移336: 已创建 guide_popup_log 表");
-        } catch (Exception e) {
-            log.warn("guide_popup_log 表可能已存在: {}", e.getMessage());
-        }
-
-
-
-        // 迁移323: 注册素质测评A2报告类型(dan家族)+ 默认指纹规则
-        // 统一上传后指纹识别为 dan_a2 → ReportCollectService 按 report_type_registry.family=dan 分流走 DAN 采集管道
-        try {
-            Integer danA2Count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM report_type_registry WHERE type_id = ?", Integer.class, "dan_a2");
-            if (danA2Count == null || danA2Count == 0) {
-                jdbcTemplate.update(
-                        "INSERT INTO report_type_registry (type_id, family, display_name, description, parser_path, " +
-                        "min_confidence, is_active, source, review_status, version, created_at, updated_at) " +
-                        "VALUES ('dan_a2', 'dan', '素质测评A2', '核心素养评估报告:大五人格/认知能力/社会关系等', " +
-                        "NULL, 30, 1, 'prebuilt', 'approved', '1.0', NOW(), NOW())");
-                log.info("迁移323: 已注册报告类型 dan_a2(dan家族)");
-            } else {
-                log.info("迁移323: 报告类型 dan_a2 已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("迁移323: 注册 dan_a2 类型失败: {}", e.getMessage());
-        }
-        seedDanA2Fingerprints();
-        seedDiscountRulesMenu();
-        createUserShortcutConfigTable();
-        createUserAppUsageTable();
-        seedGuidePopupData();
-        addGiftAmountColumn();
-        createGiftMembershipProgressTable();
-        addFlowTaskColumnsToTasksTable();
-        addPolicyTermsColumn();
-        createHomeBannersTable();
-        ensureHealthReportDraftsMemberIdColumn();
-        ensureHealthPlansTotalDaysColumn();
-        seedTaskReminderTemplate();
-        backfillHealthPlanTaskPrerequisite();
-        backfillTemplateInstanceFamilyMemberId();
-        createReportTransferRequestsTable();
-        addProductMinDiscountLevel();
-        restoreBasicMembershipLevel();
-        backfillMembershipLevelOrder();
-        removeReportUploadQuota();
-
-        createProductDimensionMappingTable();
-        createProductRecommendationLogTable();
-        createRepurchaseReminderTables();
-        createRecommendationProductAssociationsTable();
-        addAbTestColumnsToRecommendationLog();
-        createTaskReminderConfigTable();
-        addMissingColumnsToRecommendationLog();
-        createDietFamilySelectedIngredientsTable();
-        createSsoTicketTable();
-
-        // 迁移327: 创建 report_feedback 表(报告反馈+AI解答)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_feedback (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '提交人 users.id', " +
-                    "member_id BIGINT DEFAULT NULL COMMENT '关联家庭成员 family_members.id', " +
-                    "report_id BIGINT DEFAULT NULL COMMENT '健康报告ID', " +
-                    "draft_id BIGINT DEFAULT NULL COMMENT '草稿ID', " +
-                    "feedback_type VARCHAR(20) DEFAULT 'question' COMMENT 'question=疑问 / suggestion=建议', " +
-                    "content VARCHAR(500) NOT NULL COMMENT '反馈内容', " +
-                    "ai_answer TEXT COMMENT 'AI 解答', " +
-                    "ai_status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/answered/failed', " +
-                    "conversation_id VARCHAR(64) DEFAULT NULL COMMENT 'AI 会话ID(付费多轮)', " +
-                    "created_at DATETIME NOT NULL COMMENT '创建时间', " +
-                    "INDEX idx_rf_user (user_id, created_at), " +
-                    "INDEX idx_rf_report (report_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告反馈与AI解答'");
-            log.info("迁移327: 已创建 report_feedback 表");
-        } catch (Exception e) {
-            // 表已存在,忽略错误
-        }
-
-        // 迁移313: 修复 meal_configs 历史双编码 participant_member_ids(共餐配置前端曾 JSON.stringify 二次编码,存成了 "\"[1,2]\"",
-        //          导致再次进入页面时无法识别选中成员)。仅处理以双引号包裹的值,不触碰正常 "[]..." 格式
-        try {
-            jdbcTemplate.execute("UPDATE meal_configs SET participant_member_ids = JSON_UNQUOTE(participant_member_ids) " +
-                    "WHERE participant_member_ids LIKE '\"%\"' ");
-            log.info("迁移313: 已修复 meal_configs 双编码 participant_member_ids");
-        } catch (Exception e) {
-            log.warn("迁移313: 修复 meal_configs participant_member_ids 失败: {}", e.getMessage());
-        }
-
-// 迁移314: meal_configs 增加 config_date 字段(当天临时共餐配置)+ 修改 UNIQUE KEY
-        // 支持「今天」模式:config_date 有值=当天临时配置(优先级最高),config_date=NULL+config_date_type=工作日/周末默认配置
-        try {
-            jdbcTemplate.execute("ALTER TABLE meal_configs ADD COLUMN config_date DATE DEFAULT NULL COMMENT '当天临时配置日期(NULL=默认工作日/周末配置)'");
-            log.info("迁移314: meal_configs 已添加 config_date 列");
-        } catch (Exception e) {
-            log.warn("迁移314: meal_configs 添加 config_date 列失败(可能已存在): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE meal_configs ADD COLUMN config_date_eff DATE GENERATED ALWAYS AS (COALESCE(config_date, '9999-12-31')) STORED COMMENT '生效日期(NULL映射为9999-12-31,用于唯一约束)'");
-            log.info("迁移314: meal_configs 已添加生成列 config_date_eff");
-        } catch (Exception e) {
-            log.warn("迁移314: meal_configs 添加 config_date_eff 生成列失败(可能已存在): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE meal_configs DROP INDEX uk_config");
-            log.info("迁移314: meal_configs 已删除旧 UNIQUE KEY uk_config");
-        } catch (Exception e) {
-            log.warn("迁移314: 删除旧 UNIQUE KEY 失败(可能不存在): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE meal_configs ADD UNIQUE KEY uk_config (family_id, config_date_eff, meal_type)");
-            log.info("迁移314: meal_configs 已添加新 UNIQUE KEY uk_config(支持当天临时配置)");
-        } catch (Exception e) {
-            log.warn("迁移314: 添加新 UNIQUE KEY 失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE meal_configs ADD INDEX idx_config_date (config_date)");
-            log.info("迁移314: meal_configs 已添加索引 idx_config_date");
-        } catch (Exception e) {
-            log.warn("迁移314: meal_configs 添加索引 idx_config_date 失败(可能已存在): {}", e.getMessage());
-        }
-
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS doa_stage (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "member_id BIGINT NOT NULL COMMENT '目标归属成员ID(family_members.id)', " +
-                    "title VARCHAR(200) COMMENT '阶段主题(可选)', " +
-                    "start_date DATE NOT NULL COMMENT '阶段开始日期', " +
-                    "end_date DATE NOT NULL COMMENT '阶段结束日期', " +
-                    "duration_weeks TINYINT NOT NULL COMMENT '周期周数:2/4/8/12', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT 'active/completed/cancelled', " +
-                    "created_by BIGINT NOT NULL COMMENT '创建人userId(代管时为代管人)', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_ds_family_member (family_id, member_id), " +
-                    "INDEX idx_ds_status (status) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 阶段'");
-            log.info("迁移318: 已创建 doa_stage 表");
-        } catch (Exception e) {
-            log.warn("迁移318: 创建 doa_stage 表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS doa_goal (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "stage_id BIGINT NOT NULL COMMENT '所属阶段ID', " +
-                    "domain VARCHAR(20) NOT NULL COMMENT '领域:health/wealth/family/social/help', " +
-                    "content VARCHAR(500) NOT NULL COMMENT '量化目标内容', " +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT 'active/achieved/abandoned', " +
-                    "sort_order TINYINT DEFAULT 0 COMMENT '排序', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_dg_stage (stage_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 阶段目标'");
-            log.info("迁移318: 已创建 doa_goal 表");
-        } catch (Exception e) {
-            log.warn("迁移318: 创建 doa_goal 表失败: {}", e.getMessage());
-        }
-
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS doa_week (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "stage_id BIGINT NOT NULL COMMENT '所属阶段ID', " +
-                    "week_no TINYINT NOT NULL COMMENT '第几周(1起)', " +
-                    "week_start DATE NOT NULL COMMENT '本周开始(周一)', " +
-                    "week_end DATE NOT NULL COMMENT '本周结束(周日)', " +
-                    "plan TEXT COMMENT '周行动宣告计划(A表)', " +
-                    "achieved TEXT COMMENT '复盘:本周达成了什么', " +
-                    "experience TEXT COMMENT '复盘:有什么体验', " +
-                    "worked TEXT COMMENT '复盘:行得通的', " +
-                    "improve TEXT COMMENT '复盘:要提升/行不通的', " +
-                    "next_challenge TEXT COMMENT '复盘:下周挑战自己什么', " +
-                    "status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/planned/reviewed', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_dw_stage_week (stage_id, week_no), " +
-                    "INDEX idx_dw_stage (stage_id) " +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 周记录'");
-            log.info("迁移318: 已创建 doa_week 表");
-        } catch (Exception e) {
-            log.warn("迁移318: 创建 doa_week 表失败: {}", e.getMessage());
-        }
-
-        // 迁移318: 基础管理分组挂载「系统提示词」菜单(cfc-web菜单树同步)
-        migrateSystemPromptMenu();
-
-        // 迁移319: system_prompts 插入 health_plan 提示词种子(仅当不存在时)
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                "SELECT COUNT(*) FROM system_prompts WHERE prompt_key = 'health_plan'", Integer.class);
-            if (count == null || count == 0) {
-                jdbcTemplate.update(
-                    "INSERT INTO system_prompts (prompt_key, title, content, default_content, version, status, remark) VALUES (?, ?, ?, ?, 1, 1, ?)",
-                    "health_plan", "健康方案生成",
-                    "你是一个专业的家庭健康方案规划师。根据用户的健康数据和目标,生成结构化的改善方案。\n\n" +
-                    "## 输出格式(必须严格遵守 JSON)\n\n" +
-                    "```\n" +
-                    "{\n" +
-                    "  \"overview\": \"总体概述(100字以内,说明方案目标和核心策略)\",\n" +
-                    "  \"sections\": [\n" +
-                    "    {\n" +
-                    "      \"key\": \"nutrition\",\n" +
-                    "      \"title\": \"营养补充建议\",\n" +
-                    "      \"content\": \"Markdown 格式的详细内容,包含具体产品推荐、用量、服用时间\",\n" +
-                    "      \"items\": [{\"name\": \"产品名\", \"dosage\": \"用量\", \"timing\": \"服用时间\", \"reason\": \"推荐理由\"}]\n" +
-                    "    },\n" +
-                    "    {\n" +
-                    "      \"key\": \"diet\",\n" +
-                    "      \"title\": \"饮食建议\",\n" +
-                    "      \"content\": \"Markdown 格式的餐饮建议,包含早餐/午餐/晚餐建议\",\n" +
-                    "      \"items\": [{\"meal\": \"餐型\", \"food\": \"食物建议\", \"notes\": \"注意事项\"}]\n" +
-                    "    },\n" +
-                    "    {\n" +
-                    "      \"key\": \"exercise\",\n" +
-                    "      \"title\": \"运动计划\",\n" +
-                    "      \"content\": \"Markdown 格式的运动建议,包含频率、时长、类型\",\n" +
-                    "      \"items\": [{\"type\": \"运动类型\", \"duration\": \"时长\", \"frequency\": \"频率\", \"notes\": \"注意事项\"}]\n" +
-                    "    }\n" +
-                    "  ]\n" +
-                    "}\n" +
-                    "```\n\n" +
-                    "## 原则\n" +
-                    "1. 基于实际数据给出建议,不编造\n" +
-                    "2. 引用知识库时标注来源\n" +
-                    "3. 建议要具体可执行,避免空泛\n" +
-                    "4. 营养补充部分要具体到品牌/产品类型和用量\n" +
-                    "5. 严重健康问题建议咨询医生",
-                    "你是一个专业的家庭健康方案规划师。根据用户的健康数据和目标,生成结构化的改善方案。",
-                    "健康方案生成 prompt(营养+饮食+运动三段结构化输出)");
-                log.info("迁移319: 已插入 health_plan 提示词种子数据");
-            } else {
-                log.info("迁移319: health_plan 提示词已存在,跳过");
-            }
-        } catch (Exception e) {
-            log.warn("迁移319: 插入 health_plan 提示词种子数据失败: {}", e.getMessage());
-    }
-
-        try {
-            jdbcTemplate.execute("ALTER TABLE exercise_record ADD COLUMN step_count INT COMMENT '微信运动步数'");
-            log.info("迁移320: exercise_record.step_count 列已添加");
-        } catch (Exception e) {
-            log.warn("迁移320: exercise_record.step_count 列已存在或添加失败: {}", e.getMessage());
-        }
-
-        // 迁移321: 商品/分类可见性由「角色」改为「按会员级别」控制
-        // - membership_levels.level_order: 级别数字(数字越小级别越低): FREE=1 FAMILY=2 PROVIDER=3 PREMIUM=4 LIFETIME=5
-        // - products.min_visible_level: 最低可见会员级别编码(NULL=所有用户含未登录可见)
-        // - shop_categories.min_visible_level: 分类最低可见会员级别编码(NULL=所有用户含未登录可见)
-        ensureColumn("membership_levels", "level_order",
-                "INT DEFAULT 1 COMMENT '级别数字(越小级别越低): FREE=1 FAMILY=2 PROVIDER=3 PREMIUM=4 LIFETIME=5'");
-        try {
-            jdbcTemplate.update("UPDATE membership_levels SET level_order = CASE level_code " +
-                    "WHEN 'FREE' THEN 1 WHEN 'FAMILY' THEN 2 WHEN 'PROVIDER' THEN 3 " +
-                    "WHEN 'PREMIUM' THEN 4 WHEN 'LIFETIME' THEN 5 ELSE level_order END");
-            log.info("迁移321: 已回填 membership_levels.level_order");
-        } catch (Exception e) {
-            log.warn("迁移321: 回填 membership_levels.level_order 失败: {}", e.getMessage());
-        }
-        ensureColumn("products", "min_visible_level",
-                "VARCHAR(50) DEFAULT NULL COMMENT '最低可见会员级别编码(FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME, NULL=全部可见)'");
-        ensureColumn("shop_categories", "min_visible_level",
-                "VARCHAR(50) DEFAULT NULL COMMENT '最低可见会员级别编码(FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME, NULL=全部可见)'");
-        log.info("迁移321: 已完成商品/分类按会员级别可见性改造");
-
-        // 迁移299: 创建 article_quiz_records 表(文章阅读答题记录)
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS article_quiz_records (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "article_id BIGINT DEFAULT NULL, " +
-                    "user_id BIGINT DEFAULT NULL, " +
-                    "member_id BIGINT DEFAULT NULL, " +
-                    "questions TEXT, " +
-                    "answers TEXT, " +
-                    "score INT DEFAULT 0, " +
-                    "total_questions INT DEFAULT 0, " +
-                    "cf_earned INT DEFAULT 0, " +
-                    "energy_earned INT DEFAULT 0, " +
-                    "created_at DATETIME, " +
-                    "updated_at DATETIME, " +
-                    "INDEX idx_member (member_id), " +
-                    "INDEX idx_article (article_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章答题记录表'");
-            log.info("已创建article_quiz_records表");
-        } catch (Exception e) {
-            log.warn("创建article_quiz_records表可能已存在: {}", e.getMessage());
-        }
-
-        // 迁移300: profile_snapshot 增加 quiz_summary 列(答题认知雷达汇总)
-        ensureColumn("profile_snapshot", "quiz_summary", "JSON DEFAULT NULL COMMENT '答题认知雷达汇总'");
-
-        // 迁移323: dan_assessment_results 添加 language_score 列(游戏化认知测评:语言表达维度)
-        ensureColumn("dan_assessment_results", "language_score", "INT COMMENT '语言表达得分'");
-        log.info("迁移323: 已确保 language_score 列存在于 dan_assessment_results");
-
-        // 迁移324-325: octopus_effect_record 添加 happened_at 列 + article_reading_records 回填与补列
-        try {
-            jdbcTemplate.execute("ALTER TABLE octopus_effect_record ADD COLUMN happened_at DATETIME COMMENT '成效发生时间'");
-            log.info("迁移324: octopus_effect_record.happened_at 列已添加");
-        } catch (Exception e) {
-            log.warn("迁移324: octopus_effect_record.happened_at 列已存在或添加失败: {}", e.getMessage());
-        }
-
-        try {
-            int updated = jdbcTemplate.update(
-                    "UPDATE article_reading_records r " +
-                    "LEFT JOIN tasks t ON r.task_id = t.id AND t.source_type = 'article' " +
-                    "SET r.article_id = t.source_id " +
-                    "WHERE r.article_id IS NULL AND t.id IS NOT NULL AND t.source_id IS NOT NULL"
-            );
-            log.info("迁移325: 已回填 article_reading_records.article_id {} 条记录", updated);
-        } catch (Exception e) {
-            log.warn("迁移325: 回填 article_reading_records.article_id 失败: {}", e.getMessage());
-        }
-
-        ensureColumn("article_reading_records", "reading_completed", "TINYINT DEFAULT 0 COMMENT '是否已阅读达标(达到最低时长阈值)'");
-
-        // 迁移342: octopus_key_person 添加 first_meet_time / referrer_id / system_user_id 列(感恩记录新增字段)
-        ensureColumn("octopus_key_person", "first_meet_time", "DATETIME COMMENT '相识具体时间'");
-        log.info("迁移342: octopus_key_person.first_meet_time 列已添加");
-        ensureColumn("octopus_key_person", "referrer_id", "BIGINT DEFAULT NULL COMMENT '介绍人关键人ID(指向同用户另一条关键人)'");
-        log.info("迁移342: octopus_key_person.referrer_id 列已添加");
-        ensureColumn("octopus_key_person", "system_user_id", "BIGINT DEFAULT NULL COMMENT '匹配到的系统用户ID(如有)'");
-        log.info("迁移342: octopus_key_person.system_user_id 列已添加");
-
-        try {
-            Integer reportCount = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM admin_task_templates WHERE title = 'REPORT_UPLOAD' AND onboarding_sequence IS NOT NULL", Integer.class);
-            if (reportCount == null || reportCount == 0) {
-                jdbcTemplate.execute("INSERT INTO admin_task_templates (title, description, points, category, need_review, is_active, task_type, frequency, onboarding_sequence, created_at, updated_at) VALUES " +
-                        "('REPORT_UPLOAD', '完成首次报告上传', 300, '成长', 0, 1, 'onetime', 'none', 8, NOW(), NOW())");
-                log.info("迁移343: 已插入完成首次报告上传新人引导任务模板");
-            }
-        } catch (Exception e) {
-            log.warn("迁移343: 插入完成首次报告上传任务模板失败或已存在: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 迁移318: 系统配置·基础管理 挂载 系统提示词 菜单(幂等)
-     * 仅当 sys_menu 表已有数据(即角色授权已存在)时补授权,避免破坏兼容逻辑
-     */
-    private void migrateSystemPromptMenu() {
-        try {
-            Long baseManageId = queryMenuId("SELECT id FROM sys_menu WHERE title='基础管理'");
-            if (baseManageId == null) {
-                log.warn("迁移318: 未找到基础管理分组,跳过");
-                return;
-            }
-            Long promptId = insertSystemPromptMenu(baseManageId);
-            if (promptId != null) {
-                Integer grantCount = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM sys_role_menu", Integer.class);
-                if (grantCount != null && grantCount > 0) {
-                    grantMenuToRole("admin", promptId);
-                    log.info("迁移318: 已授权 admin 角色");
-                }
-                log.info("迁移318: 系统提示词菜单挂载完成 id={}", promptId);
-            }
-        } catch (Exception e) {
-            log.warn("迁移318失败: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 按 path 幂等插入系统提示词叶子菜单,返回菜单 id(已存在返回原 id)
-     */
-    private Long insertSystemPromptMenu(Long parentId) {
-        Long existed = queryMenuId("SELECT id FROM sys_menu WHERE path='/system-prompt'");
-        if (existed != null) {
-            return existed;
-        }
-        try {
-            jdbcTemplate.update(
-                    "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible) VALUES (?, NULL, '系统提示词', '/system-prompt', 'el-icon-chat-line-square', 'system:base', 8, 1)",
-                    parentId);
-            Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-            log.info("迁移318: 已挂载系统提示词菜单");
-            return id;
-        } catch (Exception e) {
-            log.warn("迁移318: 挂载菜单失败: {}", e.getMessage());
-            return null;
-        }
-    }
-
-    private void seedGutFloraFingerprints() {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM report_fingerprint WHERE type_id = ?", Integer.class, "gut_flora");
-            if (count != null && count > 0) {
-                log.info("迁移312: gut_flora 指纹规则已存在,跳过");
-                return;
-            }
-            String[][] rows = {
-                    {"肠道菌群检测", "20", "0", "1"},
-                    {"核心菌属", "15", "0", "2"},
-                    {"高通量测序", "15", "0", "3"},
-                    {"菌群健康", "10", "0", "4"},
-                    {"益生菌", "8", "0", "5"},
-                    {"Shannon", "8", "0", "6"},
-                    {"肠道菌群", "10", "0", "7"},
-            };
-            for (String[] row : rows) {
-                jdbcTemplate.update(
-                        "INSERT INTO report_fingerprint (type_id, pattern, weight, is_exclusion, sort_order, created_at) "
-                                + "VALUES ('gut_flora', ?, ?, ?, ?, NOW())",
-                        row[0], Integer.valueOf(row[1]), Integer.valueOf(row[2]), Integer.valueOf(row[3]));
-            }
-            log.info("迁移312: 已写入 gut_flora 默认指纹规则 {} 条", rows.length);
-        } catch (Exception e) {
-            log.warn("迁移312: 写入 gut_flora 指纹规则失败: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 迁移323: 为 dan_a2(素质测评A2)补默认指纹规则。
-     * 空表会导致指纹引擎永远 unknown;A2 报告特征词取自 DanReportParseService.parseA2Report 的章节识别词。
-     * dan_a2 注册表 min_confidence=30,两高权重词同时命中即判定成功,避免单词误判。
-     */
-    private void seedDanA2Fingerprints() {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM report_fingerprint WHERE type_id = ?", Integer.class, "dan_a2");
-            if (count != null && count > 0) {
-                log.info("迁移323: dan_a2 指纹规则已存在,跳过");
-                return;
-            }
-            String[][] rows = {
-                    {"大五人格", "20", "0", "1"},
-                    {"人格特质", "15", "0", "2"},
-                    {"核心素养", "15", "0", "3"},
-                    {"认知能力", "10", "0", "4"},
-                    {"感知觉", "10", "0", "5"},
-                    {"评估报告", "8", "0", "6"},
-                    {"综合评估", "8", "0", "7"},
-            };
-            for (String[] row : rows) {
-                jdbcTemplate.update(
-                        "INSERT INTO report_fingerprint (type_id, pattern, weight, is_exclusion, sort_order, created_at) "
-                                + "VALUES ('dan_a2', ?, ?, ?, ?, NOW())",
-                        row[0], Integer.valueOf(row[1]), Integer.valueOf(row[2]), Integer.valueOf(row[3]));
-            }
-            log.info("迁移323: 已写入 dan_a2 默认指纹规则 {} 条", rows.length);
-        } catch (Exception e) {
-            log.warn("迁移323: 写入 dan_a2 指纹规则失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移326: 商城营销菜单新增「限时折扣管理」(幂等)
-    private void seedDiscountRulesMenu() {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM sys_menu WHERE path = '/discount-rules'", Integer.class);
-            if (count != null && count > 0) {
-                log.info("迁移326: 限时折扣管理菜单已存在,跳过");
-                return;
-            }
-            jdbcTemplate.update(
-                    "INSERT INTO sys_menu (parent_id, title, label, path, icon, perm, sort, visible, created_at) "
-                            + "VALUES (15, NULL, '限时折扣管理', '/discount-rules', 'el-icon-timer', 'commerce:discount', 7, 1, NOW())");
-            log.info("迁移326: 已添加限时折扣管理菜单");
-        } catch (Exception e) {
-            log.warn("迁移326: 添加限时折扣管理菜单失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移327: 创建 user_shortcut_config 表(首页快捷方式自定义配置,每应用一条记录,locked=置顶)
-    private void createUserShortcutConfigTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_shortcut_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "app_key VARCHAR(64) NOT NULL COMMENT '应用key', " +
-                    "locked TINYINT DEFAULT 0 COMMENT '是否锁定置顶(1=锁定,0=普通)', " +
-                    "sort_order INT DEFAULT 0 COMMENT '手动排序序号', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_user_app (user_id, app_key)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页快捷方式自定义配置'");
-            log.info("迁移327: 已创建 user_shortcut_config 表");
-        } catch (Exception e) {
-            log.warn("迁移327: 创建 user_shortcut_config 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移327: 创建 user_app_usage 表(应用使用频度记录)
-    private void createUserAppUsageTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS user_app_usage (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID', " +
-                    "app_key VARCHAR(64) NOT NULL COMMENT '应用key', " +
-                    "enter_count INT DEFAULT 0 COMMENT '累计进入次数', " +
-                    "last_enter_at DATETIME COMMENT '最近进入时间', " +
-                    "UNIQUE KEY uk_user_app (user_id, app_key)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用使用频度记录'");
-            log.info("迁移327: 已创建 user_app_usage 表");
-        } catch (Exception e) {
-            log.warn("迁移327: 创建 user_app_usage 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移333: 预置引导弹窗种子数据(parent_first_login,首次登录家长端)
-    private void seedGuidePopupData() {
-        try {
-            Long count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM guide_popup WHERE slug = 'parent_first_login'", Long.class);
-            if (count != null && count > 0L) {
-                log.info("迁移333: parent_first_login 种子弹窗已存在,跳过");
-                return;
-            }
-            jdbcTemplate.update(
-                    "INSERT INTO guide_popup (slug, title, description, icon, icon_type, theme_color, btn_text, btn_action, status, sort_order, created_at, updated_at) "
-                            + "VALUES ('parent_first_login', '欢迎使用浠艾福', '身·智·富·行·心,全家健康一站式管理', '🌏', 0, '#F97316', '开始体验', '', 1, 0, NOW(), NOW())");
-            Long popupId = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class);
-            // 步骤
-            jdbcTemplate.update("INSERT INTO guide_popup_step (popup_id, step_order, title, desc, icon, icon_type, is_intro, btn_text, btn_action) VALUES (?, 0, '你真的了解家人的状态吗?', '情绪低落没察觉、习惯变化没注意、能力短板没发现——什么问题等爆发了才看见。浠艾福帮你在问题发生前,看清每位家人的真实状态。', '🔍', 0, 1, '下一步', '')", popupId);
-            jdbcTemplate.update("INSERT INTO guide_popup_step (popup_id, step_order, title, desc, icon, icon_type, is_intro, btn_text, btn_action) VALUES (?, 1, '五维能量,看见全家', '身·心·智·行·富,一张全景图看清每位家人。谁的身体需要关注、谁的情绪需要疏导、谁的状态正在下滑——不用猜,看得见。', '🌏', 0, 0, '下一步', '')", popupId);
-            jdbcTemplate.update("INSERT INTO guide_popup_step (popup_id, step_order, title, desc, icon, icon_type, is_intro, btn_text, btn_action) VALUES (?, 2, '小行动,大改变', '全家一起完成每日小任务,各自攒星星。每天一点点积累,好习惯自然养成。', '📋', 0, 0, '下一步', '')", popupId);
-            jdbcTemplate.update("INSERT INTO guide_popup_step (popup_id, step_order, title, desc, icon, icon_type, is_intro, btn_text, btn_action) VALUES (?, 3, '心愿墙,看得见努力', '每位家人用自己的星星兑换心愿。努力有回报,全家人都能看到彼此的坚持。', '🎁', 0, 0, '开始体验', '')", popupId);
-            // 触发条件:首次登录,parent 角色
-            jdbcTemplate.update("INSERT INTO guide_popup_trigger (popup_id, trigger_type, target_page, target_action, min_role, extra_config, created_at) VALUES (?, 'first_login', '', '', 'parent', NULL, NOW())", popupId);
-            log.info("迁移333: 已预置 parent_first_login 种子弹窗 (popup_id={})", popupId);
-        } catch (Exception e) {
-            log.warn("预置引导弹窗种子数据失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移337: product_orders 表添加 gift_amount 列(送会员商品原价金额,分)
-    private void addGiftAmountColumn() {
-        ensureColumn("product_orders", "gift_amount", "INT DEFAULT 0 COMMENT '送会员商品原价金额(分)'");
-    }
-
-    // 迁移338: 创建 gift_membership_progress 表(家庭维度送会员累计进度)
-    private void createGiftMembershipProgressTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS gift_membership_progress (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID', " +
-                    "accumulated_amount INT DEFAULT 0 COMMENT '累计送会员商品原价金额(分)', " +
-                    "granted INT DEFAULT 0 COMMENT '是否已赠送 1=已赠送 0=未赠送', " +
-                    "granted_level VARCHAR(50) COMMENT '已赠送会员等级', " +
-                    "granted_order_no VARCHAR(64) COMMENT '触发赠送的订单号', " +
-                    "granted_at DATETIME COMMENT '赠送时间', " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='送会员累计进度'");
-            log.info("迁移338: 已创建 gift_membership_progress 表");
-        } catch (Exception e) {
-            log.warn("迁移338: 创建 gift_membership_progress 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移339: tasks 表加 is_flow_task / successor_task_ids 列(TASK-SYS-248 流程任务前置/后置逻辑)
-    private void addFlowTaskColumnsToTasksTable() {
-        ensureColumn("tasks", "is_flow_task", "TINYINT DEFAULT 0 COMMENT '是否为流程任务:1=是(有前置/后置任务),0=否'");
-        ensureColumn("tasks", "successor_task_ids", "TEXT NULL COMMENT '后置任务IDs JSON: [1,2,3],任意一个完成则解锁(OR 逻辑)'");
-    }
-
-    // 迁移339: insurance_policies 表加 policy_terms 列(保单原始条款,AI 解析后原样保存)
-    private void addPolicyTermsColumn() {
-        ensureColumn("insurance_policies", "policy_terms", "TEXT COMMENT '保单原始条款(AI 解析后原样保存)'");
-    }
-
-    // 迁移340: 创建 home_banners 表(首页广告栏配置)
-    private void createHomeBannersTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS home_banners (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "title VARCHAR(100) NOT NULL COMMENT '展示标题'," +
-                    "banner_type VARCHAR(20) NOT NULL COMMENT '类型: activity/product/link'," +
-                    "ref_id BIGINT DEFAULT NULL COMMENT '关联活动/商品ID(banner_type=activity/product时有效)'," +
-                    "cover_image VARCHAR(500) DEFAULT NULL COMMENT '封面图URL(可覆盖默认封面)'," +
-                    "link_url VARCHAR(500) DEFAULT NULL COMMENT '跳转链接(banner_type=link时有效)'," +
-                    "sort_order INT NOT NULL DEFAULT 0 COMMENT '排序,值越小越靠前'," +
-                    "enabled TINYINT NOT NULL DEFAULT 1 COMMENT '启用状态:1=启用 0=禁用'," +
-                    "start_time DATETIME DEFAULT NULL COMMENT '投放开始时间(NULL=不限)'," +
-                    "end_time DATETIME DEFAULT NULL COMMENT '投放结束时间(NULL=不限)'," +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页广告栏配置表'");
-            log.info("迁移340: 已创建 home_banners 表");
-        } catch (Exception e) {
-            log.warn("迁移340: 创建 home_banners 表失败: {}", e.getMessage());
-        }
-    }
-
-    /** 迁移343: health_report_drafts 补 member_id 列(commit 21f8f6740 遗漏,schema.sql 已含但无迁移脚本) */
-    /** 迁移345: health_plans 补 total_days 列(方案周期天数,驱动服务任务周期边界与截止日期) */
-    private void ensureHealthPlansTotalDaysColumn() {
-        ensureColumn("health_plans", "total_days",
-                "INT DEFAULT NULL COMMENT '方案周期天数,驱动服务任务周期边界与截止日期'");
-        log.info("迁移345: health_plans.total_days 已确保存在");
-    }
-
-    /** 迁移346: 未打卡任务提醒通知模板(原有种子仅在空表时插入,此处单独幂等补种) */
-    /** 迁移346: 未打卡任务提醒通知模板(原有种子仅在空表时插入,此处单独幂等补种) */
-    private void seedTaskReminderTemplate() {
-        try {
-            Integer cnt = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM notification_templates WHERE type = ?",
-                    Integer.class, "task_reminder");
-            if (cnt != null && cnt == 0) {
-                jdbcTemplate.update("INSERT INTO notification_templates (type, title, content, channels) VALUES (?,?,?,?)",
-                        "task_reminder",
-                        "任务待完成提醒",
-                        "任务「{title}」{status},完成后记得打卡,可获得积分与 CF 值奖励。",
-                        "in_app,sms");
-                log.info("迁移346: task_reminder 通知模板已插入");
-            }
-        } catch (Exception e) {
-            log.warn("迁移346: 插入 task_reminder 通知模板失败: " + e.getMessage());
-        }
-        try {
-            Integer c2 = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM notification_templates WHERE type = ?",
-                    Integer.class, "task_completion_praise");
-            if (c2 != null && c2 == 0) {
-                jdbcTemplate.update("INSERT INTO notification_templates (type, title, content, channels) VALUES (?,?,?,?)",
-                        "task_completion_praise",
-                        "任务完成,太棒了!",
-                        "太棒了!任务「{title}」已完成,继续保持,加油~",
-                        "in_app,wechat");
-                log.info("迁移346+: task_completion_praise 通知模板已插入");
-            }
-        } catch (Exception e) {
-            log.warn("迁移346+: 插入 task_completion_praise 通知模板失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 迁移347: 回填健康方案任务的依赖链。
-     * 历史上使用任务只写了 parent_task_id,从未写 prerequisite_task_id,导致"采购完成才激活服务任务"的闸门失效。
-     * 这里补写依赖并把前置未完成的使用任务置为 locked。
-     * 幂等:每次启动只处理 prerequisite IS NULL / status=pending 的行,可重复执行。
-     */
-    /**
-     * 迁移348: 回填周期实例的 family_member_id。
-     * RepeatTaskGenerator 过去未透传该字段,导致周期实例在"今日任务"列表查不到、
-     * 且 completeTask 抛 NPE。存量实例按其模板回填,模板缺失时按 child_id 兜底。
-     */
-    private void backfillTemplateInstanceFamilyMemberId() {
-        try {
-            int fromTpl = jdbcTemplate.update(
-                    "UPDATE tasks i JOIN tasks tpl ON tpl.id = i.template_id " +
-                    "SET i.family_member_id = tpl.family_member_id " +
-                    "WHERE i.family_member_id IS NULL AND tpl.family_member_id IS NOT NULL");
-            int fromChild = jdbcTemplate.update(
-                    "UPDATE tasks SET family_member_id = child_id " +
-                    "WHERE family_member_id IS NULL AND child_id IS NOT NULL AND is_template = 0");
-            if (fromTpl > 0 || fromChild > 0) {
-                log.info("迁移348: 周期实例 family_member_id 回填 模板来源={}条 child_id兜底={}条",
-                        fromTpl, fromChild);
-            }
-        } catch (Exception e) {
-            log.warn("迁移348: 周期实例 family_member_id 回填失败: " + e.getMessage());
-        }
-    }
-
-    private void backfillHealthPlanTaskPrerequisite() {
-        try {
-            int linked = jdbcTemplate.update(
-                    "UPDATE tasks SET prerequisite_task_id = parent_task_id " +
-                    "WHERE source_type = 'health_plan' AND category = '使用任务' " +
-                    "AND parent_task_id IS NOT NULL AND prerequisite_task_id IS NULL");
-            // 注意:单表 UPDATE 的 WHERE 子查询不能引用目标表本身(MySQL 1093),必须用 LEFT JOIN 自连接
-            int locked = jdbcTemplate.update(
-                    "UPDATE tasks t LEFT JOIN tasks p " +
-                    "ON p.id = t.prerequisite_task_id AND p.status = 'completed' " +
-                    "SET t.status = 'locked' " +
-                    "WHERE t.source_type = 'health_plan' AND t.category = '使用任务' " +
-                    "AND t.prerequisite_task_id IS NOT NULL AND t.status = 'pending' AND p.id IS NULL");
-            if (linked > 0 || locked > 0) {
-                log.info("迁移347: 健康方案任务依赖回填 prerequisite={}条, 置locked={}条", linked, locked);
-            }
-        } catch (Exception e) {
-            log.warn("迁移347: 健康方案任务依赖回填失败: " + e.getMessage());
-        }
-    }
-
-    private void ensureHealthReportDraftsMemberIdColumn() {
-        ensureColumn("health_report_drafts", "member_id",
-                "BIGINT DEFAULT NULL COMMENT '报告归属成员ID(family_members.id),A2/DAN自动采集必需'");
-        log.info("迁移343: health_report_drafts.member_id 已确保存在");
-    }
-
-    // 迁移344: 创建 supply_customer_relation 表(供应商团队客户归属记录)
-    private void createSupplyCustomerRelationTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS supply_customer_relation (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "system_id BIGINT NOT NULL COMMENT '供应商体系ID(supply_system.id)'," +
-                    "parent_user_id BIGINT NOT NULL COMMENT '上级供应商用户ID(supply_hierarchy.parent_id)'," +
-                    "family_id BIGINT NOT NULL COMMENT '客户家庭ID(family_members.family_id)'," +
-                    "child_user_id BIGINT DEFAULT NULL COMMENT '下单用户ID(users.id),可为空'," +
-                    "relation_type VARCHAR(32) NOT NULL DEFAULT 'family' COMMENT '归属类型: family=家庭归属 order=下单自动 referral=推荐码'," +
-                    "source VARCHAR(32) NOT NULL DEFAULT 'manual' COMMENT '来源: manual=人工绑定 order=下单自动 referral=推荐码'," +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "INDEX idx_system_family (system_id, family_id)," +
-                    "INDEX idx_parent_user (parent_user_id)," +
-                    "INDEX idx_family_id (family_id)," +
-                    "UNIQUE KEY uk_system_family (system_id, family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商团队客户归属关系表'");
-            log.info("迁移344: 已创建 supply_customer_relation 表");
-        } catch (Exception e) {
-            log.warn("迁移344: 创建 supply_customer_relation 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移345: 创建 product_dimension_mapping 表(商品-维度关联)
-    private void createProductDimensionMappingTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_dimension_mapping (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID(products.id)'," +
-                    "dimension_code VARCHAR(32) NOT NULL COMMENT '维度编码: body/wisdom/mind/action/wealth'," +
-                    "match_score INT DEFAULT 100 COMMENT '匹配度 0-100'," +
-                    "match_reason VARCHAR(200) COMMENT '匹配原因说明'," +
-                    "tags VARCHAR(500) COMMENT '推荐标签JSON'," +
-                    "enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
-                    "INDEX idx_product_id (product_id)," +
-                    "INDEX idx_dimension (dimension_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品维度关联表'");
-            log.info("迁移345: 已创建 product_dimension_mapping 表");
-        } catch (Exception e) {
-            log.warn("迁移345: 创建 product_dimension_mapping 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移346: 创建 product_recommendation_log 表(推荐曝光日志)
-    private void createProductRecommendationLogTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS product_recommendation_log (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "user_id BIGINT DEFAULT NULL COMMENT '用户ID(users.id)'," +
-                    "family_id BIGINT DEFAULT NULL COMMENT '家庭ID(family_members.family_id)'," +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID'," +
-                    "scene VARCHAR(32) NOT NULL COMMENT '场景: dimension_page/ai_chat/report_upload/repurchase'," +
-                    "reason VARCHAR(200) COMMENT '推荐理由'," +
-                    "match_score INT DEFAULT NULL COMMENT '匹配分'," +
-                    "was_clicked TINYINT DEFAULT 0 COMMENT '是否点击 1=是 0=否'," +
-                    "was_purchased TINYINT DEFAULT 0 COMMENT '是否购买 1=是 0=否'," +
-                    "clicked_at DATETIME DEFAULT NULL COMMENT '点击时间'," +
-                    "purchased_at DATETIME DEFAULT NULL COMMENT '购买时间'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "INDEX idx_user_scene (user_id, scene)," +
-                    "INDEX idx_product_purchased (product_id, was_purchased)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐曝光日志表'");
-            log.info("迁移346: 已创建 product_recommendation_log 表");
-        } catch (Exception e) {
-            log.warn("迁移346: 创建 product_recommendation_log 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移347: 创建 repurchase_reminder_record 和 repurchase_reminder_config 表
-    private void createRepurchaseReminderTables() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS repurchase_reminder_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID(users.id)'," +
-                    "product_id BIGINT NOT NULL COMMENT '商品ID'," +
-                    "order_id BIGINT DEFAULT NULL COMMENT '关联订单ID'," +
-                    "reminder_days INT DEFAULT 30 COMMENT '提醒天数'," +
-                    "sent_at DATETIME DEFAULT NULL COMMENT '发送时间'," +
-                    "clicked TINYINT DEFAULT 0 COMMENT '是否点击 1=是 0=否'," +
-                    "purchased TINYINT DEFAULT 0 COMMENT '是否购买 1=是 0=否'," +
-                    "INDEX idx_user_pending (user_id, purchased)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='复购提醒记录表'");
-            log.info("迁移347a: 已创建 repurchase_reminder_record 表");
-        } catch (Exception e) {
-            log.warn("迁移347a: 创建 repurchase_reminder_record 表失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS repurchase_reminder_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "product_category VARCHAR(100) DEFAULT NULL COMMENT '商品类目'," +
-                    "product_id BIGINT DEFAULT NULL COMMENT '特定商品ID(优先于category)'," +
-                    "reminder_days INT DEFAULT 30 COMMENT '提醒天数'," +
-                    "reminder_template VARCHAR(500) DEFAULT NULL COMMENT '提醒话术模板'," +
-                    "max_reminders INT DEFAULT 3 COMMENT '最大提醒次数'," +
-                    "enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='复购提醒配置表'");
-            log.info("迁移347b: 已创建 repurchase_reminder_config 表");
-        } catch (Exception e) {
-            log.warn("迁移347b: 创建 repurchase_reminder_config 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移348: 创建 recommendation_product_associations 表(商品推荐关联关系)
-    private void createRecommendationProductAssociationsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS recommendation_product_associations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "source_product_id BIGINT NOT NULL COMMENT '源商品ID(已购/关注商品)'," +
-                    "target_product_id BIGINT NOT NULL COMMENT '目标商品ID(被推荐商品)'," +
-                    "association_type VARCHAR(32) NOT NULL COMMENT '类型: co_purchase/repurchase/profile_gap/manual'," +
-                    "strength DECIMAL(5,2) DEFAULT 0.50 COMMENT '关联强度 0.00-1.00'," +
-                    "manual_override TINYINT DEFAULT 0 COMMENT '是否运营手动覆盖 1=是 0=否'," +
-                    "reason VARCHAR(500) DEFAULT NULL COMMENT '关联原因说明'," +
-                    "dimension_code VARCHAR(32) DEFAULT NULL COMMENT '关联维度(body/mind/wisdom/action/wealth)'," +
-                    "repurchase_days INT DEFAULT NULL COMMENT '复购周期天数(repurchase场景)'," +
-                    "co_purchase_window_days INT DEFAULT 30 COMMENT '共购时间窗口天数(co_purchase场景)'," +
-                    "co_purchase_count INT DEFAULT 0 COMMENT '共购次数(co_purchase场景自动累计)'," +
-                    "enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用'," +
-                    "created_by BIGINT DEFAULT NULL COMMENT '创建人用户ID(manual场景记录运营)'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
-                    "INDEX idx_source_target (source_product_id, target_product_id)," +
-                    "INDEX idx_type_enabled (association_type, enabled)," +
-                    "INDEX idx_dimension (dimension_code)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐关联关系表'");
-            log.info("迁移348: 已创建 recommendation_product_associations 表");
-        } catch (Exception e) {
-            log.warn("迁移348: 创建 recommendation_product_associations 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移349: product_recommendation_log 表添加 AB测试分组与推荐来源类型列
-    private void addAbTestColumnsToRecommendationLog() {
-        ensureColumn("product_recommendation_log", "ab_test_group",
-                "VARCHAR(32) DEFAULT NULL COMMENT 'AB测试分组(A/B/C/控制组)'");
-        ensureColumn("product_recommendation_log", "recommendation_type",
-                "VARCHAR(32) DEFAULT NULL COMMENT '推荐来源类型:dimension/co_purchase/repurchase/profile_gap/manual'");
-        log.info("迁移349: product_recommendation_log 已添加 ab_test_group / recommendation_type 列");
-    }
-    // 迁移349: 创建 report_transfer_requests 表(健康报告跨家庭转移申请)
-    // 同一份报告(file_hash 相同)被其他家庭上传时,申请方家庭发起转移申请,
-    // 原归属家庭同意后 health_reports.family_id 转移至申请方,原家庭不再可见。
-    private void createReportTransferRequestsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS report_transfer_requests (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "report_id BIGINT NOT NULL COMMENT '报告ID(health_reports.id)'," +
-                    "from_family_id BIGINT NOT NULL COMMENT '原归属家庭ID(需同意方)'," +
-                    "to_family_id BIGINT NOT NULL COMMENT '申请转入家庭ID(申请方)'," +
-                    "requester_user_id BIGINT NOT NULL COMMENT '申请人用户ID(users.id)'," +
-                    "status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending=待同意 approved=已同意 denied=已拒绝'," +
-                    "handled_by BIGINT DEFAULT NULL COMMENT '处理人用户ID'," +
-                    "handled_at DATETIME DEFAULT NULL COMMENT '处理时间'," +
-                    "remark VARCHAR(200) DEFAULT NULL COMMENT '备注(拒绝原因)'," +
-                    "created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
-                    "INDEX idx_report_id (report_id)," +
-                    "INDEX idx_from_family_status (from_family_id, status)," +
-                    "INDEX idx_to_family_status (to_family_id, status)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告跨家庭转移申请'");
-            log.info("迁移349: 已创建 report_transfer_requests 表");
-        } catch (Exception e) {
-            log.warn("迁移349: 创建 report_transfer_requests 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移350: products 表添加 min_discount_level 列(商品粒度控制会员价门槛,NULL=所有会员均可享会员价)
-    private void addProductMinDiscountLevel() {
-        try {
-            jdbcTemplate.execute("ALTER TABLE products ADD COLUMN min_discount_level VARCHAR(50) DEFAULT NULL " +
-                    "COMMENT '享受会员价所需的最低会员级别编码(FREE/FAMILY/PREMIUM/LIFETIME,NULL=所有会员均可)' AFTER min_visible_level");
-            log.info("迁移350: 已添加 products.min_discount_level 列");
-        } catch (Exception e) {
-            // 列已存在,忽略
-            log.debug("迁移350: products.min_discount_level 列已存在,跳过");
-        }
-    }
-
-    // 迁移351: membership_levels.level_order 顺延,为 BASIC 让出独立档位
-    // 会员级别包含关系(数字越小级别越低、可见范围越大): FREE=1 BASIC=2 FAMILY=3 PROVIDER=4 PREMIUM=5 LIFETIME=6
-    private void backfillMembershipLevelOrder() {
-        try {
-            int updated = jdbcTemplate.update("UPDATE membership_levels SET level_order = CASE level_code " +
-                    "WHEN 'FREE' THEN 1 WHEN 'BASIC' THEN 2 WHEN 'FAMILY' THEN 3 WHEN 'PROVIDER' THEN 4 " +
-                    "WHEN 'PREMIUM' THEN 5 WHEN 'LIFETIME' THEN 6 ELSE level_order END");
-            log.info("迁移351: 已回填 membership_levels.level_order({} 行):FREE=1 BASIC=2 FAMILY=3 PROVIDER=4 PREMIUM=5 LIFETIME=6", updated);
-        } catch (Exception e) {
-            log.warn("迁移351: 回填 membership_levels.level_order 失败: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 迁移360: 恢复 9.9 元/月 BASIC 体验会员等级与权益(幂等)。
-     * 反向还原提交 f86dd164b 删除的内容;level_order 由 backfillMembershipLevelOrder 统一回填。
-     */
-    private void restoreBasicMembershipLevel() {
-        try {
-            jdbcTemplate.execute(
-                    "INSERT IGNORE INTO membership_levels " +
-                            "(level_code, level_name, level_desc, price_monthly, features, max_children, max_tasks_per_day) " +
-                            "VALUES ('BASIC', '体验会员', " +
-                            "'9.9元/月体验版,解锁核心功能,限次使用AI与报告解读', " +
-                            "990, " +
-                            "'[\"free_activities\",\"free_courses\",\"discount_purchase\",\"invite_family\",\"mascot_ai_lite\",\"ai_report_reading_lite\",\"assessment_quota_lite\",\"health_report_upload_lite\",\"growth_plan_lite\",\"task_template_lite\",\"referral_commission\"]', " +
-                            "3, 3)");
-            log.info("迁移360: 已恢复 BASIC 体验会员等级");
-        } catch (Exception e) {
-            log.warn("迁移360: 恢复 BASIC 会员等级失败: {}", e.getMessage());
-        }
-        // 兼容历史数据:早期 BASIC features 缺少 referral_commission,补齐
-        try {
-            jdbcTemplate.update("UPDATE membership_levels SET features = ? WHERE level_code = 'BASIC' AND features NOT LIKE '%referral_commission%'",
-                    "[\"free_activities\",\"free_courses\",\"discount_purchase\",\"invite_family\",\"mascot_ai_lite\",\"ai_report_reading_lite\",\"assessment_quota_lite\",\"health_report_upload_lite\",\"growth_plan_lite\",\"task_template_lite\",\"referral_commission\"]");
-        } catch (Exception e) {
-            log.warn("迁移360: 补齐 BASIC features 失败: {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute(
-                    "INSERT IGNORE INTO membership_benefits " +
-                            "(level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES " +
-                            "('BASIC', 'AI_CHAT_LITE', 'AI健康顾问(限3次/月)', '每月3次AI健康顾问问答', '🤖', '#DBEAFE', 1), " +
-                            "('BASIC', 'REPORT_READING_LITE', '报告解读(限1次/月)', '每月1次体检/测评报告AI解读', '📊', '#FCE7F3', 4), " +
-                            "('BASIC', 'GROWTH_PLAN_LITE', '基础成长计划', '创建成长计划但模板有限', '📋', '#FEF3C7', 3), " +
-                            "('BASIC', 'ASSESSMENT_QUOTA_LITE', '测评预约(限1次)', '每月可预约1次测试', '📅', '#E0E7FF', 8)");
-            log.info("迁移360: 已恢复 BASIC 会员权益");
-        } catch (Exception e) {
-            log.warn("迁移360: 恢复 BASIC 会员权益失败: {}", e.getMessage());
-        }
-    }
-
-    private void removeReportUploadQuota() {
-        try {
-            int deletedBenefits = jdbcTemplate.update(
-                    "DELETE FROM membership_benefits WHERE level_code = 'BASIC' AND benefit_code = 'REPORT_UPLOAD_LITE'");
-            log.info("迁移352: 已清理遗留权益记录({} 行)", deletedBenefits);
-        } catch (Exception e) {
-            log.warn("迁移352: 移除 REPORT_UPLOAD_LITE 权益失败: {}", e.getMessage());
-        }
-        try {
-            int deletedUsage = jdbcTemplate.update(
-                    "DELETE FROM basic_quota_usage WHERE quota_type = 'REPORT_UPLOAD'");
-            log.info("迁移352: 已清理 REPORT_UPLOAD 配额记录({} 行)", deletedUsage);
-        } catch (Exception e) {
-            log.warn("迁移352: 清理 REPORT_UPLOAD 配额记录失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移353: 任务提醒配置表(用户级,一行/用户;提醒渠道/时机/偏移分钟可配置)
-    private void createTaskReminderConfigTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS task_reminder_config (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "user_id BIGINT NOT NULL COMMENT '用户ID(users.id),家长账号'," +
-                    "channels VARCHAR(100) DEFAULT 'wechat' COMMENT '提醒渠道(逗号分隔): in_app/wechat/sms/phone/email'," +
-                    "timing_mode VARCHAR(20) DEFAULT 'after_timeout' COMMENT '提醒时机: before_deadline=截止前提醒 after_timeout=超时后提醒'," +
-                    "offset_minutes INT DEFAULT 60 COMMENT '偏移分钟: before_deadline=截止前N分钟; after_timeout=超时后N分钟'," +
-                    "enabled TINYINT DEFAULT 1 COMMENT '是否启用 1=启用 0=停用'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
-                    "UNIQUE KEY uk_user (user_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务提醒配置表'");
-            log.info("迁移353: 已创建 task_reminder_config 表");
-            try { ensureColumn("task_reminder_config", "completion_praise_enabled", "TINYINT DEFAULT 0 COMMENT '任务正常完成时是否发送表扬鼓励消息 1=启用 0=停用'"); ensureColumn("task_reminder_config", "completion_praise_channels", "VARCHAR(100) DEFAULT 'wechat,in_app' COMMENT '完成表扬渠道(逗号分隔)'"); } catch (Exception ex) { log.warn("迁移353补充列失败: {}", ex.getMessage()); }
-        } catch (Exception e) {
-            log.warn("迁移353: 创建 task_reminder_config 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移359: 跨小程序单点登录一次性票据表(cfc ↔ train 双向免登)
-    // 详见 schema.sql。此处自愈建表,避免 schema.sql 建表语句因故静默失败导致登录报错。
-    private void createSsoTicketTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS sso_ticket (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "ticket VARCHAR(64) NOT NULL COMMENT '一次性票据(SecureRandom 生成)'," +
-                    "source_system VARCHAR(16) NOT NULL COMMENT '签发方系统: cfc / train'," +
-                    "target_system VARCHAR(16) NOT NULL COMMENT '目标系统: cfc / train'," +
-                    "source_user_id BIGINT NOT NULL COMMENT '签发方用户ID(cfc=users.id / train=train_user.id)'," +
-                    "cfc_user_id BIGINT NOT NULL COMMENT 'cfc 统一会员ID(users.id),跨系统换票依据'," +
-                    "used TINYINT NOT NULL DEFAULT 0 COMMENT '是否已使用: 0=未用 1=已用'," +
-                    "expire_at DATETIME NOT NULL COMMENT '过期时间'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "UNIQUE KEY uk_ticket (ticket)," +
-                    "INDEX idx_expire (expire_at)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跨小程序单点登录一次性票据'");
-            log.info("迁移359: 已创建 sso_ticket 表");
-        } catch (Exception e) {
-            log.warn("迁移359: 创建 sso_ticket 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移355: product_recommendation_log 补齐缺失列
-    // 旧库该表由更早版本的建表语句创建(CREATE TABLE IF NOT EXISTS 不会补列),
-    // 缺 family_id/was_clicked/was_purchased/clicked_at/purchased_at/updated_at,
-    // 导致 stats/ab-summary、stats/by-type 查询报 Unknown column 返回 500
-    private void addMissingColumnsToRecommendationLog() {
-        ensureColumn("product_recommendation_log", "family_id",
-                "BIGINT DEFAULT NULL COMMENT '家庭ID(family_members.family_id)'");
-        ensureColumn("product_recommendation_log", "was_clicked",
-                "TINYINT DEFAULT 0 COMMENT '是否点击 1=是 0=否'");
-        ensureColumn("product_recommendation_log", "was_purchased",
-                "TINYINT DEFAULT 0 COMMENT '是否购买 1=是 0=否'");
-        ensureColumn("product_recommendation_log", "clicked_at",
-                "DATETIME DEFAULT NULL COMMENT '点击时间'");
-        ensureColumn("product_recommendation_log", "purchased_at",
-                "DATETIME DEFAULT NULL COMMENT '购买时间'");
-        ensureColumn("product_recommendation_log", "updated_at",
-                "DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'");
-        log.info("迁移355: product_recommendation_log 已补齐缺失列");
-    }
-
-    // 迁移354: 报告采集指标项定义(report_type_registry.expected_indicators)+ 草稿采集校验结果列(health_report_drafts.collect_validation)
-    // 每个报告类型定义「应采集指标项」清单(JSON 数组),ReportCollectService 采集完成后按此校验完整性,结果写入草稿 collect_validation。
-    // DAN 指标项按 测评数据_优化提取.csv 各报告类型列(填充率>=30%)总结;菌群指标项按 docs/参考资料 已解析报告的指标/区块总结。
-    private void registerCollectExpectedIndicators() {
-        ensureColumn("report_type_registry", "expected_indicators",
-                "TEXT NULL COMMENT '该报告类型应采集的指标项定义(JSON数组),用于数据采集完整性校验'");
-        ensureColumn("health_report_drafts", "collect_validation",
-                "TEXT NULL COMMENT '采集指标校验结果(JSON: typeId/expected/matched/pass/missing)'");
-
-        // 确保注册表存在各 DAN 类型 + 北京菌群类型的行(parser_path 空 = 保持走 LangGraph 检测,不影响既有路由)
-        ensureReportTypeRow("dan_a1", "dan", "素质测评A1", "核心认知发展评估报告:感知觉/注意力/记忆力/推理能力/空间能力/加工速度");
-        ensureReportTypeRow("dan_b2", "dan", "素质测评B2", "儿童行为评估报告:自我概念/行为问题");
-        ensureReportTypeRow("dan_b3", "dan", "素质测评B3", "学习能力评估报告:执行功能/学习动机/学习策略/自我效能感");
-        ensureReportTypeRow("dan_b4", "dan", "素质测评B4", "核心素养评估报告:认知能力/成长型思维/自我概念");
-        ensureReportTypeRow("dan_b5", "dan", "素质测评B5", "青春期发展评估报告:情绪调节/人际关系/睡眠/运动/网络依赖/学业压力");
-        ensureReportTypeRow("dan_b6", "dan", "素质测评B6", "职业发展评估报告:霍兰德兴趣/多元智能/职业价值观");
-        ensureReportTypeRow("dan_c1", "dan", "素质测评C1", "校园版核心素养评估报告:认知能力/大五人格/自我概念/学习动机");
-        ensureReportTypeRow("gut_flora_beijing", "gut_flora", "北京菌群检测", "北京肠道菌群检测报告(FMT移植前/后评估)");
-
-        // 种子各类型「应采集指标项」定义(每次启动覆盖,保证与代码一致)
-        seedExpectedIndicator("dan_a1", jsonArray(
-                "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
-                "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
-                "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
-                "总分", "百分位"));
-        seedExpectedIndicator("dan_a2", jsonArray(
-                "BMI", "感知觉_pct", "记忆力_pct", "注意力_pct",
-                "外倾性", "宜人性", "开放性", "责任心", "神经质",
-                "情绪总分", "焦虑-安详", "抑郁-愉快", "无力感-掌控感", "自卑-自尊",
-                "与同伴亲近", "与同伴信任", "与同伴沟通",
-                "与母亲亲近", "与母亲信任", "与母亲沟通",
-                "与父亲亲近", "与父亲信任", "与父亲沟通",
-                "身高", "体重", "睡眠_小时", "运动_小时", "饮食_小时",
-                "总分", "百分位"));
-        seedExpectedIndicator("dan_b2", jsonArray(
-                "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
-                "自我概念_行为表现", "自我概念_躯体外貌",
-                "行为_品行问题", "行为_学习问题", "行为_情绪问题", "行为_生活习惯", "行为_社交问题"));
-        seedExpectedIndicator("dan_b3", jsonArray(
-                "工作记忆_pct", "认知灵活性_pct", "抑制控制_pct",
-                "表面动机", "深层动机", "学习自我调节", "表面方法与策略", "深层方法与策略",
-                "自我效能感", "总分"));
-        seedExpectedIndicator("dan_b4", jsonArray(
-                "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
-                "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
-                "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
-                "成长型思维",
-                "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
-                "自我概念_行为表现", "自我概念_躯体外貌",
-                "自主性", "胜任感", "归属感",
-                "总分", "百分位"));
-        seedExpectedIndicator("dan_b5", jsonArray(
-                "表达抑制", "认知重评",
-                "人际_父亲关系", "人际_父亲关系_过度期待", "人际_父亲关系_价值冲突",
-                "人际_父亲关系_控制压迫", "人际_父亲关系_情感疏离", "人际_父亲关系_双重标准",
-                "人际_母亲关系", "人际_母亲关系_过度期待", "人际_母亲关系_价值冲突",
-                "人际_母亲关系_控制压迫", "人际_母亲关系_情感疏离", "人际_母亲关系_双重标准",
-                "人际_师生关系", "人际_师生关系_敌对型", "人际_师生关系_高控制型",
-                "人际_师生关系_关系疏离型", "人际_师生关系_回避型",
-                "人际_同伴关系", "人际_同伴关系_被排斥型", "人际_同伴关系_边缘型",
-                "人际_同伴关系_攻击型", "人际_同伴关系_回避型", "人际_同伴关系_特殊因素型",
-                "社交_表达影响", "社交_冲突解决", "社交_情感表达", "社交_情感支持", "社交_主动交往",
-                "入睡时间_min", "睡眠_催眠药物", "睡眠_日间功能", "睡眠_时长", "睡眠_效率",
-                "睡眠_障碍", "睡眠_主观质量",
-                "网络依赖_戒断反应", "网络依赖_强迫使用", "网络依赖_时间管理", "网络依赖_总分",
-                "学业压力_家庭期望", "学业压力_师生关系", "学业压力_同伴竞争", "学业压力_学业负担", "学业压力_自我期望",
-                "运动_步行_频率", "运动_步行_时长", "运动_高强度_频率", "运动_高强度_时长",
-                "运动_久坐_频率", "运动_久坐_时长", "运动_中等强度_频率", "运动_中等强度_时长",
-                "总分", "百分位"));
-        seedExpectedIndicator("dan_b6", jsonArray(
-                "能力_内省", "能力_人际关系", "能力_音乐", "能力_自然",
-                "兴趣_常规型", "兴趣_社会型", "兴趣_事业型", "兴趣_现实型", "兴趣_研究型", "兴趣_艺术型",
-                "职业价值观"));
-        seedExpectedIndicator("dan_c1", jsonArray(
-                "BMI",
-                "感知觉_pct", "感知觉_score", "注意力_pct", "注意力_score",
-                "记忆力_pct", "记忆力_score", "推理能力_pct", "推理能力_score",
-                "空间能力_pct", "空间能力_score", "加工速度_pct", "加工速度_score",
-                "外倾性", "宜人性", "开放性", "责任心", "神经质", "情绪总分",
-                "自我概念_合群", "自我概念_幸福与满足", "自我概念_情绪状态", "自我概念_能力与学校",
-                "自我概念_行为表现", "自我概念_躯体外貌",
-                "表面动机", "深层动机", "学习自我调节", "表面方法与策略", "深层方法与策略", "自我效能感",
-                "自主性", "胜任感", "归属感",
-                "与同伴亲近", "与同伴信任", "与同伴沟通",
-                "与母亲亲近", "与母亲信任", "与母亲沟通",
-                "与父亲亲近", "与父亲信任", "与父亲沟通",
-                "身高", "体重", "睡眠时长", "运动时间",
-                "总分", "百分位"));
-        seedExpectedIndicator("gut_flora", jsonArray(
-                "肠道预测年龄", "肠型", "肠道菌群平衡", "菌群多样性", "有益菌", "有害菌", "核心菌属",
-                "健康总分", "菌群健康", "慢病控制", "营养均衡",
-                "疾病风险评估", "主要营养评估", "氨基酸评估", "维生素评估", "微量元素评估",
-                "主要消化道致病菌", "抗生素风险评估", "肠道屏障及代谢物", "短链脂肪酸",
-                "神经递质及激素", "菌群检出详细列表", "个体化食物推荐表"));
-        seedExpectedIndicator("gut_flora_beijing", jsonArray(
-                "肠型", "肠道微生物健康指数", "肠道菌群平衡评估", "肠道黏膜屏障", "肠道菌群多样性",
-                "肠道菌群表型评估", "肠道抗炎能力", "肠道免疫力", "肠道膳食纤维需求", "短链脂肪酸合成能力",
-                "核心菌属综合评分", "有益菌综合评分", "有害菌综合评分",
-                "疾病风险评估", "营养物质及营养素代谢评估", "抗生素风险评估",
-                "毒性物质清除能力评估", "胃肠道感染病原体评估", "趣味肠菌评估",
-                "菌群检出详细列表", "个体化食物推荐表"));
-    }
-
-    /** 注册报告类型行(INSERT IF 不存在,幂等;parser_path=null 保持走 LangGraph 检测) */
-    private void ensureReportTypeRow(String typeId, String family, String displayName, String description) {
-        try {
-            Integer count = jdbcTemplate.queryForObject(
-                    "SELECT COUNT(*) FROM report_type_registry WHERE type_id = ?", Integer.class, typeId);
-            if (count == null || count == 0) {
-                jdbcTemplate.update(
-                        "INSERT INTO report_type_registry (type_id, family, display_name, description, parser_path, " +
-                        "min_confidence, is_active, source, review_status, version, created_at, updated_at) " +
-                        "VALUES (?, ?, ?, ?, NULL, 30, 1, 'prebuilt', 'approved', '1.0', NOW(), NOW())",
-                        typeId, family, displayName, description);
-                log.info("迁移354: 已注册报告类型 {}", typeId);
-            }
-        } catch (Exception e) {
-            log.warn("迁移354: 注册报告类型 {} 失败: {}", typeId, e.getMessage());
-        }
-    }
-
-    /** 写入类型「应采集指标项」定义(仅当为空时写入,保留管理员编辑) */
-    void seedExpectedIndicator(String typeId, String expectedJson) {
-        try {
-            int updated = jdbcTemplate.update(
-                    "UPDATE report_type_registry SET expected_indicators = ?, updated_at = NOW() " +
-                    "WHERE type_id = ? AND (expected_indicators IS NULL OR expected_indicators = '')",
-                    expectedJson, typeId);
-            if (updated == 0) {
-                log.info("迁移354: 类型 {} 已有指标项定义,跳过种子", typeId);
-            } else {
-                log.info("迁移354: 已为类型 {} 写入指标项定义", typeId);
-            }
-        } catch (Exception e) {
-            log.warn("迁移354: 为类型 {} 写入指标项定义失败: {}", typeId, e.getMessage());
-        }
-    }
-
-    /** 简易 JSON 字符串数组序列化(指标项均为中文/ASCII,无转义风险) */
-    private String jsonArray(String... items) {
-        StringBuilder sb = new StringBuilder("[");
-        for (int i = 0; i < items.length; i++) {
-            if (i > 0) {
-                sb.append(',');
-            }
-            sb.append('"').append(items[i]).append('"');
-        }
-        return sb.append(']').toString();
-    }
-
-    // 迁移359: 家庭共餐选中食材表(持久化共餐场景食材选择)
-    private void createDietFamilySelectedIngredientsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS diet_family_selected_ingredients (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
-                    "family_id BIGINT NOT NULL COMMENT '家庭ID'," +
-                    "food_id BIGINT NOT NULL COMMENT '食材ID'," +
-                    "food_name VARCHAR(100) COMMENT '食材名称'," +
-                    "score INT COMMENT '推荐分'," +
-                    "reason VARCHAR(255) COMMENT '推荐理由'," +
-                    "category VARCHAR(50) COMMENT '分类'," +
-                    "calories_per_100g INT COMMENT '每100克卡路里'," +
-                    "cooking_level TINYINT COMMENT '烹饪难度(1=快手,2=中等,3=耗时)'," +
-                    "nutrition_score INT COMMENT '营养密度分(0-100)'," +
-                    "balance_reason VARCHAR(255) COMMENT '均衡化推荐理由'," +
-                    "sort_order INT DEFAULT 0 COMMENT '排序'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
-                    "UNIQUE KEY uk_family_food (family_id, food_id)," +
-                    "INDEX idx_family (family_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭共餐选中食材'");
-            log.info("迁移359: 已创建 diet_family_selected_ingredients 表");
-        } catch (Exception e) {
-            log.warn("迁移359: 创建 diet_family_selected_ingredients 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移356: indicator_definitions 升级为统一指标层(指标变化曲线/速查/关联 需求)
-    private void migrateIndicatorDefinitionsColumns() {
-        ensureColumn("indicator_definitions", "source_kind",
-                "VARCHAR(32) DEFAULT NULL COMMENT '指标来源: report_indicator/bacteria/food_index/dimension_score'");
-        ensureColumn("indicator_definitions", "report_type_scope",
-                "VARCHAR(32) DEFAULT NULL COMMENT '适用报告类型(type_id,空=通用)'");
-        ensureColumn("indicator_definitions", "value_type",
-                "VARCHAR(16) DEFAULT NULL COMMENT '语义类型: numeric/categorical/level'");
-        ensureColumn("indicator_definitions", "good_direction",
-                "VARCHAR(16) DEFAULT 'neutral' COMMENT '变化优劣方向: higher_is_better/lower_is_better/in_range_is_better/neutral'");
-        ensureColumn("indicator_definitions", "dimension_code",
-                "VARCHAR(16) DEFAULT NULL COMMENT '关联五维(body/mind/wisdom/action/wealth,可空)'");
-        log.info("迁移356: indicator_definitions 已补齐统一指标层 5 列");
-    }
-
-    // 迁移357: indicator_values 升级为统一观测时序(subject_id/family_id/report_id/report_date/unit/status)
-    private void migrateIndicatorValuesColumns() {
-        ensureColumn("indicator_values", "subject_id", "BIGINT DEFAULT NULL COMMENT '观测对象(family_members.id)'");
-        ensureColumn("indicator_values", "family_id", "BIGINT DEFAULT NULL COMMENT '所属家庭(family_members.family_id)'");
-        ensureColumn("indicator_values", "report_id", "BIGINT DEFAULT NULL COMMENT '来源报告(health_reports.id,食物指数可空)'");
-        ensureColumn("indicator_values", "report_date", "DATE DEFAULT NULL COMMENT '冗余真实报告日期(时序查询键)'");
-        ensureColumn("indicator_values", "unit", "VARCHAR(32) DEFAULT NULL COMMENT '观测单位'");
-        ensureColumn("indicator_values", "status", "VARCHAR(32) DEFAULT NULL COMMENT '观测状态快照(正常/偏高/偏低等)'");
-        log.info("迁移357: indicator_values 已补齐统一观测时序 6 列");
-    }
-
-    // 迁移358: indicator_values 幂等唯一键(source_type+source_id+definition_id)+ 时序查询索引
-    private void addIndicatorValuesKeys() {
-        try {
-            // 先清理极端重复(保留最小 id),避免建唯一键失败;正常数据本无重复
-            jdbcTemplate.execute(
-                    "DELETE v FROM indicator_values v " +
-                    "JOIN (SELECT MIN(id) keep_id, source_type, source_id, definition_id " +
-                    "      FROM indicator_values " +
-                    "      GROUP BY source_type, source_id, definition_id " +
-                    "      HAVING COUNT(*) > 1) d " +
-                    "  ON v.source_type = d.source_type AND v.source_id = d.source_id " +
-                    " AND v.definition_id = d.definition_id AND v.id <> d.keep_id");
-            log.info("迁移358: 已清理 indicator_values 重复行(如有)");
-        } catch (Exception e) {
-            log.warn("迁移358: 清理 indicator_values 重复行失败(表可能为空): {}", e.getMessage());
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE indicator_values ADD UNIQUE KEY uk_source_definition (source_type, source_id, definition_id)");
-            log.info("迁移358: 已添加 uk_source_definition 唯一键");
-        } catch (Exception e) {
-            log.info("迁移358: uk_source_definition 已存在,跳过");
-        }
-        try {
-            jdbcTemplate.execute("ALTER TABLE indicator_values ADD INDEX idx_subject_def_date (subject_id, definition_id, report_date)");
-            log.info("迁移358: 已添加 idx_subject_def_date 索引");
-        } catch (Exception e) {
-            log.info("迁移358: idx_subject_def_date 已存在,跳过");
-        }
-    }
-
-    // 迁移359: 新建 indicator_mapping_rules(指标归一化映射规则)
-    private void createIndicatorMappingRulesTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS indicator_mapping_rules (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "source_type VARCHAR(32) NOT NULL COMMENT '来源: gut_flora|physical_exam|dan_a2|food_recommend|five_dimension|health_dimension'," +
-                    "raw_name VARCHAR(200) NOT NULL COMMENT '报告中的原始名称(指标名/菌名/食材名)'," +
-                    "alias_text TEXT COMMENT '别名 JSON 数组,用于模糊匹配'," +
-                    "definition_id BIGINT NOT NULL COMMENT 'FK → indicator_definitions.id'," +
-                    "match_type VARCHAR(20) DEFAULT 'exact' COMMENT 'exact|fuzzy|ai_fallback|auto_created'," +
-                    "priority INT DEFAULT 0 COMMENT '多规则冲突时取最高'," +
-                    "status TINYINT DEFAULT 1," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "UNIQUE KEY uk_source_raw (source_type, raw_name)," +
-                    "INDEX idx_def (definition_id)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标归一化映射规则'");
-            log.info("迁移359: 已创建 indicator_mapping_rules 表");
-        } catch (Exception e) {
-            log.warn("迁移359: 创建 indicator_mapping_rules 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移360: 新建 indicator_correlations(指标关联关系:人工定义 + 数据校准)
-    private void createIndicatorCorrelationsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS indicator_correlations (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
-                    "definition_id_a BIGINT NOT NULL COMMENT 'code 字典序较小的指标'," +
-                    "definition_id_b BIGINT NOT NULL COMMENT 'code 字典序较大的指标'," +
-                    "relation_type VARCHAR(20) DEFAULT 'correlation' COMMENT 'correlation|influence|same_source'," +
-                    "direction VARCHAR(10) NOT NULL COMMENT 'positive|negative'," +
-                    "manual_strength DECIMAL(3,2) NOT NULL COMMENT '人工标定强度 0~1'," +
-                    "computed_strength DECIMAL(4,3) NULL COMMENT '统计计算相关系数(Spearman rho)'," +
-                    "method VARCHAR(20) DEFAULT 'spearman' COMMENT 'pearson|spearman'," +
-                    "sample_size INT DEFAULT 0 COMMENT '参与计算的聚合有效样本数'," +
-                    "confidence VARCHAR(10) COMMENT 'high(>=30)|medium(10~29)|low(<10)'," +
-                    "effective_strength DECIMAL(4,3) NOT NULL COMMENT '展示值: 样本>=30 时取 computed 否则取 manual'," +
-                    "manual_locked TINYINT DEFAULT 0 COMMENT '1=人工锁定,校准不覆盖'," +
-                    "cohort_scope VARCHAR(20) DEFAULT 'subject' COMMENT 'subject|family|population'," +
-                    "status VARCHAR(20) DEFAULT 'active' COMMENT 'active|inactive|pending'," +
-                    "computed_at DATETIME NULL COMMENT '最后校准时间'," +
-                    "created_by BIGINT NULL COMMENT '创建者'," +
-                    "description VARCHAR(500) NULL COMMENT '给用户看的解释'," +
-                    "source_note VARCHAR(255) NULL COMMENT '依据/出处'," +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP," +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," +
-                    "UNIQUE KEY uk_pair (definition_id_a, definition_id_b)," +
-                    "INDEX idx_def_a (definition_id_a)," +
-                    "INDEX idx_def_b (definition_id_b)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标关联关系(人工定义+数据校准)'");
-            log.info("迁移360: 已创建 indicator_correlations 表");
-        } catch (Exception e) {
-            log.warn("迁移360: 创建 indicator_correlations 表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移361: health_indicators.collection_date 生产库兜底(schema.sql 已有该列,仅确保老库补齐)
-    private void ensureIndicatorCollectionDate() {
-        ensureColumn("health_indicators", "collection_date",
-                "DATETIME COMMENT '指标采集日期(报告检测日期)'");
-        log.info("迁移361: health_indicators.collection_date 已确认存在");
-    }
-
-    // 迁移362: 预置五维展示定义(dim.body 等,仅作展示标签,不写 indicator_values)
-    private void seedDimensionDefinitions() {
-        Object[][] dims = {
-            {"dim.body",     "身", "身体",  "higher_is_better", "higher_is_better"},
-            {"dim.mind",     "心", "心理",  "higher_is_better", "higher_is_better"},
-            {"dim.wisdom",   "智", "智慧",  "higher_is_better", "higher_is_better"},
-            {"dim.action",   "行", "行动",  "higher_is_better", "higher_is_better"},
-            {"dim.wealth",   "富", "财富",  "higher_is_better", "higher_is_better"},
-        };
-        for (Object[] d : dims) {
-            try {
-                Integer exists = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM indicator_definitions WHERE code = ?", Integer.class, (String) d[0]);
-                if (exists == null || exists == 0) {
-                    jdbcTemplate.update(
-                            "INSERT INTO indicator_definitions (domain, category, code, name, data_type, unit, " +
-                            "source_kind, value_type, good_direction, dimension_code, sort_order, status) " +
-                            "VALUES ('physical', ?, ?, ?, 'number', '分', 'dimension_score', 'numeric', ?, ?, 0, 1)",
-                            d[1], d[0], d[2], d[4], d[3]);
-                    log.info("迁移362: 已预置维度定义 {}", d[0]);
-                }
-            } catch (Exception e) {
-                log.warn("迁移362: 预置维度定义 {} 失败: {}", d[0], e.getMessage());
-            }
-        }
-    }
-
-    // 迁移355: 创建减脂专题体重记录表
-    private void createFatWeightRecordTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS fat_weight_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL, " +
-                    "weight DECIMAL(5,2) NOT NULL, " +
-                    "body_fat_percent DECIMAL(4,2) DEFAULT NULL, " +
-                    "waist_circumference DECIMAL(4,2) DEFAULT NULL, " +
-                    "measure_date DATE NOT NULL, " +
-                    "remark VARCHAR(255) DEFAULT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_fat_weight_member (member_id, measure_date)) " +
-                    "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-体重体脂记录'");
-            log.info("迁移355: 已创建fat_weight_record表");
-        } catch (Exception e) {
-            log.warn("迁移355: 创建fat_weight_record表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移356: 创建减脂专题饮食记录表
-    private void createFatDietRecordTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS fat_diet_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL, " +
-                    "meal_type VARCHAR(20) NOT NULL, " +
-                    "food_name VARCHAR(255) NOT NULL, " +
-                    "food_weight DECIMAL(6,2) DEFAULT NULL, " +
-                    "calories INT DEFAULT 0, " +
-                    "protein DECIMAL(6,2) DEFAULT 0, " +
-                    "fat DECIMAL(6,2) DEFAULT 0, " +
-                    "carbs DECIMAL(6,2) DEFAULT 0, " +
-                    "eat_date DATE NOT NULL, " +
-                    "remark VARCHAR(255) DEFAULT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_fat_diet_member (member_id, eat_date)) " +
-                    "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-饮食记录'");
-            log.info("迁移356: 已创建fat_diet_record表");
-        } catch (Exception e) {
-            log.warn("迁移356: 创建fat_diet_record表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移357: 创建减脂专题运动记录表
-    private void createFatExerciseRecordTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS fat_exercise_record (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL, " +
-                    "exercise_type VARCHAR(50) NOT NULL, " +
-                    "duration_min INT DEFAULT 0, " +
-                    "distance_km DECIMAL(5,2) DEFAULT NULL, " +
-                    "calories_burned INT DEFAULT 0, " +
-                    "exercise_date DATE NOT NULL, " +
-                    "remark VARCHAR(255) DEFAULT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "INDEX idx_fat_exercise_member (member_id, exercise_date)) " +
-                    "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-运动记录'");
-            log.info("迁移357: 已创建fat_exercise_record表");
-        } catch (Exception e) {
-            log.warn("迁移357: 创建fat_exercise_record表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移358: 创建减脂专题目标表
-    private void createFatGoalTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS fat_goal (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "member_id BIGINT NOT NULL, " +
-                    "target_weight DECIMAL(5,2) NOT NULL, " +
-                    "start_weight DECIMAL(5,2) NOT NULL, " +
-                    "target_body_fat DECIMAL(4,2) DEFAULT NULL, " +
-                    "target_date DATE DEFAULT NULL, " +
-                    "status VARCHAR(20) DEFAULT 'active', " +
-                    "start_date DATE NOT NULL, " +
-                    "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
-                    "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "INDEX idx_fat_goal_member (member_id)) " +
-                    "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-减脂目标'");
-            log.info("迁移358: 已创建fat_goal表");
-        } catch (Exception e) {
-            log.warn("迁移358: 创建fat_goal表失败: {}", e.getMessage());
-        }
-    }
-
-    private void addProductVendorVisibleColumn() {
-        ensureColumn("products", "vendor_visible", "TINYINT(1) DEFAULT NULL COMMENT '是否仅供应商体系内用户可见(列表接口生效,直接分享可bypass)'");
-    }
-
-    // 迁移367: products 表添加健康约束字段(基础疾病禁忌/过敏原/药物相互作用标记)
-    private void addProductHealthConstraintColumns() {
-        ensureColumn("products", "contraindicated_diseases", "VARCHAR(255) DEFAULT NULL COMMENT '禁忌基础疾病,逗号分隔(如\"慢性肾病,肝病\")'");
-        ensureColumn("products", "allergen_tags", "VARCHAR(255) DEFAULT NULL COMMENT '过敏原标签,逗号分隔(如\"花生,小麦\")'");
-        ensureColumn("products", "drug_interaction_flags", "TINYINT DEFAULT 0 COMMENT '是否命中药物-食物相互作用(1=是,需对照drug_interactions表)'");
-    }
-
-    // 迁移368: 创建 drug_interactions 表(药物-食物禁忌对照表)
-    private void createDrugInteractionsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS drug_interactions (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "drug_class VARCHAR(50) NOT NULL COMMENT '药物类别(如CCB/他汀/抗凝药/抗生素/铁剂/甲状腺药/利尿剂/MAOI/头孢/降糖药)', " +
-                    "drug_specifics VARCHAR(100) NOT NULL COMMENT '具体药名(如硝苯地平/华法林)', " +
-                    "interacting_subst VARCHAR(100) NOT NULL COMMENT '禁忌/需间隔的食材或成分(如西柚/维生素K)', " +
-                    "risk_level TINYINT NOT NULL COMMENT '1=拦截 2=警告 3=需间隔', " +
-                    "action_type VARCHAR(20) NOT NULL COMMENT 'block=硬拦截 warn=软警告 space=间隔', " +
-                    "interval_minutes INT DEFAULT NULL COMMENT '需间隔时长(分钟)', " +
-                    "note VARCHAR(255) COMMENT '风险说明', " +
-                    "UNIQUE KEY uk_drug_food (drug_class, drug_specifics, interacting_subst), " +
-                    "INDEX idx_interacting (interacting_subst)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='药物-食物禁忌对照表'");
-            log.info("迁移368: 已创建drug_interactions表");
-        } catch (Exception e) {
-            log.warn("迁移368: 创建drug_interactions表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移369: 创建 disease_intake_limits 表(疾病-饮食摄入阈值)
-    private void createDiseaseIntakeLimitsTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS disease_intake_limits (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "disease_type VARCHAR(50) NOT NULL COMMENT '疾病类型(慢性肾病/糖尿病/高血压/痛风/肝病/甲状腺疾病)', " +
-                    "nutrient VARCHAR(20) NOT NULL COMMENT '校验营养素(protein/potassium/phosphorus/sodium/carb/glycemic/fructose/purine/alcohol/iodine)', " +
-                    "unit VARCHAR(20) NOT NULL COMMENT '单位', " +
-                    "threshold_max DECIMAL(8,2) DEFAULT NULL COMMENT '每日上限', " +
-                    "threshold_min DECIMAL(8,2) DEFAULT NULL COMMENT '每日下限', " +
-                    "block_foods VARCHAR(500) DEFAULT NULL COMMENT '硬拦截食材列表,逗号分隔(如杨桃)', " +
-                    "stage_dependent TINYINT(1) DEFAULT 0 COMMENT '是否按病情分期(1=是 0=否)', " +
-                    "INDEX idx_disease_nutrient (disease_type, nutrient)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='疾病-饮食摄入校验阈值表'");
-            log.info("迁移369: 已创建disease_intake_limits表");
-        } catch (Exception e) {
-            log.warn("迁移369: 创建disease_intake_limits表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移370: 初始化 drug_interactions 种子数据(高危组合,幂等)
-    private void seedDrugInteractionsData() {
-        String[][] seed = {
-                {"CCB", "硝苯地平", "西柚", "1", "block", "0", "西柚抑制药物代谢酶,血药浓度升高数倍,低血压风险,服药期间完全避免"},
-                {"CCB", "氨氯地平", "西柚", "1", "block", "0", "西柚抑制药物代谢酶,血药浓度升高数倍,低血压风险,服药期间完全避免"},
-                {"他汀类", "辛伐他汀", "西柚", "1", "block", "0", "增加肌肉损伤、肝损伤风险"},
-                {"他汀类", "阿托伐他汀", "西柚", "1", "block", "0", "增加肌肉损伤、肝损伤风险"},
-                {"抗凝药", "华法林", "维生素K", "2", "warn", "0", "维K拮抗药效,摄入量保持稳定,调整饮食结构前先与医生沟通"},
-                {"抗凝药", "华法林", "大蒜", "2", "warn", "0", "大蒜可能增强抗凝作用,增加出血风险"},
-                {"抗生素", "四环素", "牛奶", "3", "space", "120", "钙与药物结合影响吸收,需间隔2小时以上"},
-                {"抗生素", "喹诺酮类", "牛奶", "3", "space", "120", "钙与药物结合影响吸收,需间隔2小时以上"},
-                {"抗生素", "喹诺酮类", "钙剂", "3", "space", "120", "钙与药物结合影响吸收,需间隔2小时以上"},
-                {"铁剂", "硫酸亚铁", "茶", "3", "space", "60", "鞣酸抑制铁吸收,需间隔1-2小时"},
-                {"铁剂", "硫酸亚铁", "咖啡", "3", "space", "60", "鞣酸抑制铁吸收,需间隔1-2小时"},
-                {"铁剂", "硫酸亚铁", "钙剂", "3", "space", "60", "钙抑制铁吸收,需间隔1-2小时"},
-                {"铁剂", "硫酸亚铁", "牛奶", "3", "space", "60", "钙抑制铁吸收,需间隔1-2小时"},
-                {"甲状腺药", "左甲状腺素", "豆浆", "3", "space", "240", "影响吸收,需间隔4小时"},
-                {"甲状腺药", "左甲状腺素", "高纤维食物", "3", "space", "240", "影响吸收,需间隔4小时"},
-                {"甲状腺药", "左甲状腺素", "钙剂", "3", "space", "240", "影响吸收,需间隔4小时"},
-                {"保钾利尿剂", "螺内酯", "高钾食物", "2", "warn", "0", "高钾血症风险,避免香蕉、橙汁、低钠盐大量集中摄入"},
-                {"MAOI", "苯乙肼", "发酵食品", "2", "warn", "0", "酪胺反应可致血压骤升,避免奶酪/豆豉/腌制品/陈年食品"},
-                {"头孢类", "头孢类", "酒精", "1", "block", "0", "双硫仑样反应,严重可危及生命"},
-                {"甲硝唑", "甲硝唑", "酒精", "1", "block", "0", "双硫仑样反应,严重可危及生命"},
-                {"降糖药", "磺脲类", "酒精", "1", "block", "0", "低血糖风险,避免空腹饮酒"}
-        };
-        for (String[] row : seed) {
-            try {
-                Integer cnt = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM drug_interactions WHERE drug_class=? AND drug_specifics=? AND interacting_subst=?",
-                        Integer.class, row[0], row[1], row[2]);
-                if (cnt != null && cnt > 0) continue;
-                jdbcTemplate.update(
-                        "INSERT INTO drug_interactions (drug_class, drug_specifics, interacting_subst, risk_level, action_type, interval_minutes, note) VALUES (?,?,?,?,?,?,?)",
-                        row[0], row[1], row[2], Integer.valueOf(row[3]), row[4], Integer.valueOf(row[5]), row[6]);
-            } catch (Exception e) {
-                log.warn("迁移370: 插入drug_interactions种子失败: {}", e.getMessage());
-            }
-        }
-        log.info("迁移370: drug_interactions种子数据初始化完成");
-    }
-
-    // 迁移371: 初始化 disease_intake_limits 种子数据(幂等)
-    private void seedDiseaseIntakeLimitsData() {
-        String[][] seed = {
-                {"慢性肾病", "protein", "g/kg/day", "0.8", "0.6", "杨桃", "1"},
-                {"慢性肾病", "potassium", "mmol/L/day", "5.0", "3.5", "杨桃,香蕉,橙子,土豆,菠菜,菌菇", "1"},
-                {"慢性肾病", "phosphorus", "mg/day", "800", "600", "杨桃,奶制品,坚果,加工食品", "1"},
-                {"糖尿病", "carb", "g/meal", "75", "30", "", "0"},
-                {"糖尿病", "fructose", "g/day", "50", "0", "含糖饮料,果汁,蜂蜜,甜点", "0"},
-                {"高血压", "sodium", "g/day", "5", "2", "腌菜,酱菜,酱油,加工肉制品,挂面,咸味零食", "0"},
-                {"痛风", "purine", "mg/day", "300", "150", "动物内脏,部分海鲜,浓肉汤", "0"},
-                {"痛风", "fructose", "g/day", "50", "0", "含糖饮料,蜂蜜", "0"},
-                {"肝病", "protein", "g/kg/day", "1.0", "0.5", "", "1"},
-                {"甲状腺疾病", "iodine", "ug/day", "300", "150", "海带,紫菜", "0"}
-        };
-        for (String[] row : seed) {
-            try {
-                Integer cnt = jdbcTemplate.queryForObject(
-                        "SELECT COUNT(*) FROM disease_intake_limits WHERE disease_type=? AND nutrient=?",
-                        Integer.class, row[0], row[1]);
-                if (cnt != null && cnt > 0) continue;
-                jdbcTemplate.update(
-                        "INSERT INTO disease_intake_limits (disease_type, nutrient, unit, threshold_max, threshold_min, block_foods, stage_dependent) VALUES (?,?,?,?,?,?,?)",
-                        row[0], row[1], row[2], row[3], row[4], row[5], Integer.valueOf(row[6]));
-            } catch (Exception e) {
-                log.warn("迁移371: 插入disease_intake_limits种子失败: {}", e.getMessage());
-            }
-        }
-        log.info("迁移371: disease_intake_limits种子数据初始化完成");
-    }
-
-    // 迁移363: 创建采购任务表(商品组合推荐与采购任务生命周期管理)
-    private void createProcurementTaskTable() {
-        try {
-            jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS procurement_tasks (" +
-                    "id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
-                    "task_id VARCHAR(64) NOT NULL COMMENT '任务唯一标识', " +
-                    "user_id BIGINT NOT NULL COMMENT '所属用户ID', " +
-                    "family_member_id BIGINT NOT NULL COMMENT '所属家庭成员ID', " +
-                    "combo_tier VARCHAR(20) NOT NULL COMMENT '选择的套餐等级: high|medium|low', " +
-                    "original_combo_tier VARCHAR(20) DEFAULT NULL COMMENT '原始套餐等级(用于自定义追踪)', " +
-                    "selected_product_sku_ids TEXT COMMENT '最终选中的产品SKU列表(JSON数组)', " +
-                    "custom_addition_sku_ids TEXT COMMENT '用户自新增的产品SKU列表(JSON数组)', " +
-                    "custom_removal_sku_ids TEXT COMMENT '用户移除的产品SKU列表(JSON数组)', " +
-                    "status VARCHAR(32) NOT NULL COMMENT '任务状态: SELECTED|PROCURING|PROCURED|EXECUTING|COMPLETED|CANCELLED', " +
-                    "create_time DATETIME NOT NULL COMMENT '创建时间', " +
-                    "complete_time DATETIME DEFAULT NULL COMMENT '完成时间', " +
-                    "message_reminder_sent TINYINT DEFAULT 0 COMMENT '是否已发送消息提醒', " +
-                    "execution_task_id VARCHAR(64) DEFAULT NULL COMMENT '关联的执行任务ID', " +
-                    "update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
-                    "UNIQUE KEY uk_task_id (task_id), " +
-                    "INDEX idx_user_id (user_id), " +
-                    "INDEX idx_family_member_id (family_member_id), " +
-                    "INDEX idx_status (status), " +
-                    "INDEX idx_create_time (create_time)" +
-                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购任务表(商品组合推荐与采购任务生命周期管理)'");
-            log.info("已创建procurement_tasks表");
-        } catch (Exception e) {
-            log.warn("创建procurement_tasks表失败: {}", e.getMessage());
-        }
-    }
-
-    // 迁移364: health_report_drafts 添加解析进度/重试字段(INFORMATION_SCHEMA 检查后再 ALTER,幂等)
-    private void addDraftParseProgressColumns() {
-        if (!columnExists("health_report_drafts", "parse_attempt")) {
-            jdbcTemplate.execute("ALTER TABLE health_report_drafts ADD COLUMN parse_attempt INT DEFAULT 0 COMMENT '已知类型解析重试次数'");
-            log.info("已添加 parse_attempt 列到 health_report_drafts 表");
-        }
-        if (!columnExists("health_report_drafts", "next_retry_at")) {
-            jdbcTemplate.execute("ALTER TABLE health_report_drafts ADD COLUMN next_retry_at DATETIME NULL COMMENT '下次自动重试时间(指数退避,上限5分钟)'");
-            log.info("已添加 next_retry_at 列到 health_report_drafts 表");
-        }
-        if (!columnExists("health_report_drafts", "parse_started_at")) {
-            jdbcTemplate.execute("ALTER TABLE health_report_drafts ADD COLUMN parse_started_at DATETIME NULL COMMENT '最近一次解析开始时间'");
-            log.info("已添加 parse_started_at 列到 health_report_drafts 表");
-        }
-        if (!columnExists("health_report_drafts", "parse_finished_at")) {
-            jdbcTemplate.execute("ALTER TABLE health_report_drafts ADD COLUMN parse_finished_at DATETIME NULL COMMENT '最近一次解析结束时间(成功/失败)'");
-            log.info("已添加 parse_finished_at 列到 health_report_drafts 表");
-        }
-    }
-}
+// 迁移 354: 创建 user_content_weights 表(用户内容偏好权重表)
+        try {
+            jdbcTemplate.execute(
+                "CREATE TABLE IF NOT EXISTS user_content_weights (" +
+                "id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID'," +
+                "user_id BIGINT NOT NULL COMMENT '用户ID(users.id)'," +
+                "family_id BIGINT NOT NULL COMMENT '家庭ID'," +
+                "content_type VARCHAR(16) NOT NULL COMMENT '内容类型: product/activity/article'," +
+                "item_id BIGINT NOT NULL COMMENT '内容ID(商品ID/活动ID/文章ID)'," +
+                "dimension_code VARCHAR(32) DEFAULT NULL COMMENT '维度编码: body/mind/wisdom/action/wealth'," +
+                "weight DECIMAL(5,2) NOT NULL DEFAULT 1.00 COMMENT '权重值 0.00-10.00,越大越优先'," +
+                "reason VARCHAR(200) DEFAULT NULL COMMENT '权重来源: user_set/auto_click/auto_purchase/manual/auto_profile'," +
+                "created_by BIGINT DEFAULT NULL COMMENT '创建人ID(manual场景记录运营人员)'," +
+                "created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'," +
+                "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'," +
+                "INDEX idx_user_content (user_id, content_type, item_id), " +
+                "INDEX idx_family_dimension (family_id, dimension_code), " +
+                "UNIQUE KEY uk_user_item (user_id, content_type, item_id)" +
+                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户内容偏好权重表'"
+            );
+            log.info("已添加 user_content_weights 表到数据库");
+        } catch (Exception e) {
+            // 表已存在,忽略错误
+            log.warn("user_content_weights 表可能已存在,跳过创建", e);
+        }

+ 35 - 6
cfc-backend/src/main/java/com/etotem/cfc/service/ProductRecommendationService.java

@@ -58,6 +58,9 @@ public class ProductRecommendationService {
     @Resource
     private SupplySystemService supplySystemService;
 
+    @Resource
+    private UserContentWeightService userContentWeightService;
+
     /**
      * 维度页推荐
      *
@@ -207,7 +210,7 @@ public class ProductRecommendationService {
         }
 
         // 5. 最终排序并返回
-        return sortAndReturn(candidates, limit, userId);
+        return sortAndReturn(candidates, limit, userId, familyId);
     }
 
     /**
@@ -521,13 +524,14 @@ public class ProductRecommendationService {
 
     /**
      * 根据 matchScore 和供应商优先级进行最终排序
+     * 权重表有数据时按家庭权重总和排序,无权重数据时回退 matchScore
      */
-    private List<Map<String, Object>> sortAndReturn(List<Map<String, Object>> candidates, int limit, Long userId) {
+    private List<Map<String, Object>> sortAndReturn(List<Map<String, Object>> candidates, int limit, Long userId, Long familyId) {
         if (candidates == null || candidates.isEmpty()) return Collections.emptyList();
-
+        
         // 计算供应商优先级加分(规则1~3)
         Map<Long, Double> supplierPriorityScores = getSupplierPriorityScores(userId);
-
+        
         // 将供应商优先级加入 matchScore
         if (!supplierPriorityScores.isEmpty()) {
             for (Map<String, Object> item : candidates) {
@@ -541,8 +545,33 @@ public class ProductRecommendationService {
                 item.put("supplierPriorityBoost", priorityBoost != null ? priorityBoost : 0);
             }
         }
-
+        
+        // 计算每个商品的家庭权重总和(家庭聚合:Σ成员权重,方向一致均为正向)
+        Map<Long, Double> productWeightSum = new HashMap<>();
+        if (familyId != null) {
+            for (Map<String, Object> item : candidates) {
+                Long productId = (Long) item.get("productId");
+                if (productId == null) continue;
+                // 查该家庭所有成员对该商品的权重,求和
+                List<UserContentWeight> weights = userContentWeightService.listWeights(null, familyId, "product", productId);
+                double sum = 0.0;
+                if (weights != null) {
+                    for (UserContentWeight w : weights) {
+                        sum += w.getWeight() != null ? w.getWeight().doubleValue() : 0.0;
+                    }
+                }
+                productWeightSum.put(productId, sum);
+                item.put("userWeight", sum);
+            }
+        }
+        
+        // 排序:优先按用户权重(降序),权重相同或无权重数据时回退 matchScore(降序)
         candidates.sort((a, b) -> {
+            Double weightA = productWeightSum.getOrDefault((Long) a.get("productId"), 0.0);
+            Double weightB = productWeightSum.getOrDefault((Long) b.get("productId"), 0.0);
+            int cmp = weightB.compareTo(weightA);
+            if (cmp != 0) return cmp;
+            
             Double scoreA = (Double) a.get("matchScore");
             Double scoreB = (Double) b.get("matchScore");
             if (scoreA == null && scoreB == null) return 0;
@@ -550,7 +579,7 @@ public class ProductRecommendationService {
             if (scoreB == null) return -1;
             return scoreB.compareTo(scoreA);
         });
-
+        
         // 去重(按 productId 去重)
         Set<Long> seenIds = new HashSet<>();
         List<Map<String, Object>> result = new ArrayList<>();

+ 13 - 6332
cfc-backend/src/main/resources/schema.sql

@@ -1,6336 +1,17 @@
--- 浠艾福数据库初始化脚本
--- 自动创建表
-
--- 推荐规则表(统一推荐引擎规则配置)
-CREATE TABLE IF NOT EXISTS recommendation_rules (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    rule_type TINYINT NOT NULL COMMENT '1-5',
-    rule_name VARCHAR(100) COMMENT '运营名称',
-    trigger_product_id BIGINT COMMENT '触发商品ID',
-    trigger_product_ids VARCHAR(1000) COMMENT '触发商品ID JSON 数组',
-    target_product_id BIGINT COMMENT '目标商品ID',
-    priority INT DEFAULT 10 COMMENT '优先级,越大越优',
-    enabled TINYINT DEFAULT 1 COMMENT '启用 1/0',
-    time_window_days INT COMMENT '回溯窗口(天)',
-    delay_days INT COMMENT '复购延迟天数',
-    scope VARCHAR(20) COMMENT 'family/individual',
-    scene_codes VARCHAR(500) COMMENT '生效场景 JSON 数组',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐规则配置';
-
--- 推荐规则表索引
-CREATE INDEX idx_rules_enabled ON recommendation_rules(enabled);
-CREATE INDEX idx_rules_scene ON recommendation_rules(scene_codes);
-CREATE INDEX idx_rules_priority ON recommendation_rules(priority);
-
--- 浠艾福数据库初始化脚本
--- 自动创建表
-
--- 家庭表
-CREATE TABLE IF NOT EXISTS families (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100),
-    invite_code VARCHAR(8) UNIQUE,
-    butler_id BIGINT COMMENT '绑定的管家userId',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_invite_code (invite_code),
-    INDEX idx_butler_id (butler_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 用户表
-CREATE TABLE IF NOT EXISTS users (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    openid VARCHAR(64) NOT NULL,
-    unionid VARCHAR(64),
-    family_id BIGINT,
-    role VARCHAR(20) NOT NULL,
-    roles VARCHAR(100) COMMENT '角色列表JSON/逗号分隔(多角色)',
-    nickname VARCHAR(50),
-    avatar VARCHAR(255),
-    password VARCHAR(128),
-    session_key VARCHAR(64) COMMENT '微信登录会话密钥(虚拟支付签名用)',
-    id_card VARCHAR(18),
-    real_name VARCHAR(50),
-    phone VARCHAR(11),
-    birthday DATE,
-    gender ENUM('male','female'),
-    birth_hour VARCHAR(10) COMMENT '出生时辰: 子丑寅卯辰巳午未申酉戌亥',
-    mascot VARCHAR(20) DEFAULT NULL COMMENT 'AI助手形象: xibao(浠宝)/fubao(福宝)',
-    portrait_prompt TEXT COMMENT '用户自定义画像 prompt(为空时自动从 profile_snapshot 渲染)',
-    family_inviter_id BIGINT DEFAULT NULL COMMENT '家庭邀请人ID(首次注册时绑定,用于追踪邀请来源)',
-    province VARCHAR(50) DEFAULT NULL COMMENT '省份',
-    city VARCHAR(50) DEFAULT NULL COMMENT '城市',
-    district VARCHAR(50) DEFAULT NULL COMMENT '区县',
-    street VARCHAR(100) DEFAULT NULL COMMENT '详细地址',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_openid (openid),
-    INDEX idx_family_id (family_id),
-    INDEX idx_phone (phone)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
--- 注:role 字段值 'child' 已废弃,存量数据通过迁移298统一归一为 'parent'。
--- 可登录成员(有 openid)= 原 role='child' 迁移后的账号;
--- 不可登录成员(无 openid)= 家长手动创建的子账号。
-
--- ============================================================
--- 【已删除】children 表已废弃:数据由 DatabaseInitializer 迁移322 迁移至 family_members 后 DROP。
--- 保留此处仅作参考,勿执行
--- ============================================================
--- CREATE TABLE IF NOT EXISTS children (
---     id BIGINT AUTO_INCREMENT PRIMARY KEY,
---     user_id BIGINT NOT NULL,
---     family_id BIGINT NOT NULL,
---     nickname VARCHAR(50) NOT NULL,
---     age TINYINT NOT NULL,
---     birthday DATE,
---     gender ENUM('male','female'),
---     penalty_enabled TINYINT DEFAULT 1 COMMENT '是否开启扣分(0否1是)',
---     theme VARCHAR(32) DEFAULT 'default',
---     total_points INT DEFAULT 0,
---     system_points INT DEFAULT 0 COMMENT 'CF值(测评建档/平台发放)',
---     streak_days INT DEFAULT 0,
---     last_task_date DATE,
---     focus_max_daily TINYINT DEFAULT 3,
---     focus_remaining TINYINT DEFAULT 3,
---     focus_reset_date DATE,
---     created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
---     updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
---     INDEX idx_user_id (user_id),
---     INDEX idx_family_id (family_id)
--- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 任务表
-CREATE TABLE IF NOT EXISTS tasks (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL,
-    creator_id BIGINT NOT NULL,
-    child_id BIGINT COMMENT '执行者ID(child任务时必填,parent任务时可空)',
-    executor_type VARCHAR(20) COMMENT '执行者类型: child=非登录用户/parent=可登录家长/member=其他成员',
-    executor_id BIGINT COMMENT '执行者ID',
-    title VARCHAR(200) NOT NULL,
-    description TEXT,
-    points TINYINT DEFAULT 2 COMMENT '任务积分1-10',
-    deadline DATETIME NOT NULL,
-    accept_deadline DATETIME DEFAULT NULL COMMENT '接受截止时间(分配给其他家庭成员的任务)',
-    repeat_type ENUM('none', 'daily', 'weekly') DEFAULT 'none',
-    category VARCHAR(32),
-    need_review TINYINT DEFAULT 0 COMMENT '是否需要审核',
-    review_by_category TINYINT DEFAULT 0 COMMENT '是否按分类审核',
-    status ENUM('pending', 'assigned', 'in_progress', 'completed', 'rejected', 'overdue', 'cancelled', 'locked', 'pending_review') DEFAULT 'pending',
-    completed_at DATETIME,
-    bonus_rule JSON COMMENT '积分奖励规则',
-    points_expire_days INT DEFAULT 0 COMMENT '积分有效期天数',
-    dimension_code VARCHAR(20) COMMENT '五维维度: body/mind/wisdom/action/wealth',
-    dimension_weights JSON COMMENT '五维权重: {"body":0,"mind":0,"wisdom":0,"action":0,"wealth":0}',
-    parent_task_id BIGINT NULL COMMENT '父任务ID(购买任务→每日使用子任务链;子任务在父任务完成前不显示)',
-    -- TASK-SYS-248: 行为调度中心扩展字段
-    prerequisite_task_id BIGINT NULL COMMENT '前置任务ID:完成后才解锁本任务',
-    is_flow_task TINYINT DEFAULT 0 COMMENT '是否为流程任务:1=是(有前置/后置任务),0=否',
-    successor_task_ids TEXT NULL COMMENT '后置任务IDs JSON: [1,2,3],任意一个完成则解锁(OR 逻辑)',
-    action_type VARCHAR(32) NULL COMMENT '联动动作: minigame/focus/survey/article/activity/cart/order',
-    action_config JSON NULL COMMENT '联动参数: {"gameCode":"schulte","productId":123,"minSeconds":30,"completeMilestone":"paid"/"received","surveyId":99}',
-    require_input TINYINT DEFAULT 0 COMMENT '1=需填写内容才能完成',
-    start_required TINYINT DEFAULT 0 COMMENT '1=需先开始再完成(两阶段)',
-    start_count INT DEFAULT 0 COMMENT '已开始次数(累计)',
-    min_duration_seconds INT DEFAULT 0 COMMENT '最短持续秒数(专注/游戏类,未达标不计完成)',
-    source_type VARCHAR(32) DEFAULT NULL COMMENT '来源类型: self/assigned/plan/health_plan/training_plan/onboarding/ai/template/article/activity/purchase',
-    source_id BIGINT DEFAULT NULL COMMENT '来源ID(plan_instance_id/template_id/article_id等)',
-    is_daily_progress TINYINT DEFAULT 0 COMMENT '1=每日进度型任务(无deadline,每日重置)',
-    target_value INT DEFAULT NULL COMMENT '进度目标值(is_daily_progress=1时有效)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_id_deadline (child_id, deadline),
-    INDEX idx_status (status),
-    INDEX idx_category (category),
-    INDEX idx_executor (executor_type, executor_id),
-    INDEX idx_dimension_code (dimension_code),
-    INDEX idx_executor_assigned (executor_type, executor_id, status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 任务执行进度表(两阶段/里程碑/填写内容记录)
-CREATE TABLE IF NOT EXISTS task_executions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    task_id BIGINT NOT NULL COMMENT '任务实例ID',
-    member_id BIGINT NULL COMMENT '执行成员ID(family_members.id)',
-    status VARCHAR(20) NOT NULL DEFAULT 'started' COMMENT 'started/finished/failed',
-    started_at DATETIME NOT NULL COMMENT '开始时间',
-    finished_at DATETIME COMMENT '完成时间',
-    milestone VARCHAR(32) COMMENT '购物任务里程碑: cart_added/paid/received(当前进度)',
-    content TEXT COMMENT '填写内容(require_input 任务)',
-    content_type VARCHAR(20) COMMENT 'content 类型: text/image/audio/video',
-    extra JSON COMMENT '扩展数据: {gameScore, focusMinutes, orderId, articleId, surveyId}',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_task_member (task_id, member_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务执行进度表';
-
--- 积分流水表
-CREATE TABLE IF NOT EXISTS points_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    family_member_id BIGINT COMMENT '家庭成员ID',
-    task_id BIGINT,
-    amount INT NOT NULL COMMENT '积分数量正负',
-    type ENUM('earn', 'spend', 'bonus', 'penalty', 'adjust', 'reset', 'refund') NOT NULL,
-    category VARCHAR(20) DEFAULT 'task' COMMENT '积分分类: task-任务积分, cf-CF值',
-    description TEXT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_id_created (child_id, created_at),
-    INDEX idx_type (type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 积分清零记录表
-CREATE TABLE IF NOT EXISTS points_reset_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    balance_before INT NOT NULL,
-    balance_after INT DEFAULT 0,
-    reset_type ENUM('monthly', 'manual') NOT NULL,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 奖励表
-CREATE TABLE IF NOT EXISTS rewards (
-id BIGINT AUTO_INCREMENT PRIMARY KEY,
-family_id BIGINT NOT NULL COMMENT '家庭 ID,所有奖励必须关联家庭',
-child_id BIGINT NULL COMMENT '孩子 ID,模板奖励为NULL',
-title VARCHAR(100) NOT NULL,
-points_required INT NOT NULL,
-category VARCHAR(32),
-status ENUM('available', 'pending', 'exchanged', 'rejected') DEFAULT 'available',
-exchange_approved TINYINT COMMENT '是否审批通过',
-exchanged_at DATETIME,
-is_template TINYINT DEFAULT 0 COMMENT '是否为预设模板',
-created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-INDEX idx_family_id (family_id),
-INDEX idx_child_id_status (child_id, status),
-INDEX idx_is_template (is_template)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='奖励表,所有奖励必须关联到具体家庭';
-
--- 奖励分类表
-CREATE TABLE IF NOT EXISTS reward_categories (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL,
-    name VARCHAR(32) NOT NULL,
-    icon VARCHAR(64),
-    sort_order INT DEFAULT 0,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 预设奖励模板数据(child_id为NULL表示模板)
-INSERT IGNORE INTO rewards (family_id, child_id, title, points_required, category, is_template) VALUES
-(0, NULL, '看动画片30分钟', 30, '精神奖励', 1),
-(0, NULL, '玩平板游戏30分钟', 40, '特权奖励', 1),
-(0, NULL, '去游乐场', 100, '物质奖励', 1),
-(0, NULL, '买玩具', 150, '物质奖励', 1),
-(0, NULL, '吃冰淇淋', 20, '物质奖励', 1),
-(0, NULL, '选择晚餐', 25, '特权奖励', 1);
-
--- 默认奖励分类
-INSERT IGNORE INTO reward_categories (family_id, name, icon, sort_order) VALUES
-(0, '物质奖励', 'gift', 1),
-(0, '精神奖励', 'star', 2),
-(0, '特权奖励', 'crown', 3);
-
--- 敏感词表
-CREATE TABLE IF NOT EXISTS sensitive_words (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    word VARCHAR(50) NOT NULL,
-    category VARCHAR(32) NOT NULL,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_word (word)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 任务审核表
-CREATE TABLE IF NOT EXISTS task_reviews (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    task_id BIGINT NOT NULL,
-    child_id BIGINT NOT NULL,
-    photo_url VARCHAR(255),
-    voice_note_url VARCHAR(255),
-    ai_result ENUM('pass', 'review', 'pending'),
-    ai_confidence INT COMMENT 'AI置信度(0-100)',
-    ai_suggestion VARCHAR(255),
-    ai_threshold ENUM('strict', 'normal', 'loose') DEFAULT 'normal',
-    parent_result ENUM('pass', 'reject'),
-    parent_override TINYINT DEFAULT 0,
-    review_type ENUM('ai', 'manual') NOT NULL,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    reviewed_at DATETIME,
-    INDEX idx_task_id (task_id),
-    INDEX idx_ai_result (ai_result)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 打卡里程碑表
-CREATE TABLE IF NOT EXISTS streak_milestones (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    days INT NOT NULL,
-    reward_points INT DEFAULT 0,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 插入打卡里程碑数据
-INSERT IGNORE INTO streak_milestones (days, reward_points) VALUES
-(3, 5),
-(7, 10),
-(30, 30),
-(100, 100);
-
--- 专注训练记录表
-CREATE TABLE IF NOT EXISTS focus_sessions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    mode ENUM('simple', 'pomodoro') NOT NULL,
-    duration TINYINT NOT NULL,
-    stars TINYINT COMMENT '评分1-5',
-    points_earned INT,
-    voice_note_url VARCHAR(255),
-    started_at DATETIME NOT NULL,
-    completed_at DATETIME,
-    task_id BIGINT NULL COMMENT '关联的任务ID(专注任务挂钩)',
-    INDEX idx_child_id_completed (child_id, completed_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 专注训练配置表
-CREATE TABLE IF NOT EXISTS focus_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT,
-    max_daily_count TINYINT DEFAULT 3,
-    allow_exit TINYINT DEFAULT 1 COMMENT '是否允许退出(0否1是)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- DAN测评表
-CREATE TABLE IF NOT EXISTS dan_assessments (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    assessment_date DATE NOT NULL,
-    details JSON,
-    source ENUM('api', 'manual') DEFAULT 'manual',
-    photo_url VARCHAR(255),
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 任务模板表
-CREATE TABLE IF NOT EXISTS task_templates (
-id BIGINT AUTO_INCREMENT PRIMARY KEY,
-title VARCHAR(200) NOT NULL,
-points TINYINT DEFAULT 2,
-duration_minutes TINYINT,
-category VARCHAR(32),
-is_default TINYINT DEFAULT 1,
-family_id BIGINT,
-created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-INDEX idx_is_default (is_default)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 媒体记录表(支持图片、视频、音频、文字)
-CREATE TABLE IF NOT EXISTS media_records (
-id BIGINT AUTO_INCREMENT PRIMARY KEY,
-type ENUM('image', 'video', 'audio', 'text') NOT NULL,
-url VARCHAR(500),
-description TEXT,
-task_id BIGINT NOT NULL,
-creator_id BIGINT NOT NULL,
-original_filename VARCHAR(255),
-file_size BIGINT,
-content_type VARCHAR(100),
-created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-INDEX idx_task_id (task_id),
-INDEX idx_creator_id (creator_id),
-INDEX idx_type (type),
-FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
-FOREIGN KEY (creator_id) REFERENCES users(id) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 服务商(成长规划师)相关表
--- =============================================
-
--- 服务商表(统一管理 teacher/planner/activity_provider/product_supplier)
-CREATE TABLE IF NOT EXISTS guides (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL UNIQUE COMMENT '用户ID(唯一)',
-    type VARCHAR(32) DEFAULT 'teacher' COMMENT '服务商类型: teacher/planner/activity_provider/product_supplier',
-    teacher_no VARCHAR(20) COMMENT '服务商编号',
-    title VARCHAR(50) COMMENT '职称/称号',
-    specialty VARCHAR(200) COMMENT '专长领域',
-    bio TEXT COMMENT '简介',
-    university VARCHAR(200) COMMENT '毕业院校',
-    education_system VARCHAR(32) COMMENT '教育体系(参考education_systems表)',
-    experience_years TINYINT DEFAULT 0 COMMENT '从业年限',
-    rating INT DEFAULT 500 COMMENT '评分(百分位,500=5.00)',
-    total_appointments INT DEFAULT 0 COMMENT '总服务次数',
-    level VARCHAR(20) NOT NULL DEFAULT 'junior' COMMENT '等级: junior-初级, intermediate-中级, senior-高级',
-    status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active-活跃, inactive-停用',
-    service_count INT DEFAULT 0 COMMENT '当前服务家庭数',
-    package_id BIGINT COMMENT '购买套餐ID',
-    nickname VARCHAR(100) COMMENT '申请昵称',
-    phone VARCHAR(20) COMMENT '联系电话',
-    intro TEXT COMMENT '个人介绍',
-    avatar VARCHAR(500) COMMENT '头像URL',
-    commission_rate INT DEFAULT 1000 COMMENT '佣金比例(基点,1000=10%)',
-    street_id BIGINT COMMENT '街道ID',
-    province VARCHAR(50) COMMENT '省份',
-    city VARCHAR(50) COMMENT '城市',
-    district VARCHAR(50) COMMENT '区县',
-    street VARCHAR(100) COMMENT '街道',
-    approved_at DATETIME COMMENT '审核通过时间',
-    verified_at DATETIME COMMENT '认证通过时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_id (user_id),
-    INDEX idx_level (level),
-    INDEX idx_status (status),
-    INDEX idx_type (type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务商表(规划师/活动方/供应商)';
-
--- 测评预约表
-CREATE TABLE IF NOT EXISTS assessment_appointments (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID',
-    family_id BIGINT NOT NULL,
-    child_id BIGINT COMMENT '孩子ID',
-    teacher_id BIGINT COMMENT '教师ID',
-    guide_id BIGINT COMMENT '规划师ID',
-    assessor_id BIGINT COMMENT '测评师ID(供应商体系)',
-    package_id BIGINT COMMENT '套餐ID',
-    appointment_date VARCHAR(20) COMMENT '预约日期 yyyy-MM-dd',
-    appointment_time VARCHAR(20) COMMENT '预约时间 HH:mm',
-    duration_minutes INT COMMENT '测评时长',
-    status TINYINT DEFAULT 0 COMMENT '0=待确认,1=已确认,2=已完成,3=已取消,4=未到',
-    appointment_type VARCHAR(20) DEFAULT 'initial' COMMENT '初测/复测/回访',
-    notes TEXT COMMENT '备注',
-    remark TEXT COMMENT '补充说明',
-    contact_phone VARCHAR(20),
-    meet_link VARCHAR(255) COMMENT '会议链接',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_teacher_id (teacher_id),
-    INDEX idx_guide_id (guide_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_child_id (child_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- DAN测评结果表
-CREATE TABLE IF NOT EXISTS dan_assessment_results (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    family_member_id BIGINT COMMENT '家庭成员ID',
-    family_member_name VARCHAR(50) COMMENT '成员姓名快照',
-    family_member_birthday DATE COMMENT '成员出生日期快照',
-    family_member_gender VARCHAR(10) COMMENT '成员性别快照',
-    family_member_age INT COMMENT '成员年龄快照',
-    teacher_id BIGINT NOT NULL,
-    appointment_id BIGINT,
-    attention_score INT COMMENT '注意力得分',
-    focus_score INT COMMENT '专注力得分',
-    memory_score INT COMMENT '记忆力得分',
-    logic_score INT COMMENT '逻辑思维得分',
-    perception_score INT COMMENT '感知得分',
-    spatial_score INT COMMENT '空间思维得分',
-    processing_speed_score INT COMMENT '加工速度得分',
-    language_score INT COMMENT '语言表达得分',
-    emotion_score INT COMMENT '情绪商数(EMI)',
-    resilience_score INT COMMENT '心理韧性(EMI)',
-    stress_coping_score INT COMMENT '压力应对(EMI)',
-    self_awareness_score INT COMMENT '自我认知(EMI)',
-    emotion_management_score INT COMMENT '情绪管理得分(EMI)',
-    empathy_score INT COMMENT '同理心得分(EMI)',
-    social_adaptability_score INT COMMENT '社会适应得分(EMI)',
-    self_motivation_score INT COMMENT '自我激励得分(EMI)',
-    overall_score INT COMMENT '综合得分',
-    openness_score INT COMMENT '开放性(大五人格)',
-    conscientiousness_score INT COMMENT '尽责性(大五人格)',
-    extraversion_score INT COMMENT '外向性(大五人格)',
-    agreeableness_score INT COMMENT '宜人性(大五人格)',
-    neuroticism_score INT COMMENT '神经质(大五人格)',
-    big_five_overall_score INT COMMENT '大五人格综合分',
-    assessment_date DATE NOT NULL,
-    duration_minutes INT COMMENT '测评时长',
-    game_records JSON COMMENT '游戏记录详情',
-    analysis_report TEXT COMMENT '分析报告',
-    growth_suggestions TEXT COMMENT '成长建议',
-    next_review_date DATE COMMENT '下次复测日期',
-    status ENUM('draft', 'completed', 'archived') DEFAULT 'draft',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    -- 孩子快照字段(测评时保存的完整信息)
-    child_name VARCHAR(50) COMMENT '孩子姓名快照',
-    child_birthday DATE COMMENT '出生日期快照',
-    child_gender VARCHAR(10) COMMENT '性别快照',
-    child_age INT COMMENT '年龄快照',
-    school VARCHAR(100) COMMENT '学校快照',
-    grade VARCHAR(20) COMMENT '年级快照',
-    grade_class VARCHAR(20) COMMENT '班级快照',
-    height INT COMMENT '身高(CM)快照',
-    weight INT COMMENT '体重(KG)快照',
-    family_status VARCHAR(50) COMMENT '家庭状况快照',
-    parent_degree VARCHAR(50) COMMENT '父母最高学历快照',
-    nation VARCHAR(20) COMMENT '民族快照',
-    province VARCHAR(50) COMMENT '省快照',
-    city VARCHAR(50) COMMENT '市快照',
-    district VARCHAR(50) COMMENT '区快照',
-    address VARCHAR(200) COMMENT '详细地址快照',
-    single_child VARCHAR(10) COMMENT '是否独生子女快照',
-    school_score VARCHAR(20) COMMENT '在校成绩快照',
-    urgent_name VARCHAR(50) COMMENT '紧急联系人姓名',
-    urgent_phone VARCHAR(20) COMMENT '紧急联系人电话',
-    -- 媒体字段
-    pics TEXT COMMENT '图片IDs',
-    videos TEXT COMMENT '视频IDs',
-    audio VARCHAR(100) COMMENT '音频ID',
-    audio_url VARCHAR(255) COMMENT '音频URL',
-    -- 扩展描述字段
-    process_desc TEXT COMMENT '过程描述',
-    result_desc TEXT COMMENT '结果简评',
-    source VARCHAR(20) DEFAULT 'planner_entry' COMMENT '报告来源: planner_entry/parent_upload/auto_fetch',
-    dimension VARCHAR(10) DEFAULT 'mind' COMMENT '报告维度: mind(心-A2)/wisdom(智-B4)',
-    report_file_id VARCHAR(500) COMMENT '上传文件媒资ID或相对路径',
-    draft_status VARCHAR(10) DEFAULT 'pending' COMMENT '草稿状态: pending(待确认)/confirmed(已确认)',
-    dan_level VARCHAR(10) DEFAULT NULL COMMENT 'DAN等级A/B/C/D',
-    INDEX idx_child_id (child_id),
-    INDEX idx_teacher_id (teacher_id),
-    INDEX idx_assessment_date (assessment_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DAN测评结果表';
-
--- 成长规划表
-CREATE TABLE IF NOT EXISTS growth_plans (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    teacher_id BIGINT NOT NULL,
-    assessment_id BIGINT,
-    plan_title VARCHAR(200) NOT NULL,
-    plan_content TEXT NOT NULL COMMENT '规划内容',
-    duration_months TINYINT COMMENT '规划周期(月)',
-    status ENUM('draft', 'active', 'completed', 'expired') DEFAULT 'draft',
-    start_date DATE,
-    end_date DATE,
-    review_count INT DEFAULT 0 COMMENT '已复盘次数',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id),
-    INDEX idx_teacher_id (teacher_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 成长档案表
--- =============================================
-CREATE TABLE IF NOT EXISTS growth_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL COMMENT '孩子ID',
-    family_member_id BIGINT COMMENT '家庭成员ID',
-    family_member_age INT COMMENT '家庭成员年龄(月)',
-    parent_id BIGINT NOT NULL COMMENT '家长用户ID',
-    family_member_id BIGINT COMMENT '关联家庭成员ID',
-    family_member_age INT COMMENT '成员年龄快照',
-    assessment_id BIGINT COMMENT '关联的测评结果ID',
-    record_title VARCHAR(200) COMMENT '档案标题',
-    child_age INT COMMENT '孩子当时年龄(月)',
-    height VARCHAR(20) COMMENT '身高',
-    weight VARCHAR(20) COMMENT '体重',
-    school VARCHAR(100) COMMENT '学校名称',
-    grade INT COMMENT '年级(数字)',
-    academicPerformance VARCHAR(200) COMMENT '成绩/学业表现',
-    schoolProvince VARCHAR(50) COMMENT '学校所在省',
-    schoolCity VARCHAR(50) COMMENT '学校所在市',
-    schoolDistrict VARCHAR(50) COMMENT '学校所在区',
-    schoolStreet VARCHAR(100) COMMENT '学校所在街道',
-    assessment_summary TEXT COMMENT '测评摘要',
-    overall_score INT COMMENT '综合得分',
-    growth_suggestions TEXT COMMENT '成长建议',
-    task_recommendations TEXT COMMENT '任务推荐(JSON)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed',
-    external_sync TINYINT DEFAULT 0 COMMENT '是否来自外部系统同步',
-    external_source VARCHAR(100) COMMENT '外部系统来源',
-    source_type VARCHAR(20) DEFAULT 'manual' COMMENT '来源类型: manual/platform_purchase/self_upload/supplement',
-    source_file_url VARCHAR(500) COMMENT '原始报告文件URL',
-    order_id BIGINT COMMENT '关联订单ID',
-    report_date DATETIME COMMENT '测评/报告日期',
-    parent_record_id BIGINT COMMENT '关联的原始档案ID(补充档案专用)',
-    is_latest TINYINT(1) DEFAULT 1 COMMENT '是否同组最新记录',
-    dedup_hash VARCHAR(64) COMMENT '去重哈希值(SHA256)',
-    parsed_data TEXT COMMENT '上传报告的解析结果(JSON)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id),
-    INDEX idx_parent_id (parent_id),
-    INDEX idx_status (status),
-    UNIQUE INDEX uk_growth_dedup_hash (dedup_hash)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 数据库迁移(新增字段和表)- 通过Java代码处理
--- =============================================
-
--- 注意:ALTER TABLE语句已移到 DatabaseInitializer.java 中执行
--- 避免重复执行导致的错误
-
--- 3. 家长心愿单表(新增)
-CREATE TABLE IF NOT EXISTS reward_wishlists (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '创建者用户ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    title VARCHAR(100) NOT NULL COMMENT '心愿名称',
-    description TEXT COMMENT '心愿描述',
-    points_required INT NOT NULL COMMENT '所需积分',
-    category VARCHAR(32) COMMENT '分类',
-    image_url VARCHAR(255) COMMENT '图片链接',
-    status ENUM('available', 'pending', 'exchanged', 'rejected') DEFAULT 'available' COMMENT '状态',
-    exchange_approved TINYINT COMMENT '是否审批通过',
-    exchanged_at DATETIME COMMENT '兑换时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 4. 更新任务状态枚举(如果需要支持更多状态)
--- ALTER TABLE tasks MODIFY COLUMN status ENUM('pending', 'completed', 'overdue', 'cancelled', 'parent_pending', 'parent_completed') DEFAULT 'pending';
-
--- ===================== 任务模板套餐功能 =====================
-
--- 成长规划师-家庭关系表
-CREATE TABLE IF NOT EXISTS guide_families (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    guide_id BIGINT NOT NULL COMMENT '成长规划师用户ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    service_type VARCHAR(20) DEFAULT 'consulting' COMMENT '服务类型: monthly/yearly/consulting',
-    service_price INT DEFAULT 0 COMMENT '服务价格(分)',
-    status VARCHAR(20) DEFAULT 'binding' COMMENT '状态: binding/paused/cancelled',
-    bound_at DATETIME COMMENT '绑定时间',
-    expire_at DATETIME COMMENT '服务到期时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_guide_family (guide_id, family_id),
-    INDEX idx_guide_id (guide_id),
-    INDEX idx_family_id (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 任务模板套餐
-CREATE TABLE IF NOT EXISTS task_template_packages (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    creator_id BIGINT NOT NULL COMMENT '创建者成长规划师ID',
-    name VARCHAR(100) NOT NULL COMMENT '套餐名称',
-    description TEXT COMMENT '详细介绍',
-    cycle_days INT NOT NULL COMMENT '周期天数',
-    category VARCHAR(50) COMMENT '分类',
-    tags JSON COMMENT '标签',
-    price INT DEFAULT 0 COMMENT '售价(分)',
-    platform_fee INT DEFAULT 0 COMMENT '平台服务费(基点)',
-    is_public TINYINT DEFAULT 0 COMMENT '是否公开',
-    share_code VARCHAR(50) UNIQUE COMMENT '分享码',
-    cover_image VARCHAR(500) COMMENT '封面图',
-    status VARCHAR(20) DEFAULT 'draft' COMMENT '状态',
-    reviewer_id BIGINT COMMENT '审核人',
-    reviewed_at DATETIME COMMENT '审核时间',
-    reject_reason TEXT COMMENT '拒绝原因',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_creator_id (creator_id),
-    INDEX idx_status (status),
-    INDEX idx_is_public (is_public)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 套餐内任务项
-CREATE TABLE IF NOT EXISTS task_template_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    package_id BIGINT NOT NULL COMMENT '所属套餐ID',
-    task_name VARCHAR(100) NOT NULL,
-    description TEXT,
-    points INT DEFAULT 0,
-    frequency VARCHAR(20) DEFAULT 'daily',
-    duration INT COMMENT '预计时长(分钟)',
-    is_required TINYINT DEFAULT 0,
-    sort_order INT DEFAULT 0,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_package_id (package_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 套餐应用实例
-CREATE TABLE IF NOT EXISTS task_plan_instances (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    package_id BIGINT NOT NULL,
-    family_id BIGINT NOT NULL,
-    child_id BIGINT NOT NULL,
-    name VARCHAR(100) NOT NULL,
-    start_date DATE NOT NULL,
-    end_date DATE NOT NULL,
-    status VARCHAR(20) DEFAULT 'active',
-    total_days INT,
-    completed_days INT DEFAULT 0,
-    source VARCHAR(20) DEFAULT NULL COMMENT '来源: manual/assessment/template',
-    source_result_id BIGINT DEFAULT NULL COMMENT '关联测评结果ID',
-    remark TEXT COMMENT '方案备注',
-    reviewed_by BIGINT DEFAULT NULL COMMENT '审核人(规划师ID)',
-    reviewed_at DATETIME DEFAULT NULL COMMENT '审核时间',
-    review_comment TEXT COMMENT '审核意见',
-    confirmed_by BIGINT DEFAULT NULL COMMENT '确认人(家长ID)',
-    confirmed_at DATETIME DEFAULT NULL COMMENT '确认时间',
-    activated_at DATETIME DEFAULT NULL COMMENT '激活时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id),
-    INDEX idx_child_id (child_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 实例任务项
-CREATE TABLE IF NOT EXISTS task_plan_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    instance_id BIGINT NOT NULL,
-    template_item_id BIGINT,
-    task_name VARCHAR(100) NOT NULL,
-    description TEXT,
-    points INT DEFAULT 0,
-    frequency VARCHAR(20) DEFAULT 'daily',
-    duration INT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_instance_id (instance_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 套餐购买订单
-CREATE TABLE IF NOT EXISTS package_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    order_no VARCHAR(32) UNIQUE NOT NULL,
-    user_id BIGINT NOT NULL COMMENT '购买者用户ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    package_id BIGINT NOT NULL COMMENT '套餐ID',
-    package_name VARCHAR(100) COMMENT '套餐名称',
-    price INT NOT NULL COMMENT '支付金额(分)',
-    platform_fee INT DEFAULT 0 COMMENT '平台服务费(分)',
-    user_coupon_id BIGINT COMMENT '使用的用户优惠券ID',
-    guide_id BIGINT COMMENT '成长规划师ID',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/paid/cancelled/refunded',
-    pay_method VARCHAR(20) COMMENT '支付方式',
-    transaction_id VARCHAR(64) COMMENT '微信支付订单号',
-    paid_at DATETIME COMMENT '支付时间',
-    notify_data TEXT COMMENT '支付回调数据',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_package_id (package_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 用户表增加成长规划师相关字段 - 已移到 DatabaseInitializer.java 执行
--- ALTER TABLE users ADD COLUMN teacher_no VARCHAR(50) COMMENT '成长规划师证书号';
--- ALTER TABLE users ADD COLUMN teacher_photo VARCHAR(500) COMMENT '成长规划师照片';
--- ALTER TABLE users ADD COLUMN certificate_image VARCHAR(500) COMMENT '成长规划师证书照片';
--- ALTER TABLE users ADD COLUMN teacher_status VARCHAR(20) DEFAULT 'pending' COMMENT '成长规划师审核状态: pending/approved/rejected';
--- ALTER TABLE users ADD INDEX idx_teacher_status (teacher_status);
-
--- 成长规划师咨询消息表
-CREATE TABLE IF NOT EXISTS teacher_messages (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    parent_id BIGINT NOT NULL COMMENT '家长用户ID',
-    teacher_id BIGINT NOT NULL COMMENT '成长规划师用户ID',
-    content TEXT NOT NULL COMMENT '消息内容',
-    reply_content TEXT COMMENT '回复内容',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态:pending/replied',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    replied_at DATETIME COMMENT '回复时间',
-    INDEX idx_family_id (family_id),
-    INDEX idx_teacher_id (teacher_id),
-    INDEX idx_parent_id (parent_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 游戏记录表(专注训练模块)
-CREATE TABLE IF NOT EXISTS game_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL COMMENT '孩子ID',
-    game_code VARCHAR(20) NOT NULL COMMENT '游戏代码',
-    score INT DEFAULT 0 COMMENT '得分(0-100)',
-    completion_time INT COMMENT '完成用时(秒)',
-    difficulty VARCHAR(20) DEFAULT 'medium' COMMENT '难度(easy/medium/hard)',
-    points_earned INT DEFAULT 0 COMMENT '获得积分',
-    played_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '游玩时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id),
-    INDEX idx_game_code (game_code),
-    INDEX idx_played_at (played_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 勋章定义表
-CREATE TABLE IF NOT EXISTS badge (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    badge_id VARCHAR(50) UNIQUE NOT NULL COMMENT '勋章唯一标识',
-    name VARCHAR(100) NOT NULL COMMENT '勋章名称',
-    description TEXT COMMENT '勋章描述',
-    icon VARCHAR(255) COMMENT '勋章图标',
-    category VARCHAR(20) COMMENT '分类(学习/运动/家务/阅读/打卡/综合)',
-    level VARCHAR(20) COMMENT '等级(铜牌/银牌/金牌/钻石)',
-    rarity VARCHAR(20) COMMENT '稀有度(普通/稀有/史诗/传说)',
-    trigger_type VARCHAR(20) COMMENT '触发类型(task_count/streak_days/points_total/reward_count/custom)',
-    threshold INT DEFAULT 0 COMMENT '阈值',
-    need_approval TINYINT DEFAULT 0 COMMENT '是否需要审批',
-    expire_days INT DEFAULT -1 COMMENT '有效期天数(-1永久)',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    is_active TINYINT DEFAULT 1 COMMENT '是否启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_category (category),
-    INDEX idx_is_active (is_active)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 儿童勋章关联表
-CREATE TABLE IF NOT EXISTS child_badge (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL COMMENT '孩子ID',
-    badge_id BIGINT NOT NULL COMMENT '勋章ID',
-    earned_at DATETIME COMMENT '获得时间',
-    expire_at DATETIME COMMENT '过期时间',
-    status TINYINT DEFAULT 1 COMMENT '状态:1有效 0过期 -1撤销',
-    is_favorite TINYINT DEFAULT 0 COMMENT '是否收藏',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_child_badge (child_id, badge_id),
-    INDEX idx_child_id (child_id),
-    INDEX idx_badge_id (badge_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 以下表从 DatabaseInitializer.java 提取
--- 管理后台表
--- =============================================
-
--- 管理员表
-CREATE TABLE IF NOT EXISTS admins (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    username VARCHAR(50) NOT NULL COMMENT '用户名',
-    password VARCHAR(128) NOT NULL COMMENT '密码(MD5加密)',
-    nickname VARCHAR(50) COMMENT '昵称',
-    real_name VARCHAR(50) COMMENT '真实姓名',
-    phone VARCHAR(11) COMMENT '手机号',
-    email VARCHAR(100) COMMENT '邮箱',
-    role VARCHAR(20) DEFAULT 'admin' COMMENT '角色: admin/teacher',
-    status TINYINT DEFAULT 1 COMMENT '状态:1启用0禁用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_phone (phone),
-    INDEX idx_username (username)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理员表';
-
--- 验证码表
-CREATE TABLE IF NOT EXISTS verification_codes (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    phone VARCHAR(11) NOT NULL COMMENT '手机号',
-    code VARCHAR(6) NOT NULL COMMENT '验证码',
-    type VARCHAR(20) NOT NULL DEFAULT 'login' COMMENT '验证码类型: login/register/reset',
-    expires_in INT DEFAULT 300 COMMENT '过期时间(秒)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    expires_at DATETIME NOT NULL COMMENT '过期时间',
-    used TINYINT DEFAULT 0 COMMENT '是否已使用:0否1是',
-    INDEX idx_phone_type (phone, type),
-    INDEX idx_expires_at (expires_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='验证码表';
-
--- 管理后台任务模板表
-CREATE TABLE IF NOT EXISTS admin_task_templates (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    title VARCHAR(200) NOT NULL COMMENT '模板标题',
-    description TEXT COMMENT '模板描述',
-    points INT DEFAULT 10 COMMENT '默认积分',
-    category VARCHAR(32) COMMENT '任务分类',
-    need_review TINYINT DEFAULT 0 COMMENT '是否需要审核:0否1是',
-    review_by_category TINYINT DEFAULT 0 COMMENT '是否按分类审核:0否1是',
-    recommended_age INT COMMENT '推荐年龄',
-    difficulty ENUM('easy', 'medium', 'hard') DEFAULT 'medium' COMMENT '难度: easy/medium/hard',
-    teacher_id BIGINT COMMENT '成长规划师ID',
-    onboarding_sequence INT DEFAULT NULL COMMENT '新人引导顺序(source_type=onboarding的模板用)',
-    complete_types VARCHAR(100) COMMENT '完成方式JSON',
-    duration INT COMMENT '预计完成时长(分钟)',
-    review_type VARCHAR(20) COMMENT '审核人类型: creator/parent/teacher/ai',
-    task_type VARCHAR(20) COMMENT '任务性质: onetime/recurring',
-    frequency VARCHAR(20) COMMENT '频率: daily/weekly/monthly',
-    max_frequency INT COMMENT '周期内最多完成次数',
-    is_active TINYINT DEFAULT 1 COMMENT '是否启用:0禁用1启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_category (category),
-    INDEX idx_difficulty (difficulty),
-    INDEX idx_is_active (is_active)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管理后台任务模板表';
-
--- =============================================
--- 测评模块表
--- =============================================
-
--- 测评资料表
--- 数学闯关 - 孩子当前等级
-CREATE TABLE IF NOT EXISTS math_child_level (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL UNIQUE,
-    current_level TINYINT NOT NULL DEFAULT 1 COMMENT '1=一位数加减,2=两位数加减,3=一位数四则,4=两位数四则',
-    total_passed INT DEFAULT 0 COMMENT '累计通关次数',
-    best_time_ms BIGINT DEFAULT NULL COMMENT '最佳用时(毫秒)',
-    best_accuracy INT DEFAULT NULL COMMENT '最佳正确率(%)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 数学闯关 - 通关日志
-CREATE TABLE IF NOT EXISTS math_quiz_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL,
-    level TINYINT NOT NULL COMMENT '闯关时等级',
-    target_n INT NOT NULL COMMENT '目标连续答对数',
-    correct_count INT NOT NULL COMMENT '实际连续答对数',
-    total_attempts INT NOT NULL COMMENT '总答题数',
-    total_time_ms BIGINT NOT NULL COMMENT '总用时(毫秒)',
-    accuracy INT NOT NULL COMMENT '正确率(%)',
-    passed TINYINT(1) DEFAULT 0 COMMENT '是否通关',
-    exprs TEXT COMMENT '本轮表达式列表(JSON)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id),
-    INDEX idx_level (level)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
-CREATE TABLE IF NOT EXISTS assessment_materials (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
-    title VARCHAR(100) NOT NULL COMMENT '资料标题',
-    content TEXT COMMENT '测评介绍内容',
-    cover_image VARCHAR(255) COMMENT '封面图片',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态:active/inactive',
-    created_at DATETIME COMMENT '创建时间',
-    updated_at DATETIME COMMENT '更新时间',
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评资料表';
-
--- 积分配置表
-CREATE TABLE IF NOT EXISTS assessment_points_config (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
-    points_value INT DEFAULT 100 COMMENT '完成测评获得积分',
-    points_value_yuan INT DEFAULT 1 COMMENT '1积分等于多少分(原元→现分)',
-    is_active TINYINT DEFAULT 1 COMMENT '是否启用',
-    created_at DATETIME COMMENT '创建时间',
-    updated_at DATETIME COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分配置表';
-
--- 家庭测评配置表
-CREATE TABLE IF NOT EXISTS family_assessment_config (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    material_id BIGINT COMMENT '测评资料ID',
-    remind_months INT DEFAULT 12 COMMENT '提醒周期(月)',
-    last_remind_at DATETIME COMMENT '上次提醒时间',
-    next_remind_at DATETIME COMMENT '下次提醒时间',
-    is_enabled TINYINT DEFAULT 1 COMMENT '是否启用:1启用0关闭',
-    created_by BIGINT COMMENT '创建人(规划师ID)',
-    created_at DATETIME COMMENT '创建时间',
-    updated_at DATETIME COMMENT '更新时间',
-    UNIQUE KEY uk_family (family_id),
-    INDEX idx_next_remind (next_remind_at),
-    INDEX idx_enabled (is_enabled)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭测评配置表';
-
--- 测评记录表
-CREATE TABLE IF NOT EXISTS assessment_records (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
-    family_id BIGINT COMMENT '家庭ID',
-    child_id BIGINT COMMENT '孩子ID',
-    material_id BIGINT COMMENT '测评资料ID',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态:pending待完成/completed已完成',
-    completed_at DATETIME COMMENT '完成时间',
-    created_at DATETIME COMMENT '创建时间',
-    INDEX idx_family (family_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评记录表';
-
--- 评估订单表(测评订单)
-CREATE TABLE IF NOT EXISTS assessment_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    order_no VARCHAR(64) NOT NULL UNIQUE COMMENT '订单编号',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT COMMENT '孩子ID',
-    guide_id BIGINT NOT NULL COMMENT '成长规划师ID',
-    package_id BIGINT NOT NULL COMMENT '套餐ID',
-    appointment_id BIGINT COMMENT '关联预约ID',
-    guide_name VARCHAR(50) COMMENT '规划师名称',
-    package_name VARCHAR(100) COMMENT '套餐名称',
-    total_price BIGINT DEFAULT 0 COMMENT '总价(分)',
-    discount_amount BIGINT DEFAULT 0 COMMENT '优惠金额(分)',
-    actual_price BIGINT DEFAULT 0 COMMENT '实付金额(分)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/paid/completed/cancelled/refunded',
-    pay_time VARCHAR(50) COMMENT '支付时间',
-    pay_type VARCHAR(20) COMMENT '支付方式',
-    transaction_id VARCHAR(64) COMMENT '交易流水号',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_family (family_id),
-    INDEX idx_guide (guide_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评估订单表';
-
--- =============================================
--- 成长规划师相关表
--- =============================================
-
--- 成长规划师申请表
-CREATE TABLE IF NOT EXISTS guide_applications (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '申请人用户ID',
-    type VARCHAR(20) NOT NULL DEFAULT 'new_apply' COMMENT '申请类型: new_apply-新注册, upgrade-升级',
-    target_level VARCHAR(20) NOT NULL COMMENT '目标等级: junior-初级, intermediate-中级, senior-高级',
-    current_level VARCHAR(20) DEFAULT NULL COMMENT '当前等级(升级时填写)',
-    package_id BIGINT COMMENT '申请的套餐ID',
-    payment_proof VARCHAR(500) COMMENT '付款凭证URL',
-    payment_amount INT COMMENT '付款金额(分)',
-    address VARCHAR(500) COMMENT '地址',
-    bank_card VARCHAR(50) COMMENT '银行卡号',
-    bank_name VARCHAR(100) COMMENT '开户行',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending-待审核, approved-已通过, rejected-已拒绝',
-    reject_reason TEXT COMMENT '拒绝原因',
-    reviewed_at DATETIME COMMENT '审核时间',
-    reviewed_by BIGINT COMMENT '审核人ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_id (user_id),
-    INDEX idx_status (status),
-    INDEX idx_type (type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师申请表';
-
--- 成长规划师申请过程记录表
-CREATE TABLE IF NOT EXISTS guide_application_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    application_id BIGINT NOT NULL COMMENT '关联申请ID',
-    user_id BIGINT NOT NULL COMMENT '操作人用户ID',
-    action VARCHAR(50) NOT NULL COMMENT '操作: submit/approve/reject/withdraw/resubmit',
-    from_status VARCHAR(20) COMMENT '操作前状态',
-    to_status VARCHAR(20) NOT NULL COMMENT '操作后状态',
-    remark TEXT COMMENT '备注/原因',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_application_id (application_id),
-    INDEX idx_user_id (user_id),
-    INDEX idx_action (action)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师申请过程记录表';
-
--- =============================================
--- 小游戏表
--- =============================================
-
--- 小游戏表
-CREATE TABLE IF NOT EXISTS mini_games (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    game_code VARCHAR(20) NOT NULL UNIQUE COMMENT '游戏代码',
-    game_name VARCHAR(50) NOT NULL COMMENT '游戏名称',
-    description TEXT COMMENT '游戏描述',
-    icon VARCHAR(50) COMMENT '图标emoji',
-    default_duration INT DEFAULT 5 COMMENT '默认时长(分钟)',
-    default_points INT DEFAULT 5 COMMENT '默认奖励积分',
-    game_url VARCHAR(255) COMMENT '游戏H5页面URL',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status TINYINT DEFAULT 1 COMMENT '状态:0禁用1启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_game_code (game_code),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小游戏表';
-
--- =============================================
--- 地址维度表
--- =============================================
-
--- 街道地址维度表
-CREATE TABLE IF NOT EXISTS streets (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    province VARCHAR(50) COMMENT '省份',
-    province_code VARCHAR(20) COMMENT '省份编码',
-    city VARCHAR(50) COMMENT '城市',
-    city_code VARCHAR(20) COMMENT '城市编码',
-    district VARCHAR(50) COMMENT '区县',
-    district_code VARCHAR(20) COMMENT '区县编码',
-    street VARCHAR(100) COMMENT '街道',
-    street_code VARCHAR(20) COMMENT '街道编码',
-    full_name VARCHAR(200) COMMENT '完整地址',
-    level INT COMMENT '层级:1省2市3区4街道',
-    parent_id BIGINT COMMENT '父级ID',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_level (level),
-    INDEX idx_parent_id (parent_id),
-    INDEX idx_street_code (street_code),
-    INDEX idx_full_name (full_name(50))
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='街道地址维度表';
-
--- =============================================
--- 系统日志表
--- =============================================
-
--- 用户操作日志表
-CREATE TABLE IF NOT EXISTS user_operation_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT COMMENT '用户ID',
-    nickname VARCHAR(50) COMMENT '用户昵称',
-    operation_type VARCHAR(20) NOT NULL COMMENT '操作类型: login/logout/create/update/delete/query等',
-    description TEXT COMMENT '操作描述',
-    request_path VARCHAR(200) COMMENT '请求路径',
-    request_method VARCHAR(10) COMMENT '请求方法',
-    request_params TEXT COMMENT '请求参数(脱敏)',
-    response_status INT COMMENT '响应状态码',
-    client_ip VARCHAR(50) COMMENT '客户端IP',
-    user_agent VARCHAR(500) COMMENT 'User-Agent',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_user_id (user_id),
-    INDEX idx_operation_type (operation_type),
-    INDEX idx_created_at (created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户操作日志表';
-
--- =============================================
--- 邀请与心愿表
--- =============================================
-
--- 邀请卡片表
-CREATE TABLE IF NOT EXISTS invite_card (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    type VARCHAR(20) NOT NULL COMMENT '类型: child/family/guide',
-    code VARCHAR(64) NOT NULL UNIQUE COMMENT '邀请码',
-    ref_id BIGINT NOT NULL COMMENT '关联ID(childId/familyId)',
-    creator_id BIGINT NOT NULL COMMENT '创建人',
-    expires_at DATETIME NOT NULL COMMENT '过期时间',
-    used TINYINT DEFAULT 0 COMMENT '是否已使用:0否1是',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_code (code),
-    INDEX idx_ref_type (ref_id, type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='邀请卡片表';
-
--- 心愿单表
-CREATE TABLE IF NOT EXISTS wishes (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    family_id BIGINT COMMENT '家庭ID',
-    child_id BIGINT COMMENT '目标孩子ID',
-    created_by BIGINT COMMENT '创建者用户ID',
-    creator_type VARCHAR(20) COMMENT '创建者类型: child/parent',
-    title VARCHAR(200) NOT NULL COMMENT '心愿标题',
-    description TEXT COMMENT '心愿描述',
-    category VARCHAR(32) COMMENT '心愿分类',
-    points_required INT COMMENT '所需积分',
-    points_set_by BIGINT COMMENT '定价者ID',
-    points_set_at DATETIME COMMENT '定价时间',
-    status VARCHAR(32) DEFAULT 'active' COMMENT '状态: draft/active/pending_exchange/approved/exchanging/fulfilled/cancelled/rejected',
-    exchange_requested_at DATETIME COMMENT '申请兑换时间',
-    exchange_approved_by BIGINT COMMENT '批准者ID',
-    exchange_approved_at DATETIME COMMENT '批准时间',
-    points_deducted_at DATETIME COMMENT '扣积分时间',
-    fulfilled_by BIGINT COMMENT '兑现者ID',
-    fulfilled_at DATETIME COMMENT '兑现时间',
-    child_confirmed_at DATETIME COMMENT '孩子确认收货时间',
-    rejected_by BIGINT COMMENT '拒绝者ID',
-    rejected_at DATETIME COMMENT '拒绝时间',
-    reject_reason TEXT COMMENT '拒绝原因',
-    reject_count INT DEFAULT 0 COMMENT '被拒绝次数',
-    cancelled_by BIGINT COMMENT '取消者ID',
-    cancelled_at DATETIME COMMENT '取消时间',
-    cancel_reason TEXT COMMENT '取消原因',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_family_id (family_id),
-    INDEX idx_child_id (child_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心愿单表';
-
--- =============================================
--- 商品与订单表
--- =============================================
-
--- 商品表
-CREATE TABLE IF NOT EXISTS products (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    name VARCHAR(200) NOT NULL COMMENT '商品名称',
-    description TEXT COMMENT '商品描述',
-    intro TEXT COMMENT '详细介绍',
-    cover_image VARCHAR(500) COMMENT '封面图片',
-    images TEXT COMMENT '多张图片JSON',
-    price INT NOT NULL DEFAULT 0 COMMENT '价格(分)',
-    purchase_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '进价(分)',
-    stock INT NOT NULL DEFAULT 0 COMMENT '库存',
-    min_stock_alert INT DEFAULT 0 COMMENT '库存预警阈值(低于此值预警)',
-    sales_count INT NOT NULL DEFAULT 0 COMMENT '销量',
-    product_type VARCHAR(32) NOT NULL COMMENT '商品类型: activity/course/physical/digital/service',
-    growth_category VARCHAR(50) DEFAULT NULL COMMENT '成长分类',
-    vendor_id BIGINT COMMENT '供应商ID',
-    vendor_name VARCHAR(100) COMMENT '供应商名称',
-    status VARCHAR(32) NOT NULL DEFAULT 'draft' COMMENT '状态: draft/pending/approved/rejected/on_shelf/off_shelf',
-    reject_reason TEXT COMMENT '审核拒绝原因',
-    member_price INT COMMENT '会员价(分)',
-    member_eligible VARCHAR(32) DEFAULT 'none' COMMENT '会员资格: all/budget/none',
-    domain VARCHAR(32) COMMENT '五维领域: action/mind/body/wisdom/wealth',
-    dimension_weights JSON DEFAULT NULL COMMENT '五维权重百分比: {"body":0,"mind":0,"wisdom":0,"action":0,"wealth":0}',
-    profit_rate INT DEFAULT 0 COMMENT '平台利润率(千分比)',
-    sort_order INT DEFAULT 0 COMMENT '排序(值越小越靠前)',
-    points_multiplier DECIMAL(10,2) NOT NULL DEFAULT 1.00 COMMENT '平台积分倍数,1元=1积分×倍数',
-    delivery_method TINYINT DEFAULT 1 COMMENT '配送方式: 1=快递 2=自提 3=两者皆可 4=线上-可选人 5=线上-单人',
-    purchase_count_threshold INT DEFAULT 0 COMMENT '最小购买数量限制',
-    category_id BIGINT COMMENT '商品类目ID',
-    distribution_system_id BIGINT COMMENT '销售体系ID',
-    external_source VARCHAR(64) COMMENT '外部来源系统',
-    external_id VARCHAR(128) COMMENT '外部来源ID',
-    external_data TEXT COMMENT '外部来源数据JSON',
-    family_scope TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员消费过即排除, 0=仅按个人消费排除',
-    visible_roles JSON DEFAULT NULL COMMENT '可见角色: ["parent","child","teacher","admin"],NULL=全部可见',
-    min_visible_level VARCHAR(50) DEFAULT NULL COMMENT '最低可见会员级别编码(FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME,NULL=全部可见)',
-    min_discount_level VARCHAR(50) DEFAULT NULL COMMENT '享受会员价所需的最低会员级别编码(FREE/FAMILY/PREMIUM/LIFETIME,NULL=所有会员均可)',
-    contraindicated_diseases VARCHAR(255) DEFAULT NULL COMMENT '禁忌基础疾病,逗号分隔(如"慢性肾病,肝病")',
-    allergen_tags VARCHAR(255) DEFAULT NULL COMMENT '过敏原标签,逗号分隔(如"花生,小麦")',
-    drug_interaction_flags TINYINT DEFAULT 0 COMMENT '是否命中药物-食物相互作用(1=是,需对照drug_interactions表)',
-    is_recommended TINYINT(1) DEFAULT 0 COMMENT '是否推荐商品 0否 1是',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
-
--- 商品类目表(迁移创建于 DatabaseInitializer,同步到 schema.sql 保持完整快照)
-CREATE TABLE IF NOT EXISTS shop_categories (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(64) NOT NULL COMMENT '分类名称',
-    parent_id BIGINT DEFAULT 0 COMMENT '父分类ID(0=根节点)',
-    level INT DEFAULT 0 COMMENT '层级(0/1/2/3)',
-    sort INT DEFAULT 0 COMMENT '排序',
-    image VARCHAR(512) COMMENT '分类图标',
-    enabled TINYINT(1) DEFAULT 1 COMMENT '启用',
-    dimension_codes VARCHAR(128) COMMENT '维度编码(逗号分隔: body,mind,heart)',
-    product_types VARCHAR(128) COMMENT '商品类型(逗号分隔: PHYSICAL,COURSE,ASSESSMENT)',
-    min_visible_level VARCHAR(50) DEFAULT NULL COMMENT '最低可见会员级别编码(FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME,NULL=全部可见)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_parent (parent_id),
-    INDEX idx_sort (sort)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品类目';
-
--- 库存交易流水表
-CREATE TABLE IF NOT EXISTS inventory_transactions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT COMMENT '商品ID',
-    sku_id BIGINT COMMENT 'SKU ID',
-    type VARCHAR(32) COMMENT '交易类型: INBOUND/OUTBOUND/ADJUSTMENT/TRANSFER/COUNT',
-    direction TINYINT COMMENT '方向: 1=入库, -1=出库',
-    quantity INT NOT NULL COMMENT '数量',
-    before_stock INT COMMENT '操作前库存',
-    after_stock INT COMMENT '操作后库存',
-    reference_type VARCHAR(32) COMMENT '关联业务类型',
-    reference_id BIGINT COMMENT '关联业务ID',
-    operator_id BIGINT COMMENT '操作人ID',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存交易流水表';
-
--- 库存盘点记录表
-CREATE TABLE IF NOT EXISTS inventory_counting_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT COMMENT '商品ID',
-    sku_id BIGINT COMMENT 'SKU ID',
-    expected_stock INT COMMENT '账面库存',
-    actual_stock INT COMMENT '实际库存',
-    difference INT COMMENT '差异',
-    status VARCHAR(16) DEFAULT 'pending' COMMENT '状态',
-    operator_id BIGINT COMMENT '盘点人ID',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存盘点记录表';
-
--- 库存入库单表
-CREATE TABLE IF NOT EXISTS inventory_inbound_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    order_no VARCHAR(64) NOT NULL COMMENT '入库单号',
-    supplier_id BIGINT COMMENT '供应商ID',
-    supplier_name VARCHAR(100) COMMENT '供应商名称',
-    status VARCHAR(16) DEFAULT 'pending' COMMENT '状态',
-    total_items INT DEFAULT 0 COMMENT '商品种类数',
-    total_amount INT DEFAULT 0 COMMENT '入库总金额(分)',
-    inbound_date DATE COMMENT '入库日期',
-    operator_id BIGINT COMMENT '操作人ID',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存入库单表';
-
--- 库存入库明细表
-CREATE TABLE IF NOT EXISTS inventory_inbound_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    inbound_order_id BIGINT NOT NULL COMMENT '入库单ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    sku_id BIGINT COMMENT 'SKU ID',
-    quantity INT NOT NULL COMMENT '入库数量',
-    purchase_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '入库单价(分)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库存入库明细表';
-
--- 商品规格SKU表(product_skus)
-CREATE TABLE IF NOT EXISTS product_skus (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    product_id BIGINT NOT NULL COMMENT '所属商品ID',
-    sku_code VARCHAR(64) COMMENT 'SKU编码',
-    specs JSON COMMENT '规格选项JSON: [{"name":"颜色","value":"红色"},{"name":"尺码","value":"M"}]',
-    price INT DEFAULT 0 COMMENT 'SKU价格(分)',
-    purchase_price DECIMAL(10,2) DEFAULT 0.00 COMMENT '进价(分)',
-    stock INT DEFAULT 0 COMMENT '库存数量',
-    min_stock_alert INT DEFAULT 0 COMMENT '库存预警阈值(低于此值预警)',
-    min_quantity INT DEFAULT 1 COMMENT '最小购买数量限制',
-    original_price INT DEFAULT 0 COMMENT '原价(分)',
-    image VARCHAR(500) COMMENT 'SKU图片',
-    enabled TINYINT DEFAULT 1 COMMENT '是否启用: 0=禁用 1=启用',
-    linked_product_id BIGINT COMMENT '关联商品ID,null=Legacy SKU',
-    label VARCHAR(100) COMMENT '自定义显示标签,null=使用linked_product.name',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_product_id (product_id),
-    INDEX idx_sku_code (sku_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品规格SKU表';
-
--- 商品订单表
-CREATE TABLE IF NOT EXISTS product_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    order_no VARCHAR(64) NOT NULL UNIQUE COMMENT '订单编号',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    product_name VARCHAR(200) COMMENT '商品名称',
-    product_type VARCHAR(32) COMMENT '商品类型',
-    buyer_id BIGINT NOT NULL COMMENT '购买者ID',
-    family_id BIGINT COMMENT '家庭ID',
-    quantity INT NOT NULL DEFAULT 1 COMMENT '数量',
-    unit_price INT NOT NULL COMMENT '单价(分)',
-    total_amount INT NOT NULL COMMENT '总金额(分)',
-    status VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/paid/completed/cancelled/refunded',
-    payment_method VARCHAR(32) COMMENT '支付方式: wechat/points/membership',
-    remark TEXT COMMENT '备注',
-    paid_at DATETIME COMMENT '支付时间',
-    supply_system_id BIGINT COMMENT '所属供应商体系ID',
-    supplier_id BIGINT COMMENT '收款供应商用户ID',
-    supply_commission INT COMMENT '销售佣金(分)',
-    points_used INT DEFAULT 0 COMMENT '使用的积分数量',
-    points_cost INT DEFAULT 0 COMMENT '积分抵扣金额(分)',
-    money_amount INT DEFAULT 0 COMMENT '现金支付金额(分)',
-    consignee_id BIGINT COMMENT '收货人ID',
-    pickup_location_id BIGINT COMMENT '自取地点ID',
-    pickup_location_snapshot TEXT COMMENT '自取地点快照(JSON)',
-    time_slot_id BIGINT COMMENT '所选时间段ID',
-    time_slot_snapshot TEXT COMMENT '时间段快照(JSON)',
-    service_person_id BIGINT COMMENT '所选服务者ID(deliveryMethod=4)',
-    service_person_snapshot TEXT COMMENT '服务者快照(JSON)',
-    fulfill_status VARCHAR(32) DEFAULT 'pending' COMMENT '履约状态: pending/confirmed_by_vendor/received_by_user/completed',
-    fulfill_confirmed_at DATETIME COMMENT '供应商确认时间',
-    received_at DATETIME COMMENT '用户确认收货时间',
-purchase_info TEXT COMMENT '购买信息JSON: {id_card, hand_signature, ...}',
-provision_status VARCHAR(32) COMMENT '活动provision状态: unprovisioned(待审核)/provisioned(已发货)/signed_in(已签到)/completed(已完成)/cancelled(审核拒绝)',
-auditor_id BIGINT COMMENT '审核人ID',
-audited_at DATETIME COMMENT '审核时间',
-audit_reason TEXT COMMENT '审核拒绝原因',
-    shipping_cost INT DEFAULT 0 COMMENT '快递费(分)',
-    tracking_number VARCHAR(100) DEFAULT NULL COMMENT '快递单号',
-    express_company VARCHAR(100) DEFAULT NULL COMMENT '快递公司',
-    delivery_method INT DEFAULT NULL COMMENT '配送方式: 1=快递 2=自提 3=两者皆可 4=线上-可选人 5=线上-单人',
-    pickup_code VARCHAR(64) DEFAULT NULL COMMENT '自提码',
-    confirm_time DATETIME DEFAULT NULL COMMENT '确认收货时间',
-    refund_status INT DEFAULT NULL COMMENT '退款状态',
-    refund_reason VARCHAR(255) DEFAULT NULL COMMENT '退款原因',
-    refund_amount INT DEFAULT NULL COMMENT '退款金额(分)',
-    refund_time DATETIME DEFAULT NULL COMMENT '退款时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_buyer_id (buyer_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_product_id (product_id),
-    INDEX idx_status (status),
-    INDEX idx_supply_system_id (supply_system_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品订单表';
-
--- 商品自取地点表
-CREATE TABLE IF NOT EXISTS product_pickup_locations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    product_id BIGINT NOT NULL COMMENT '所属商品ID',
-    name VARCHAR(100) NOT NULL COMMENT '地点名称',
-    address VARCHAR(500) NOT NULL COMMENT '详细地址',
-    longitude DECIMAL(10,7) COMMENT '经度',
-    latitude DECIMAL(10,7) COMMENT '纬度',
-    contact_name VARCHAR(50) COMMENT '联系人',
-    contact_phone VARCHAR(20) COMMENT '联系电话',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    enabled TINYINT DEFAULT 1 COMMENT '启用: 0/1',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product_id (product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品自取地点';
-
--- 自取时间段模板表
-CREATE TABLE IF NOT EXISTS product_pickup_time_slots (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    location_id BIGINT NOT NULL COMMENT '所属地点ID',
-    start_time TIME NOT NULL COMMENT '开始时间 HH:MM',
-    end_time TIME NOT NULL COMMENT '结束时间 HH:MM',
-    weekday TINYINT COMMENT '周几(1-7), null=按具体日期',
-    specific_date DATE COMMENT '具体日期, null=按周循环',
-    max_capacity INT DEFAULT 1 COMMENT '该时段最大接待人数',
-    booked_count INT DEFAULT 0 COMMENT '已预订数',
-    enabled TINYINT DEFAULT 1,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_location_id (location_id),
-    INDEX idx_specific_date (specific_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自取时间段模板';
-
--- 商品线上服务者表
-CREATE TABLE IF NOT EXISTS product_service_persons (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    product_id BIGINT NOT NULL COMMENT '所属商品ID',
-    user_id BIGINT NOT NULL COMMENT '服务者用户ID(关联users表)',
-    name VARCHAR(50) NOT NULL COMMENT '展示名称',
-    title VARCHAR(100) COMMENT '头衔(如高级营养师)',
-    intro TEXT COMMENT '个人介绍',
-    avatar VARCHAR(500) COMMENT '头像URL',
-    price INT NOT NULL COMMENT '该人专属价格(分)',
-    original_price INT COMMENT '原价(分)',
-    sort_order INT DEFAULT 0,
-    enabled TINYINT DEFAULT 1,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product_id (product_id),
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品线上服务者';
-
--- 服务者可预约时间段表
-CREATE TABLE IF NOT EXISTS product_service_person_slots (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    person_id BIGINT NOT NULL COMMENT '所属服务者ID',
-    start_time DATETIME NOT NULL COMMENT '开始时间',
-    end_time DATETIME NOT NULL COMMENT '结束时间',
-    max_capacity INT DEFAULT 1 COMMENT '容量',
-    booked_count INT DEFAULT 0 COMMENT '已预订数',
-    enabled TINYINT DEFAULT 1,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_person_id (person_id),
-    INDEX idx_start_time (start_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务者可预约时间段';
-
--- 单人线上服务时间段表
-CREATE TABLE IF NOT EXISTS product_online_slots (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    product_id BIGINT NOT NULL COMMENT '所属商品ID',
-    start_time DATETIME NOT NULL COMMENT '开始时间',
-    end_time DATETIME NOT NULL COMMENT '结束时间',
-    max_capacity INT DEFAULT 1 COMMENT '容量',
-    booked_count INT DEFAULT 0 COMMENT '已预订数',
-    enabled TINYINT DEFAULT 1,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product_id (product_id),
-    INDEX idx_start_time (start_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='单人线上服务时间段';
-
--- =============================================
--- 系统配置与内容表
--- =============================================
-
--- 系统配置表
-CREATE TABLE IF NOT EXISTS sys_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    config_key VARCHAR(64) NOT NULL UNIQUE COMMENT '配置键',
-    config_value TEXT COMMENT '配置值',
-    description TEXT COMMENT '配置说明',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统配置表';
-
--- 内容区块配置表
-CREATE TABLE IF NOT EXISTS content_sections (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    page_key VARCHAR(50) NOT NULL COMMENT '页面标识',
-    section_key VARCHAR(50) NOT NULL COMMENT '区块标识',
-    title VARCHAR(100) COMMENT '区块标题',
-    allowed_roles VARCHAR(255) DEFAULT '["anonymous"]' COMMENT '允许查看的角色JSON数组',
-    sort_order INT DEFAULT 0 COMMENT '显示顺序',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/inactive',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='内容区块配置表';
-
--- 文章分类表
-CREATE TABLE IF NOT EXISTS article_categories (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    name VARCHAR(50) NOT NULL COMMENT '分类名',
-    icon VARCHAR(20) DEFAULT '' COMMENT '图标emoji',
-    color VARCHAR(20) DEFAULT '#5B9BD5' COMMENT '标识色',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status TINYINT DEFAULT 1 COMMENT '状态:1启用/0禁用'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类表';
-
--- 文章表
-CREATE TABLE IF NOT EXISTS articles (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键 ID',
-    category_id BIGINT DEFAULT 0 COMMENT '所属分类 ID',
-    title VARCHAR(200) NOT NULL UNIQUE COMMENT '标题(唯一,防止重复发布)',
-    summary TEXT COMMENT '摘要',
-    cover_image VARCHAR(500) DEFAULT '' COMMENT '封面图 URL',
-    content LONGTEXT COMMENT '富文本内容',
-    tags VARCHAR(200) DEFAULT '' COMMENT '标签 JSON 数组',
-    author VARCHAR(100) DEFAULT '浠艾福' COMMENT '作者',
-    read_time INT DEFAULT 0 COMMENT '预计阅读分钟数',
-    article_type VARCHAR(20) DEFAULT 'normal' COMMENT '文章类型:normal(普通)/premium(优质)/original(原创)',
-    word_count INT DEFAULT 0 COMMENT '文章字数',
-    related_dimensions VARCHAR(100) DEFAULT '' COMMENT '关联五维 JSON 数组',
-    dimension_weights JSON DEFAULT NULL COMMENT '五维权重百分比: {"body":0,"mind":0,"wisdom":0,"action":0,"wealth":0}',
-    visibility VARCHAR(20) DEFAULT 'public' COMMENT '浏览权限:public/login/private',
-    visible_to TEXT COMMENT '私密指定人群 JSON',
-    status VARCHAR(20) DEFAULT 'draft' COMMENT '状态:draft/published/archived',
-    growth_category VARCHAR(50) DEFAULT NULL COMMENT '成长分类',
-    is_featured TINYINT DEFAULT 0 COMMENT '是否精选:1 精选/0 普通',
-    sort_order INT NOT NULL DEFAULT 0 COMMENT '推荐排序值(越小越靠前)',
-    published_at DATETIME DEFAULT NULL COMMENT '发布时间',
-    view_count INT DEFAULT 0 COMMENT '浏览次数',
-    created_by BIGINT DEFAULT 0 COMMENT '发布人 adminID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章表';
-
--- Article audit fields (for user-generated content)
-ALTER TABLE articles
-    ADD COLUMN author_type VARCHAR(20) DEFAULT 'admin' COMMENT '作者类型:admin/parent/child' AFTER created_by,
-    ADD COLUMN audit_status VARCHAR(20) DEFAULT 'approved' COMMENT '审核状态:approved/pending/rejected' AFTER status,
-    ADD COLUMN audit_reason TEXT COMMENT '驳回原因' AFTER audit_status,
-    ADD COLUMN auditor_id BIGINT DEFAULT 0 COMMENT '审核人 ID' AFTER audit_reason,
-    ADD COLUMN audited_at DATETIME COMMENT '审核时间' AFTER auditor_id;
-
--- =============================================
--- 五维能量系统表
--- =============================================
-
--- 能量维度定义表
-CREATE TABLE IF NOT EXISTS energy_dimension (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    code VARCHAR(16) NOT NULL UNIQUE COMMENT '维度代码: body/mind/wisdom/action/wealth',
-    name VARCHAR(20) NOT NULL COMMENT '维度名称: 身/心/智/行/富',
-    icon VARCHAR(16) COMMENT '图标emoji',
-    element VARCHAR(10) COMMENT '五行元素: 土/火/金/木/水',
-    sort_order INT DEFAULT 0 COMMENT '显示顺序',
-    status TINYINT DEFAULT 1 COMMENT '状态:1启用/0禁用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量维度定义表';
-
--- 服务-维度比例配置表
-CREATE TABLE IF NOT EXISTS energy_source_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    source_type VARCHAR(32) NOT NULL COMMENT '来源类型: task/activity/course/product/consultation',
-    source_id BIGINT NOT NULL COMMENT '来源业务表ID',
-    source_name VARCHAR(200) COMMENT '冗余名称',
-    dimension_id BIGINT NOT NULL COMMENT '维度ID',
-    ratio INT NOT NULL COMMENT '占比(基点,6000=60%)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_source (source_type, source_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务-维度比例配置表';
-
--- 能量流水表
-CREATE TABLE IF NOT EXISTS energy_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    child_id BIGINT NOT NULL COMMENT '孩子ID',
-    dimension_id BIGINT NOT NULL COMMENT '维度ID',
-    amount INT NOT NULL COMMENT '变动量(正=获得,负=消耗)',
-    balance_after INT NOT NULL COMMENT '变动后余额',
-    source_type VARCHAR(32) COMMENT '来源类型: task/product/medical_report/daily_record',
-    source_id BIGINT COMMENT '来源ID',
-    ref_id BIGINT COMMENT '关联旧流水ID(覆盖时标记)',
-    expires_at DATETIME COMMENT '过期时间(空=永不过期)',
-    description TEXT COMMENT '描述',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_child_dim (child_id, dimension_id),
-    INDEX idx_created (created_at),
-    INDEX idx_source (source_type, source_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量流水表';
-
--- 维度余额表
-CREATE TABLE IF NOT EXISTS energy_balance (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    child_id BIGINT NOT NULL COMMENT '孩子ID',
-    dimension_id BIGINT NOT NULL COMMENT '维度ID',
-    balance INT DEFAULT 0 COMMENT '当前能量值(可为负)',
-    total_earned INT DEFAULT 0 COMMENT '累计获得',
-    total_spent INT DEFAULT 0 COMMENT '累计消耗',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_child_dim (child_id, dimension_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='维度余额表';
-
--- =============================================
--- 佣金系统表
--- =============================================
-
--- 佣金记录表
-CREATE TABLE IF NOT EXISTS commission_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    order_id BIGINT NOT NULL COMMENT '订单ID',
-    order_type VARCHAR(32) NOT NULL COMMENT '订单类型: membership/product/assessment/package',
-    referrer_id BIGINT NOT NULL COMMENT '推荐人ID',
-    buyer_id BIGINT NOT NULL COMMENT '购买人ID',
-    commission_type VARCHAR(16) NOT NULL COMMENT '佣金类型: member/profit',
-    level INT DEFAULT 1 COMMENT '佣金层级: 1=直接推荐, 2=间接推荐',
-    order_amount INT NOT NULL COMMENT '订单金额(分)',
-    profit_rate INT DEFAULT 0 COMMENT '利润率(千分比,如235=23.5%)',
-    commission_amount INT NOT NULL COMMENT '佣金金额(分)',
-    status VARCHAR(16) NOT NULL DEFAULT 'settled' COMMENT '状态: pending/settled',
-    remark TEXT DEFAULT NULL COMMENT '备注',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    settled_at DATETIME DEFAULT NULL COMMENT '结算时间',
-    withdrawn_at DATETIME DEFAULT NULL COMMENT '提现时间',
-    INDEX idx_referrer (referrer_id),
-    INDEX idx_buyer (buyer_id),
-    INDEX idx_order (order_id, order_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='佣金记录表';
-
--- 提现申请表
-CREATE TABLE IF NOT EXISTS withdrawal_requests (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    amount INT NOT NULL COMMENT '提现金额(分)',
-    account_info TEXT COMMENT '账户信息(JSON)',
-    type VARCHAR(20) DEFAULT 'platform_points' COMMENT '提现来源: platform_points(CF值) / commission(历史佣金)',
-    status VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/approved/rejected',
-    audit_by BIGINT DEFAULT NULL COMMENT '审核人ID',
-    audit_at DATETIME DEFAULT NULL COMMENT '审核时间',
-    remark TEXT DEFAULT NULL COMMENT '审核备注',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_user (user_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='提现申请表';
-
--- 会员升级记录表
-CREATE TABLE IF NOT EXISTS member_upgrade_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    from_level VARCHAR(20) NOT NULL COMMENT '升级前等级',
-    to_level VARCHAR(20) NOT NULL COMMENT '升级后等级',
-    upgrade_type VARCHAR(20) NOT NULL COMMENT '升级类型: pay/consumption/admin',
-    order_id BIGINT DEFAULT NULL COMMENT '关联支付订单ID',
-    consumption_amount BIGINT DEFAULT NULL COMMENT '触发升级的累计消费金额',
-    expire_time DATETIME DEFAULT NULL COMMENT '家庭会员到期时间',
-    approve_remark VARCHAR(500) DEFAULT NULL COMMENT '审批备注',
-    approve_status VARCHAR(20) DEFAULT 'approved' COMMENT '审批状态: approved/rejected',
-    approve_user_id BIGINT DEFAULT NULL COMMENT '审批人ID',
-    approve_time DATETIME DEFAULT NULL COMMENT '审批时间',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_user (user_id),
-    INDEX idx_order (order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员升级记录表';
-
--- =============================================
--- 规划师服务模块表
--- =============================================
-
--- 服务类型表
-CREATE TABLE IF NOT EXISTS service_types (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    name VARCHAR(100) NOT NULL COMMENT '类型名称',
-    icon VARCHAR(50) COMMENT '图标',
-    description TEXT COMMENT '描述',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务类型表';
-
--- 服务内容表
-CREATE TABLE IF NOT EXISTS service_contents (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    type_id BIGINT NOT NULL COMMENT '关联服务类型',
-    title VARCHAR(200) NOT NULL COMMENT '内容标题',
-    content TEXT COMMENT '富文本内容',
-    duration INT COMMENT '建议时长(分钟)',
-    age_range VARCHAR(50) COMMENT '适用年龄',
-    price INT COMMENT '参考价格(分)',
-    status VARCHAR(20) DEFAULT 'DRAFT' COMMENT '状态: DRAFT/ACTIVE',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务内容表';
-
--- 套餐模板表
-CREATE TABLE IF NOT EXISTS guide_package_templates (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    name VARCHAR(100) NOT NULL COMMENT '模板名称',
-    validity_months INT COMMENT '有效期(月)',
-    reference_price INT COMMENT '参考价格(分)',
-    min_price INT COMMENT '最低售价(分)',
-    description TEXT COMMENT '说明',
-    status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='套餐模板表';
-
--- 套餐模板服务项表
-CREATE TABLE IF NOT EXISTS package_template_services (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    template_id BIGINT NOT NULL COMMENT '关联模板',
-    content_id BIGINT NOT NULL COMMENT '关联服务内容',
-    quantity INT DEFAULT 1 COMMENT '数量',
-    unit VARCHAR(20) COMMENT '单位'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='套餐模板服务项表';
-
--- 成长规划师套餐表
-CREATE TABLE IF NOT EXISTS guide_packages (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    guide_id BIGINT COMMENT '成长规划师ID',
-    package_id BIGINT COMMENT '关联模板',
-    commission_rate INT COMMENT '佣金比例(基点,1000=10%)',
-    teacher_id BIGINT COMMENT '成长规划师ID(旧字段)',
-    template_id BIGINT COMMENT '关联模板(旧字段)',
-    name VARCHAR(100) NOT NULL COMMENT '套餐名称',
-    level VARCHAR(20) COMMENT '套餐等级',
-    price INT NOT NULL COMMENT '销售价格(分)',
-    validity_months INT COMMENT '有效期(月)',
-    validity_days INT DEFAULT 0 COMMENT '有效期天数',
-    description TEXT COMMENT '套餐说明',
-    status VARCHAR(20) DEFAULT 'DRAFT' COMMENT '状态: DRAFT/PUBLISHED/PAUSED',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    sales_count INT DEFAULT 0 COMMENT '销量',
-    share_code VARCHAR(50) COMMENT '分享码',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师套餐表';
-
--- 成长规划师套餐服务项表
-CREATE TABLE IF NOT EXISTS guide_package_services (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    package_id BIGINT NOT NULL COMMENT '关联套餐',
-    content_id BIGINT NOT NULL COMMENT '关联服务内容',
-    quantity INT DEFAULT 1 COMMENT '数量',
-    unit VARCHAR(20) COMMENT '单位'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师套餐服务项表';
-
--- 成长规划师订单表
-CREATE TABLE IF NOT EXISTS guide_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    order_no VARCHAR(50) NOT NULL COMMENT '订单号',
-    teacher_id BIGINT NOT NULL COMMENT '成长规划师ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    package_id BIGINT NOT NULL COMMENT '套餐ID',
-    amount INT NOT NULL COMMENT '金额(分)',
-    status VARCHAR(20) DEFAULT 'PENDING' COMMENT '状态: PENDING/PAID/COMPLETED/REFUNDED',
-    pay_time DATETIME COMMENT '支付时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_order_no (order_no)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师订单表';
-
--- 佣金明细表
-CREATE TABLE IF NOT EXISTS guide_commissions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    teacher_id BIGINT NOT NULL COMMENT '成长规划师ID',
-    order_id BIGINT NOT NULL COMMENT '订单ID',
-    amount INT NOT NULL COMMENT '佣金金额(分)',
-    rate INT COMMENT '佣金比例(基点)',
-    status VARCHAR(20) DEFAULT 'PENDING' COMMENT '状态: PENDING/COMPLETED',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='佣金明细表';
-
--- 服务记录表
-CREATE TABLE IF NOT EXISTS guide_service_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    teacher_id BIGINT NOT NULL COMMENT '成长规划师ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    order_id BIGINT COMMENT '订单ID',
-    service_content_id BIGINT NOT NULL COMMENT '服务内容ID',
-    notes TEXT COMMENT '服务记录',
-    duration INT COMMENT '服务时长(分钟)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务记录表';
-
--- 成长规划师邀请码表
-CREATE TABLE IF NOT EXISTS guide_invite_codes (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    guide_id BIGINT NOT NULL COMMENT '成长规划师用户ID',
-    code VARCHAR(50) NOT NULL UNIQUE COMMENT '邀请码',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态',
-    used_by_user_id BIGINT COMMENT '使用该邀请码的用户ID',
-    used_at DATETIME COMMENT '使用时间',
-    expire_at DATETIME COMMENT '过期时间',
-    use_count INT DEFAULT 0 COMMENT '使用次数',
-    max_use_count INT COMMENT '最大使用次数',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长规划师邀请码表';
-
--- =============================================
--- 财富维度表
--- =============================================
-
--- 财商打卡记录表
-CREATE TABLE IF NOT EXISTS finance_checkins (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT NULL COMMENT '孩子ID,家长本人打卡时为NULL',
-checkin_type VARCHAR(20) NOT NULL COMMENT '打卡类型: daily_plan/saving/expense/review',
-    checkin_date DATE NOT NULL COMMENT '记账日期',
-    type VARCHAR(10) DEFAULT 'expense' COMMENT '类型: income(收入)/expense(支出)',
-    amount INT COMMENT '金额(分,正数)',
-    category VARCHAR(50) COMMENT '收支分类',
-    note TEXT COMMENT '备注',
-    mood VARCHAR(20) COMMENT '心情',
-    earned_energy INT DEFAULT 0 COMMENT '获得的能量值',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_user_date (user_id, checkin_date),
-    INDEX idx_child (child_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='财商打卡记录表';
-
--- 保单管理表
-CREATE TABLE IF NOT EXISTS insurance_policies (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT COMMENT '关联孩子ID',
-    policy_name VARCHAR(100) NOT NULL COMMENT '保单名称',
-    insurance_company VARCHAR(100) COMMENT '保险公司',
-    policy_type VARCHAR(50) COMMENT '保单类型: medical/life/accident/education/endowment',
-    insured_person VARCHAR(50) NOT NULL COMMENT '被保人姓名',
-    premium INT COMMENT '保费(分)',
-    sum_insured INT COMMENT '保额(分)',
-    start_date DATE COMMENT '生效日期',
-    end_date DATE COMMENT '到期日期',
-    renewal_type VARCHAR(20) DEFAULT 'annual' COMMENT '续费类型: annual/monthly/single',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/expired/cancelled',
-    policy_no VARCHAR(100) COMMENT '保单号',
-    remark TEXT COMMENT '备注',
-    policy_terms TEXT COMMENT '保单原始条款(AI 解析后原样保存)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user (user_id),
-    INDEX idx_child (child_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='保单管理表';
-
--- =============================================
--- 健康检测报告模块表
--- =============================================
-
--- 健康检测报告表
-CREATE TABLE IF NOT EXISTS health_reports (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '上传者用户ID(关联users表)',
-    subject_id BIGINT COMMENT '报告主体用户ID(关联users表,为null表示未绑定)',
-    family_id BIGINT COMMENT '家庭ID',
-    report_type VARCHAR(32) NOT NULL COMMENT '报告类型: physical_exam(体检)/gut_flora(菌群检测)',
-    report_format VARCHAR(32) COMMENT '报告来源格式: beijing(北京菌群)/guhe(谷禾)',
-    report_date DATE COMMENT '报告日期',
-    overall_score INT COMMENT '健康总分(0-100)',
-    gut_health_score INT COMMENT '菌群健康分',
-    chronic_disease_score INT COMMENT '慢病控制分',
-    nutrition_score INT COMMENT '营养均衡分',
-    gut_age VARCHAR(32) COMMENT '肠道预测年龄',
-    gut_type VARCHAR(50) COMMENT '肠型',
-    file_url VARCHAR(500) COMMENT '报告文件URL',
-    file_hash VARCHAR(64) DEFAULT NULL COMMENT '文件MD5哈希,用于重复上传检测',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/archived',
-    remark TEXT COMMENT '备注',
-    proxy_uploader_id BIGINT COMMENT '代上传人ID(规划师/营养师)',
-    proxy_upload_note TEXT COMMENT '代上传备注',
-    ai_analysis TEXT COMMENT 'AI解读结果JSON',
-    shannon_index VARCHAR(32) DEFAULT NULL COMMENT '香农指数',
-    payload_json LONGTEXT COMMENT '报告完整载荷快照',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_id (user_id),
-    INDEX idx_subject_id (subject_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_report_type (report_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康检测报告表';
-
--- 健康报告查看权限表
-CREATE TABLE IF NOT EXISTS health_report_permissions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    report_id BIGINT NOT NULL COMMENT '报告ID',
-    user_id BIGINT NOT NULL COMMENT '有查看权限的用户ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    UNIQUE KEY uk_report_user (report_id, user_id),
-    INDEX idx_report_id (report_id),
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告查看权限表';
-
--- 健康指标明细表
-CREATE TABLE IF NOT EXISTS health_indicators (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    report_id BIGINT NOT NULL COMMENT '关联报告ID',
-    category VARCHAR(50) COMMENT '指标分类: 营养状况/疾病风险/肠道屏障/神经递质/...',
-    indicator_name VARCHAR(100) NOT NULL COMMENT '指标名称',
-    indicator_value VARCHAR(100) COMMENT '检测值',
-    unit VARCHAR(50) COMMENT '单位',
-    ref_range VARCHAR(200) COMMENT '参考范围',
-    status VARCHAR(100) COMMENT '评估状态: 正常/偏低/偏高/过多/注意/低风险/未检出',
-    symptoms TEXT COMMENT '症状描述',
-    sort_order INT DEFAULT 0 COMMENT '显示排序',
-    collection_date DATETIME COMMENT '指标采集日期(报告检测日期)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_report_id (report_id),
-    INDEX idx_category (category)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康指标明细表';
-
--- 健康报告上传草稿表(两阶段入库的中间态)
-CREATE TABLE IF NOT EXISTS health_report_drafts (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '上传人用户ID',
-    family_id BIGINT COMMENT '家庭ID',
-    member_id BIGINT DEFAULT NULL COMMENT '报告归属成员ID(family_members.id),A2/DAN自动采集必需',
-    report_type VARCHAR(32) NOT NULL COMMENT '报告类型: physical_exam/gut_flora/dan_a2',
-    file_url VARCHAR(500) COMMENT '上传的文件URL',
-    file_hash VARCHAR(64) DEFAULT NULL COMMENT '文件MD5哈希,用于重复上传检测',
-    original_filename VARCHAR(255) COMMENT '原始文件名',
-    payload_json MEDIUMTEXT NOT NULL COMMENT '草稿载荷JSON(含解析/手动录入的所有指标)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/confirmed/discarded',
-    parse_status VARCHAR(20) DEFAULT NULL COMMENT '异步解析状态: collecting/completed/failed(NULL=未触发异步采集)',
-    parse_method VARCHAR(32) DEFAULT NULL COMMENT '解析方式: fingerprint_script/opencode/langgraph',
-    parse_error VARCHAR(2000) DEFAULT NULL COMMENT '异步解析失败原因',
-    expire_at DATETIME COMMENT '草稿过期时间',
-    confirmed_report_id BIGINT COMMENT 'confirm阶段入库后的健康报告ID',
-    remark VARCHAR(500) DEFAULT NULL COMMENT '备注(如代上传时的说明文字)',
-    collect_validation TEXT DEFAULT NULL COMMENT '采集指标校验结果(JSON: typeId/expected/matched/pass/missing)',
-    parse_attempt INT DEFAULT 0 COMMENT '已知类型解析重试次数(指数退避,上限5分钟)',
-    next_retry_at DATETIME NULL COMMENT '下次自动重试时间(known-type 解析失败后设置)',
-    parse_started_at DATETIME NULL COMMENT '最近一次解析开始时间',
-    parse_finished_at DATETIME NULL COMMENT '最近一次解析结束时间(成功/失败)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_id (user_id),
-    INDEX idx_status_expire (status, expire_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告上传草稿表(两阶段入库中间态)';
-
--- 健康报告修改留痕表
-CREATE TABLE IF NOT EXISTS health_report_edit_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    report_id BIGINT NOT NULL,
-    user_id BIGINT,
-    report_type VARCHAR(32),
-    action VARCHAR(20) COMMENT 'create/edit',
-    before_payload LONGTEXT,
-    after_payload LONGTEXT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_report_id (report_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告修改留痕';
-
--- 健康报告跨家庭转移申请表(同一份报告被不同家庭上传时的归属转移审批)
-CREATE TABLE IF NOT EXISTS report_transfer_requests (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    report_id BIGINT NOT NULL COMMENT '报告ID(health_reports.id)',
-    from_family_id BIGINT NOT NULL COMMENT '原归属家庭ID(需同意方)',
-    to_family_id BIGINT NOT NULL COMMENT '申请转入家庭ID(申请方)',
-    requester_user_id BIGINT NOT NULL COMMENT '申请人用户ID(users.id)',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending=待同意 approved=已同意 denied=已拒绝',
-    handled_by BIGINT DEFAULT NULL COMMENT '处理人用户ID',
-    handled_at DATETIME DEFAULT NULL COMMENT '处理时间',
-    remark VARCHAR(200) DEFAULT NULL COMMENT '备注(拒绝原因)',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_report_id (report_id),
-    INDEX idx_from_family_status (from_family_id, status),
-    INDEX idx_to_family_status (to_family_id, status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康报告跨家庭转移申请';
-
--- 菌群检测专项数据表(针对 gut_flora 类型报告)
-CREATE TABLE IF NOT EXISTS health_gut_flora (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键 ID',
-    report_id BIGINT NOT NULL COMMENT '关联报告 ID',
-    bacteria_name VARCHAR(100) NULL COMMENT '菌种名称',
-    bacteria_value VARCHAR(50) COMMENT '菌种丰度值',
-    normal_range VARCHAR(100) COMMENT '正常范围',
-    status VARCHAR(50) COMMENT '状态:正常/偏低/偏高',
-    category VARCHAR(50) COMMENT '分类:core/probiotic/harmful/other/pathogen_genus/pathogen_detection/taxonomy',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    population_level VARCHAR(100) DEFAULT NULL COMMENT '处于人群%水平',
-    detection_rate VARCHAR(100) DEFAULT NULL COMMENT '%正常人有检出',
-    description TEXT COMMENT '菌种说明',
-    `level` VARCHAR(20) DEFAULT 'GENUS' COMMENT '级别:CLASS/ORDER/FAMILY/GENUS/SPECIES',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_report (report_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菌群检测专项数据(每种菌种的丰度值和评估状态)';
-
--- 教育体系配置表
-CREATE TABLE IF NOT EXISTS education_systems (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    name VARCHAR(32) NOT NULL UNIQUE COMMENT '编码(key)',
-    label VARCHAR(50) NOT NULL COMMENT '显示名称',
-    description TEXT COMMENT '描述说明',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '状态: ACTIVE/DISABLED',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教育体系配置表';
-
-INSERT INTO education_systems (name, label, description, sort_order) VALUES
-('high_school', '中专/高中', '中等教育学历', 1),
-('associate', '大专', '高等专科学历', 2),
-('bachelor', '本科', '大学本科学历', 3),
-('master', '硕士', '硕士研究生学历', 4),
-('doctor', '博士', '博士研究生学历', 5);
-
--- ===== v1.2 先天属性体系 =====
-
--- 家庭成员先天属性表
-CREATE TABLE IF NOT EXISTS family_member_attributes (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id        BIGINT       NOT NULL COMMENT '家庭成员ID(children表或users表)',
-    member_type      VARCHAR(10)  NOT NULL COMMENT '成员类型: child/parent',
-    birth_datetime   DATETIME     COMMENT '出生日期(精确到分钟,用于八字排盘)',
-    eight_characters JSON         COMMENT '八字四柱JSON',
-    wuxing_elements  JSON         COMMENT '五行星盘元素JSON',
-    zodiac           VARCHAR(16)  COMMENT '生肖: rat/ox/tiger/rabbit/dragon/snake/horse/sheep/monkey/rooster/dog/pig',
-    blood_type       VARCHAR(5)   COMMENT '血型: A/B/AB/O',
-    mind_base_score  INT DEFAULT 0 COMMENT '心维度基础分(百分位)',
-    wisdom_base_score INT DEFAULT 0 COMMENT '智维度基础分(百分位)',
-    behavior_modifier JSON        COMMENT '行为修正因子JSON',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at       DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_member (member_id, member_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员先天属性表';
-
--- 星座配置表
-CREATE TABLE IF NOT EXISTS zodiac_config (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    zodiac_code      VARCHAR(20)  NOT NULL UNIQUE COMMENT '星座代码',
-    zodiac_name      VARCHAR(10)  NOT NULL COMMENT '星座名称',
-    element          VARCHAR(10)  NOT NULL COMMENT '五行: 金木水火土',
-    start_month      INT          NOT NULL COMMENT '起始月',
-    start_day        INT          NOT NULL COMMENT '起始日',
-    end_month        INT          NOT NULL COMMENT '结束月',
-    end_day          INT          NOT NULL COMMENT '结束日',
-    mind_base        INT DEFAULT 0 COMMENT '心先天基础分(百分位)',
-    wisdom_base      INT DEFAULT 0 COMMENT '智先天基础分(百分位)',
-    body_modifier    INT DEFAULT 0 COMMENT '身修正系数(千分比)',
-    action_modifier  INT DEFAULT 0 COMMENT '行修正系数(千分比)',
-    wealth_modifier  INT DEFAULT 0 COMMENT '富修正系数(千分比)',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='星座配置表';
-
--- 八字配置表
-CREATE TABLE IF NOT EXISTS bazi_config (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    stem_or_branch   VARCHAR(10)  NOT NULL COMMENT '天干或地支',
-    type             VARCHAR(10)  NOT NULL COMMENT '类型: stem/branch',
-    element          VARCHAR(10)  NOT NULL COMMENT '五行: 金木水火土',
-    yin_yang         VARCHAR(5)   COMMENT '阴阳: yin/yang',
-    mind_base        INT DEFAULT 0 COMMENT '心先天基础分(百分位)',
-    wisdom_base      INT DEFAULT 0 COMMENT '智先天基础分(百分位)',
-    body_modifier    INT DEFAULT 0 COMMENT '身修正系数(千分比)',
-    action_modifier  INT DEFAULT 0 COMMENT '行修正系数(千分比)',
-    wealth_modifier  INT DEFAULT 0 COMMENT '富修正系数(千分比)',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='八字配置表(天干地支五行)';
-
--- 血型配置表
-CREATE TABLE IF NOT EXISTS blood_type_config (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    blood_type       VARCHAR(5)   NOT NULL UNIQUE COMMENT '血型: A/B/AB/O',
-    description      TEXT COMMENT '性格描述',
-    mind_base        INT DEFAULT 0 COMMENT '心先天基础分(百分位)',
-    wisdom_base      INT DEFAULT 0 COMMENT '智先天基础分(百分位)',
-    body_modifier    INT DEFAULT 0 COMMENT '身修正系数(千分比)',
-    action_modifier  INT DEFAULT 0 COMMENT '行修正系数(千分比)',
-    wealth_modifier  INT DEFAULT 0 COMMENT '富修正系数(千分比)',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='血型配置表';
-
--- =============================================
--- 活动报名 与 能量规则引擎表(v1.4)
--- =============================================
-
--- 活动报名表
-CREATE TABLE IF NOT EXISTS activity_registrations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    activity_id BIGINT NOT NULL COMMENT '活动ID',
-    child_id BIGINT COMMENT '孩子ID(手动输入报名人为空)',
-    user_id BIGINT NOT NULL COMMENT '报名人用户ID(家长)',
-    registrant_name VARCHAR(100) COMMENT '报名人姓名',
-    registrant_phone VARCHAR(20) COMMENT '报名人联系方式',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected/cancelled',
-    registered_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '报名时间',
-    approved_at DATETIME COMMENT '审核通过时间',
-    approved_by BIGINT COMMENT '审核人用户ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_activity_child (activity_id, child_id),
-    INDEX idx_activity_id (activity_id),
-    INDEX idx_child_id (child_id),
-    INDEX idx_user_id (user_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动报名表';
-
--- 能量规则表(规则引擎)
-CREATE TABLE IF NOT EXISTS energy_rule (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    rule_code VARCHAR(64) NOT NULL UNIQUE COMMENT '规则编码(唯一)',
-    rule_name VARCHAR(200) NOT NULL COMMENT '规则名称',
-    event_type VARCHAR(32) NOT NULL COMMENT '事件类型: checkin/register/complete/cancel/overdue',
-    action VARCHAR(16) NOT NULL COMMENT '动作: increase/decrease',
-    dimension_code VARCHAR(20) COMMENT '维度代码: body/mind/wisdom/action/wealth(NULL=五维均衡)',
-    amount INT COMMENT '固定变动量(基点)',
-    amount_formula VARCHAR(255) COMMENT '动态公式(如: balance*0.1)',
-    priority INT DEFAULT 0 COMMENT '优先级(数字越大越优先匹配)',
-    conditions JSON COMMENT '触发条件(JSON表达式)',
-    status TINYINT DEFAULT 1 COMMENT '状态: 1=启用 0=禁用',
-    description TEXT COMMENT '规则描述',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_event_type (event_type),
-    INDEX idx_status (status),
-    INDEX idx_priority (priority)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量规则表(规则引擎)';
-
-CREATE TABLE IF NOT EXISTS activities (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    title            VARCHAR(100) NOT NULL COMMENT '活动标题',
-    description      TEXT COMMENT '活动描述',
-    cover_image      VARCHAR(500) COMMENT '封面图片URL',
-    dimension_code   VARCHAR(20) COMMENT '维度代码: body/mind/wisdom/action/wealth',
-    dimension_weights JSON DEFAULT NULL COMMENT '五维权重百分比: {"body":0,"mind":0,"wisdom":0,"action":0,"wealth":0}',
-    activity_type    VARCHAR(20) DEFAULT 'offline' COMMENT '活动类型: offline/online/campaign',
-    status           VARCHAR(20) DEFAULT 'draft' COMMENT '状态: draft/published/ended',
-    start_time       DATETIME COMMENT '开始时间',
-    end_time         DATETIME COMMENT '结束时间',
-    location         VARCHAR(200) COMMENT '活动地点',
-    max_participants INT DEFAULT 0 COMMENT '最大参与人数',
-    current_participants INT DEFAULT 0 COMMENT '当前参与人数',
-    price INT DEFAULT 0 COMMENT '活动价格(分)',
-    member_price INT COMMENT '会员价(分)',
-    vendor_id        BIGINT COMMENT '服务商ID',
-    vendor_name      VARCHAR(100) COMMENT '服务商名称',
-    feedback_dimensions TEXT COMMENT '评价维度列表JSON',
-    family_scope TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员参与过即排除, 0=仅按个人参与排除',
-    platform_points INT DEFAULT 0 COMMENT '活动奖励CF值(0=不发)',
-    visibility VARCHAR(20) DEFAULT 'public' COMMENT '浏览权限:public/login/private',
-    visible_to TEXT COMMENT '私密指定人群JSON',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at       DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_dimension (dimension_code),
-    INDEX idx_status (status),
-    INDEX idx_start_time (start_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动表';
-
--- v1.x: 活动工作流状态扩展
-ALTER TABLE activities
-  MODIFY COLUMN status VARCHAR(20) DEFAULT 'draft'
-    COMMENT '状态:draft(草稿)/pending(待审核)/rejected(已驳回)/published(发布中)/withdrawn(已撤回)',
-  ADD COLUMN audit_status VARCHAR(20) DEFAULT NULL
-    COMMENT '审核状态:approved/pending/rejected',
-  ADD COLUMN audit_reason TEXT DEFAULT NULL
-    COMMENT '驳回原因',
-  ADD COLUMN auditor_id BIGINT DEFAULT NULL
-    COMMENT '审核人 ID',
-  ADD COLUMN audited_at DATETIME DEFAULT NULL
-    COMMENT '审核时间';
-
--- v1.x: 活动报名升级(报名截止时间+孩子/家长双收费+会员区分+创建人)
-ALTER TABLE activities
-  ADD COLUMN registration_deadline DATETIME DEFAULT NULL
-    COMMENT '报名截止时间(NULL=不限制, 默认=活动开始时间)',
-  ADD COLUMN child_fee INT DEFAULT 0
-    COMMENT '孩子·非会员价(分)',
-  ADD COLUMN child_member_fee INT DEFAULT 0
-    COMMENT '孩子·会员价(分), 0=免费',
-  ADD COLUMN parent_fee INT DEFAULT 0
-    COMMENT '家长·非会员价(分)',
-  ADD COLUMN parent_member_fee INT DEFAULT 0
-    COMMENT '家长·会员价(分), 0=免费',
-  ADD COLUMN creator_id BIGINT DEFAULT NULL
-    COMMENT '创建人userId(普通用户发布者, admin创建可为空)';
-
--- ===== v1.3 家庭成员体系 =====
-
--- 手动添加的家庭成员表(替代children表用于新成员)
-CREATE TABLE IF NOT EXISTS family_members (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id        BIGINT       NOT NULL COMMENT '所属家庭ID',
-    user_id          BIGINT       COMMENT '关联的用户ID(手机号匹配到已有用户时)',
-    nickname         VARCHAR(100) NOT NULL COMMENT '昵称',
-    phone            VARCHAR(20)  COMMENT '手机号',
-    avatar           VARCHAR(500) COMMENT '头像',
-    gender           VARCHAR(10)  COMMENT '性别: male/female',
-    birthday         DATE         COMMENT '出生日期',
-    generation INT COMMENT '辈分值(0=家庭创建者,+n=向上,-n=向下)',
-    is_spouse TINYINT(1) DEFAULT 0 COMMENT '是否配偶(同辈中)',
-    is_admin TINYINT(1) DEFAULT 0 COMMENT '是否家庭管理员: 1=管理员, 0=普通成员',
-    show_to_family INT DEFAULT 1 COMMENT '对家庭成员可见: 1=可见, 0=不可见',
-    total_points INT DEFAULT 0 COMMENT '总积分',
-    -- 孩子专属字段(原children表合并)
-    id_card VARCHAR(18) DEFAULT NULL COMMENT '身份证号(孩子)',
-    penalty_enabled TINYINT DEFAULT 1 COMMENT '是否扣减积分(0否1是)',
-    theme VARCHAR(32) DEFAULT 'default' COMMENT '主题',
-    system_points INT DEFAULT 0 COMMENT 'CF值(干预/平台奖励)',
-    streak_days INT DEFAULT 0 COMMENT '连续打卡天数',
-    last_task_date DATE COMMENT '上次任务日期',
-    focus_max_daily TINYINT DEFAULT 3 COMMENT '每日专注上限',
-    focus_remaining TINYINT DEFAULT 3 COMMENT '今日剩余专注次数',
-    focus_reset_date DATE COMMENT '专注次数重置日期',
-    -- 饮食模块扩展字段
-    is_living_together TINYINT(1) DEFAULT 1 COMMENT '是否同住(0=不同住,不出现在食谱推荐中)',
-    meal_with_breakfast_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日早餐同餐',
-    meal_with_lunch_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日午餐同餐',
-    meal_with_dinner_weekday TINYINT(1) DEFAULT 0 COMMENT '工作日晚餐同餐',
-    meal_with_breakfast_weekend TINYINT(1) DEFAULT 0 COMMENT '周末早餐同餐',
-    meal_with_lunch_weekend TINYINT(1) DEFAULT 0 COMMENT '周末午餐同餐',
-    meal_with_dinner_weekend TINYINT(1) DEFAULT 0 COMMENT '周末晚餐同餐',
-    birth_hour VARCHAR(10) DEFAULT NULL COMMENT '出生时辰',
-    birth_weight INT DEFAULT NULL COMMENT '出生体重(g)',
-    birth_place VARCHAR(255) DEFAULT NULL COMMENT '出生地',
-    is_cesarean TINYINT(1) DEFAULT 0 COMMENT '是否剖腹产: 0否 1是',
-    status VARCHAR(16) DEFAULT 'active' COMMENT '成员状态: active=正常, recycled=回收箱',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id),
-    INDEX idx_phone (phone)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员表(手动添加)';
-
--- 家庭成员双向关系表(v2: 替代relationship_type/role_override)
-CREATE TABLE IF NOT EXISTS family_relationships (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id        BIGINT       NOT NULL COMMENT '所属家庭ID',
-    from_member_id   BIGINT       NOT NULL COMMENT '关系起点成员ID',
-    to_member_id     BIGINT       NOT NULL COMMENT '关系终点成员ID',
-    generation_value INT          NOT NULL COMMENT '辈分值: -1=子女, 0=同辈, 1=父母, 2=祖父母, 3=曾祖父母',
-    relationship_key VARCHAR(50)  COMMENT '关系标签key(冗余用于显示, 如father/mother/son/daughter/spouse/sibling)',
-    trust_score        DECIMAL(5,2) DEFAULT 0 COMMENT '信任度(答卷人视角)',
-    intimacy_score     DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度(答卷人视角)',
-    communication_score DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量(答卷人视角)',
-    created_at       DATETIME     DEFAULT CURRENT_TIMESTAMP,
-    updated_at       DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_from_to (from_member_id, to_member_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_from (from_member_id),
-    INDEX idx_to (to_member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员双向关系表';
-
--- 【已废弃】relationship_types 表已删除(generation 辈分模型替代)
-
--- 用户收货地址表
-CREATE TABLE IF NOT EXISTS user_address (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    receiver_name VARCHAR(50) NOT NULL COMMENT '收货人姓名',
-    phone VARCHAR(20) NOT NULL COMMENT '收货人电话',
-    province VARCHAR(50) COMMENT '省',
-    city VARCHAR(50) COMMENT '市',
-    district VARCHAR(50) COMMENT '区',
-    street VARCHAR(200) COMMENT '详细地址',
-    is_default TINYINT DEFAULT 0 COMMENT '是否默认地址 1=是 0=否',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_is_default (is_default)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户收货地址表';
-
--- =============================================
--- 新手引导奖励表
--- =============================================
-
-CREATE TABLE IF NOT EXISTS onboarding_task (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    task_type VARCHAR(32) NOT NULL,
-    reward_points INT DEFAULT 0,
-    reward_energy INT DEFAULT 0,
-    status VARCHAR(16) DEFAULT 'PENDING',
-    completed_at DATETIME,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 成长任务配置表
--- =============================================
-
-CREATE TABLE IF NOT EXISTS growth_task (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    type VARCHAR(16) NOT NULL COMMENT 'DAILY/NEWBIE/AI_GENERATED',
-    title VARCHAR(100) NOT NULL,
-    description TEXT,
-    reward_points INT DEFAULT 0,
-    reward_energy INT DEFAULT 0,
-    target_value INT DEFAULT 1,
-    task_key VARCHAR(32) UNIQUE NOT NULL,
-    enabled TINYINT DEFAULT 1,
-    sort_order INT DEFAULT 0,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    dimension VARCHAR(20) NULL COMMENT '五维维度(body/mind/wisdom/action/wealth)',
-    source_conversation_id VARCHAR(100) NULL COMMENT '来源AI会话ID',
-    INDEX idx_type (type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长任务配置表';
-
-CREATE TABLE IF NOT EXISTS growth_task_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    task_id BIGINT NOT NULL,
-    progress INT DEFAULT 0,
-    completed TINYINT DEFAULT 0,
-    claimed TINYINT DEFAULT 0,
-    date VARCHAR(10) COMMENT 'YYYY-MM-DD for daily, empty for newbie',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_date (user_id, date),
-    INDEX idx_task_id (task_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长任务用户进度表';
-
--- =============================================
--- 优惠券配置表
--- =============================================
-
-CREATE TABLE IF NOT EXISTS coupon (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(64) NOT NULL,
-    type VARCHAR(16) DEFAULT 'FIXED',
-    value INT DEFAULT 0 COMMENT '金额 单位:分',
-    min_spend INT DEFAULT 0 COMMENT '最低消费 单位:分',
-    applicable_to VARCHAR(32) DEFAULT 'ALL',
-    valid_from DATETIME,
-    valid_until DATETIME,
-    total_count INT DEFAULT 0,
-    used_count INT DEFAULT 0,
-    discount_rate INT COMMENT '折扣券折扣率(千分比,9000=9折)',
-    product_id BIGINT COMMENT '绑定商品ID,NULL=全场通用',
-    family_id BIGINT DEFAULT NULL COMMENT '绑定家庭ID(NULL=不绑定)',
-    points_price INT DEFAULT 0 COMMENT '积分兑换价,0=不可积分兑换',
-    grant_type VARCHAR(16) COMMENT '发放规则:JOIN/PERIODIC/POPULATION,NULL=不自动发放',
-    grant_level_code VARCHAR(32) COMMENT '发放规则对应会员等级',
-    grant_period VARCHAR(16) COMMENT 'PERIODIC周期:MONTHLY/QUARTERLY',
-    grant_quantity INT DEFAULT 1 COMMENT '每次发放数量',
-    status VARCHAR(16) DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE=启用/DISABLED=停用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_valid_period (valid_from, valid_until)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券配置表';
-
-CREATE TABLE IF NOT EXISTS user_coupon (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    coupon_id BIGINT NOT NULL,
-    status VARCHAR(16) DEFAULT 'AVAILABLE',
-    received_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    used_at DATETIME,
-    order_id BIGINT,
-    INDEX idx_user_coupon (user_id, coupon_id),
-    INDEX idx_status (status),
-    INDEX idx_order_id (order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户优惠券表';
-
--- =============================================
--- 邀请里程碑表
--- =============================================
-
-CREATE TABLE IF NOT EXISTS invite_milestone (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    milestone VARCHAR(32) NOT NULL,
-    reward_points INT DEFAULT 0,
-    reward_energy INT DEFAULT 0,
-    status VARCHAR(16) DEFAULT 'PENDING',
-    achieved_at DATETIME,
-    claimed_at DATETIME,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_milestone (user_id, milestone)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='邀请里程碑表';
-
--- =============================================
--- 推广排行榜周记录表
--- =============================================
-
-CREATE TABLE IF NOT EXISTS referral_leaderboard (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    week_start VARCHAR(10) NOT NULL COMMENT '周一日期 YYYY-MM-DD',
-    referral_count INT DEFAULT 0,
-    `rank` INT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE INDEX idx_user_week (user_id, week_start),
-    INDEX idx_week_rank (week_start, referral_count DESC)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广排行榜周记录';
-
--- =============================================
--- 虚拟服务商团队(销售体系)
--- =============================================
-
-CREATE TABLE IF NOT EXISTS `distribution_systems` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `name` VARCHAR(100) NOT NULL COMMENT '团队名称',
-    `description` TEXT COMMENT '团队描述',
-    `owner_id` BIGINT COMMENT '创建人(服务商用户ID)',
-    `profit_rate` INT DEFAULT 0 COMMENT '利润分成比例(bps, 如2000=20%)',
-    `enabled` TINYINT(1) DEFAULT 1 COMMENT '是否启用',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='虚拟服务商团队(销售体系)';
-
-CREATE TABLE IF NOT EXISTS `distribution_relations` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `system_id` BIGINT NOT NULL COMMENT '所属团队ID',
-    `user_id` BIGINT NOT NULL COMMENT '服务商用户ID',
-    `parent_id` BIGINT COMMENT '上级服务商用户ID',
-    `depth` INT DEFAULT 0 COMMENT '层级深度(0=root)',
-    `invite_code` VARCHAR(64) DEFAULT NULL COMMENT '邀请码',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_system (system_id),
-    INDEX idx_user (user_id),
-    INDEX idx_parent (parent_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='团队-服务商关系(同一人在不同团队可处于不同位置)';
-
--- =============================================
--- 成长任务种子数据
--- =============================================
-
-INSERT IGNORE INTO growth_task (type, title, description, reward_points, reward_energy, target_value, task_key, sort_order) VALUES
-('DAILY', '每日签到', '完成每日签到', 20, 3, 1, 'DAILY_CHECKIN', 1),
-('DAILY', '完成任务', '完成一个任务', 30, 5, 1, 'DAILY_TASK', 2),
-('DAILY', '分享文章', '分享一篇好文给好友', 10, 2, 1, 'DAILY_SHARE', 3),
-('DAILY', 'AI对话', '与AI助手进行一次对话', 15, 3, 1, 'DAILY_AI', 4);
-
--- ========== 全域指标定义表 ==========
--- ===== v1.5 家庭文化镜:关系兼容性配置 =====
-
--- 生肖配对规则表
-CREATE TABLE IF NOT EXISTS zodiac_pairing (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    zodiac_code_1    VARCHAR(20) NOT NULL COMMENT '生肖代码1',
-    zodiac_code_2    VARCHAR(20) NOT NULL COMMENT '生肖代码2',
-    pairing_type     VARCHAR(20) NOT NULL COMMENT '配对类型: liuhe/sanhe/banhe/liuchong/xianghai/xiangxing/ping',
-    compatibility_score INT DEFAULT 50 COMMENT '兼容分 0-100',
-    description      TEXT COMMENT '配对解读',
-    advice           TEXT COMMENT '相处建议',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_zodiac_pair (zodiac_code_1, zodiac_code_2)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生肖配对规则表';
-
--- 十二生肖六合/三合/六冲种子数据
-INSERT IGNORE INTO zodiac_pairing (zodiac_code_1, zodiac_code_2, pairing_type, compatibility_score, description, advice) VALUES
-('rat', 'ox', 'liuhe', 100, '子丑六合,天生一对', '你们是最佳拍档,互相补充,默契十足'),
-('rat', 'monkey', 'sanhe', 85, '申子半合水局,默契度高', '智慧结合,创意无限,适合一起做规划'),
-('rat', 'dragon', 'sanhe', 85, '子辰半合水局,相辅相成', '一个机灵一个大气,共同成就大事'),
-('rat', 'horse', 'liuchong', 20, '子午相冲,水火不容', '价值观差异大,需要多包容理解'),
-('rat', 'tiger', 'xiangxing', 30, '寅子相刑,容易误会', '沟通方式不同,建议用行动代替言语'),
-('rat', 'rabbit', 'xiangxing', 30, '卯子相刑,互不相让', '各执己见时先冷静再沟通'),
-('rat', 'sheep', 'xianghai', 35, '子未相害,暗中较劲', '表面和谐但内心可能有竞争意识'),
-('ox', 'tiger', 'ping', 55, '牛虎平平,互敬互重', '踏实遇上冒险,可以互相学习'),
-('ox', 'rabbit', 'xianghai', 35, '丑卯相害,各怀心思', '建议开诚布公,减少猜测'),
-('ox', 'dragon', 'ping', 55, '牛龙平平,求同存异', '务实和理想主义的碰撞'),
-('ox', 'snake', 'sanhe', 85, '巳酉丑三合金局,配合默契', '务实加智慧,黄金搭档'),
-('ox', 'horse', 'xianghai', 35, '丑午相害,相处需技巧', '步调不同,需要彼此迁就'),
-('ox', 'sheep', 'liuchong', 20, '丑未相冲,针锋相对', '一个固执一个犟,需要第三方调和'),
-('tiger', 'rabbit', 'ping', 55, '虎兔平平,各有所长', '虎的魄力配兔的细腻,互补型'),
-('tiger', 'dragon', 'ping', 55, '虎龙平平,互相欣赏', '都有王者风范,但要注意谁说了算'),
-('tiger', 'snake', 'xianghai', 35, '寅巳相害,互相防备', '一个直率一个深沉,需要更多信任'),
-('tiger', 'horse', 'sanhe', 85, '寅午半合火局,一拍即合', '热情似火,志同道合的行动派'),
-('tiger', 'sheep', 'ping', 55, '虎羊平平,温柔与力量', '虎保护羊,羊温暖虎'),
-('tiger', 'monkey', 'liuchong', 20, '寅申相冲,竞争关系', '针尖对麦芒,需要在竞争中找合作'),
-('tiger', 'pig', 'liuhe', 100, '寅亥六合,情投意合', '虎猪相合,真诚相待的最佳组合'),
-('rabbit', 'dragon', 'xianghai', 35, '卯辰相害,表面和谐', '温和遇到强势,需要找到平衡'),
-('rabbit', 'snake', 'ping', 55, '兔蛇平平,温和相处', '都是内敛型,适合安静的陪伴'),
-('rabbit', 'horse', 'ping', 55, '兔马平平,一动一静', '一个爱静一个爱动,互相调剂'),
-('rabbit', 'sheep', 'sanhe', 85, '卯未半合木局,志趣相投', '文艺组合,品味相投'),
-('rabbit', 'monkey', 'xiangxing', 30, '卯申相刑,互不买账', '思维方式差异大,需要耐心'),
-('rabbit', 'rooster', 'liuchong', 20, '卯酉相冲,水火难容', '生活节奏完全不同,需要大包容'),
-('rabbit', 'dog', 'liuhe', 100, '卯戌六合,忠诚相伴', '兔狗相合,彼此忠诚的最佳关系'),
-('dragon', 'snake', 'ping', 55, '龙蛇平平,同源相惜', '都有神秘气质,惺惺相惜'),
-('dragon', 'horse', 'ping', 55, '龙马平平,各有天地', '一个在天一个在地,互不干涉'),
-('dragon', 'sheep', 'xiangxing', 30, '辰未相刑,暗中别扭', '看似无事却有暗流,多交流可化解'),
-('dragon', 'monkey', 'sanhe', 85, '申子辰三合水局,天生队友', '最佳事业组合,互相成就'),
-('dragon', 'rooster', 'liuhe', 100, '辰酉六合,珠联璧合', '龙凤配,传统的最佳搭档'),
-('dragon', 'dog', 'liuchong', 20, '辰戌相冲,正面冲突', '硬碰硬的关系,需要智慧化解'),
-('snake', 'horse', 'xiangxing', 30, '巳午相刑,热度不同', '蛇冷静马热情,温度要调和'),
-('snake', 'sheep', 'sanhe', 85, '巳酉丑三合金局,智慧搭档', '沉稳加温柔,互相信任的深层关系'),
-('snake', 'monkey', 'liuhe', 100, '巳申六合,智谋相投', '聪明人之间的默契'),
-('snake', 'rooster', 'sanhe', 85, '巳酉丑三合金局,配合无间', '细节控和完美主义者的理想组合'),
-('snake', 'pig', 'liuchong', 20, '巳亥相冲,南辕北辙', '一个深沉一个随性,需要大幅磨合'),
-('horse', 'sheep', 'liuhe', 100, '午未六合,温情相依', '马羊相合,温暖体贴的最佳关系'),
-('horse', 'monkey', 'xiangxing', 30, '午申相刑,互不理解', '行动派和思考派的碰撞'),
-('horse', 'rooster', 'xiangxing', 30, '午酉相刑,意气用事', '都容易冲动,需要一个冷静者调和'),
-('horse', 'dog', 'sanhe', 85, '寅午戌三合火局,行动搭档', '热情忠诚组合,一起行动效率高'),
-('horse', 'pig', 'liuhe', 100, '亥午暗合,心有灵犀', '一静一动却暗合,出人意料的默契'),
-('sheep', 'monkey', 'xiangxing', 30, '未申相刑,互挑毛病', '容易在小事上相互挑剔'),
-('sheep', 'rooster', 'ping', 55, '羊鸡平平,互相欣赏', '羊的细腻欣赏鸡的精致'),
-('sheep', 'dog', 'xiangxing', 30, '未戌相刑,各怀心事', '需要建立更深层的信任'),
-('sheep', 'pig', 'sanhe', 85, '亥卯未三合木局,温柔组合', '温和的三合组,舒适无压力的关系'),
-('monkey', 'rooster', 'ping', 55, '猴鸡平平,互相启发', '聪明人的相遇,火花四射'),
-('monkey', 'dog', 'xiangxing', 30, '申戌相刑,互不信任', '需要时间证明真心'),
-('monkey', 'pig', 'liuhe', 100, '申亥六合,智勇双全', '猴子机智猪包容,最佳朋友组合'),
-('rooster', 'dog', 'xiangxing', 30, '酉戌相刑,互相挑剔', '完美主义遇见忠诚卫士,互相看不惯'),
-('rooster', 'pig', 'ping', 55, '鸡猪平平,各取所需', '鸡的精明和猪的豁达互相补充'),
-('dog', 'pig', 'sanhe', 85, '寅午戌三合火局,忠诚相伴', '忠诚的守护组合,互相支持');
-
--- 血型配对表
-CREATE TABLE IF NOT EXISTS blood_type_pairing (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    blood_type_1     VARCHAR(5) NOT NULL COMMENT '血型1',
-    blood_type_2     VARCHAR(5) NOT NULL COMMENT '血型2',
-    compatibility_score INT DEFAULT 50 COMMENT '兼容分 0-100',
-    description      TEXT COMMENT '配对描述',
-    advice           TEXT COMMENT '相处建议',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_blood_pair (blood_type_1, blood_type_2)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='血型配对表';
-
-INSERT IGNORE INTO blood_type_pairing (blood_type_1, blood_type_2, compatibility_score, description, advice) VALUES
-('A', 'A', 80, '同型相吸,稳重默契', '都能理解对方的细腻敏感,但注意不要一起钻牛角尖'),
-('A', 'B', 50, '互补型,有吸引力也有摩擦', 'B型的自由奔放吸引A型,但A型的严谨可能让B型感到压力'),
-('A', 'O', 75, 'A主内O主外,搭配和谐', 'O型的大气包容A型的细致,是最常见的和谐组合'),
-('A', 'AB', 70, 'AB型善解人意,A型感到被理解', 'AB型的理性刚好平衡A型的感性'),
-('B', 'B', 75, '同型相投,自由自在', '都给彼此空间,但可能缺乏规划'),
-('B', 'O', 70, 'O型包容B型,相处轻松', 'O型的稳定给了B型安全感'),
-('B', 'AB', 65, '互相欣赏,各有天地', 'B型的创意和AB型的分析能力互补'),
-('O', 'O', 85, '强强联合,行动力爆棚', '都是行动派,但要注意不要都太强势'),
-('O', 'AB', 75, 'O型领导,AB型军师', 'O型的大方向加AB型的精细思维,无敌组合'),
-('AB', 'AB', 60, '互相理解但可能过度理性', '两个理性派,别忘了情感交流');
-
--- 生命灵数关系解读表
-CREATE TABLE IF NOT EXISTS life_number_relationship (
-    id               BIGINT AUTO_INCREMENT PRIMARY KEY,
-    relationship_number INT NOT NULL COMMENT '关系数字 1-9',
-    title            VARCHAR(100) COMMENT '关系主题',
-    description      TEXT COMMENT '关系解读',
-    advice           TEXT COMMENT '相处建议',
-    color_hex        VARCHAR(10) COMMENT '代表色',
-    created_at       DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_relationship_num (relationship_number)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生命灵数关系解读表';
-
-INSERT IGNORE INTO life_number_relationship (relationship_number, title, description, advice, color_hex) VALUES
-(1, '开创者关系', '你们在一起充满创造力和领导力,彼此激励去实现目标', '注意不要互相竞争谁说了算,明确分工才能发挥最大能量', '#FF4444'),
-(2, '合作伙伴关系', '你们是天生的搭档,善于倾听和配合,营造和谐氛围', '过于迁就对方可能会失去自我,保持适度独立才能长久', '#FF8C42'),
-(3, '创意火花关系', '在一起充满欢乐和创造力,社交圈会因为你们而扩大', '注意不要太表面化,偶尔需要深度的对话来维系情感', '#FFD700'),
-(4, '建设者关系', '你们是务实稳健的组合,能一起把想法变成现实', '生活不能只有工作和责任,记得给彼此创造惊喜和浪漫', '#10B981'),
-(5, '探险者关系', '在一起充满变化和新鲜感,喜欢一起探索未知', '变化太多可能会让关系缺乏安全感,寻找一些共同的固定仪式', '#3B82F6'),
-(6, '守护者关系', '你们的关系以关爱和责任为基础,彼此是最坚实的后盾', '付出太多可能会感到疲惫,学会接受对方的爱和照顾', '#6366F1'),
-(7, '智者关系', '在一起有深度的精神交流和思想碰撞,追求真理', '不要沉浸在各自的世界里,记得用简单的方式表达爱', '#8B5CF6'),
-(8, '成就者关系', '你们是强强联合,追求物质和事业上的共同成就', '在追求成功的同时不要忽视感情的温度,平衡事业和生活', '#F59E0B'),
-(9, '圆满者关系', '在一起有强烈的宿命感,彼此理解和支持,是灵魂伴侣', '太理想化可能会失望,接受对方的不完美才能走得更远', '#FF6B9D');
-
-CREATE TABLE IF NOT EXISTS indicator_definitions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    domain VARCHAR(50) NOT NULL COMMENT '领域: physical/mental/nutrition/behavior/social',
-    category VARCHAR(50) NOT NULL COMMENT '分类: 舌色/苔色/情绪/...',
-    code VARCHAR(50) NOT NULL UNIQUE COMMENT '编码: tongue_color/coating_color/...',
-    name VARCHAR(100) NOT NULL COMMENT '显示名: 舌体颜色/苔色/...',
-    data_type VARCHAR(20) NOT NULL DEFAULT 'enum' COMMENT '数据类型: enum/number/string',
-    options JSON COMMENT '枚举值列表: ["淡红","红","绛","青紫"] 或 null',
-    unit VARCHAR(50) COMMENT '单位',
-    ref_range VARCHAR(200) COMMENT '参考范围',
-    source_kind VARCHAR(32) COMMENT '指标来源: report_indicator/bacteria/food_index/dimension_score',
-    report_type_scope VARCHAR(32) COMMENT '适用报告类型(type_id,空=通用)',
-    value_type VARCHAR(16) COMMENT '语义类型: numeric/categorical/level',
-    good_direction VARCHAR(16) DEFAULT 'neutral' COMMENT '变化优劣方向: higher_is_better/lower_is_better/in_range_is_better/neutral',
-    dimension_code VARCHAR(16) COMMENT '关联五维(body/mind/wisdom/action/wealth,可空)',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status TINYINT DEFAULT 1 COMMENT '0=禁用 1=启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='全域指标定义';
-
--- ========== 全域指标值表 ==========
-CREATE TABLE IF NOT EXISTS indicator_values (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    source_type VARCHAR(50) NOT NULL COMMENT '来源: tongue_record/health_report/assessment',
-    source_id BIGINT NOT NULL COMMENT '来源记录ID',
-    definition_id BIGINT NOT NULL COMMENT 'FK→indicator_definitions.id',
-    value VARCHAR(200) COMMENT '值',
-    numeric_value DECIMAL(10,2) COMMENT '数值(number类型时用)',
-    remark TEXT COMMENT '备注',
-    subject_id BIGINT COMMENT '观测对象(family_members.id)',
-    family_id BIGINT COMMENT '所属家庭(family_members.family_id)',
-    report_id BIGINT COMMENT '来源报告(health_reports.id)',
-    report_date DATE COMMENT '真实报告日期(时序查询键)',
-    unit VARCHAR(32) COMMENT '观测单位',
-    status VARCHAR(32) COMMENT '观测状态快照(正常/偏高/偏低等)',
-    recorded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_source_definition (source_type, source_id, definition_id),
-    INDEX idx_source (source_type, source_id),
-    INDEX idx_definition (definition_id),
-    INDEX idx_subject_def_date (subject_id, definition_id, report_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='全域指标值';
-
--- ========== 舌诊主记录表 ==========
-CREATE TABLE IF NOT EXISTS tongue_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    child_id BIGINT COMMENT '孩子ID',
-    image_url VARCHAR(500) COMMENT '舌象图片URL',
-    overall_assessment TEXT COMMENT '总体评估',
-    status VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/confirmed',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_member (member_id, child_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='舌诊主记录';
-
--- ========== 种子数据:舌诊7项指标定义 ==========
-INSERT IGNORE INTO indicator_definitions (domain, category, code, name, data_type, options, sort_order, status) VALUES
-('physical', '舌色', 'tongue_color', '舌体颜色', 'enum', '["淡红","红","绛","青紫"]', 1, 1),
-('physical', '苔色', 'coating_color', '苔色', 'enum', '["薄白","白","黄","灰黑"]', 2, 1),
-('physical', '苔质', 'coating_texture', '苔质', 'enum', '["润","燥","滑","涩","腻"]', 3, 1),
-('physical', '裂纹', 'fissure', '裂纹程度', 'enum', '["无","轻","中","重"]', 4, 1),
-('physical', '齿痕', 'teeth_mark', '齿痕程度', 'enum', '["无","轻","中","重"]', 5, 1),
-('physical', '舌下络脉', 'sublingual_vein', '舌下络脉', 'enum', '["正常","轻","中","重"]', 6, 1),
-('physical', '体质', 'constitution', '体质辨识', 'enum', '["平和质","气虚质","阳虚质","阴虚质","湿热质","痰湿质","血瘀质","气郁质","特禀质"]', 7, 1);
-
--- =============================================
--- 活动报名 & 能量规则引擎 v1.4 - 字段扩展
--- 通过 DatabaseInitializer.java 在 ALTER 阶段执行
--- =============================================
-
--- 活动表扩展字段
-ALTER TABLE activities ADD COLUMN require_registration TINYINT DEFAULT 1 COMMENT '是否需要报名: 1=需要, 0=直接参与';
-ALTER TABLE activities ADD COLUMN require_checkin_review TINYINT DEFAULT 1 COMMENT '打卡是否需要审核: 1=需要, 0=直接通过';
-ALTER TABLE activities ADD COLUMN energy_penalty_unregistered INT DEFAULT 5 COMMENT '未报名打卡的行能量扣减值';
-
--- ============================================================
--- 新增:系统配置表(角色年龄阈值等)
--- ============================================================
-CREATE TABLE IF NOT EXISTS system_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    config_key VARCHAR(100) NOT NULL UNIQUE COMMENT '配置键',
-    config_value TEXT COMMENT '配置值',
-    description TEXT COMMENT '说明',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统配置表';
-
--- ============================================================
--- 数据迁移: children → family_members + roleOverride 变更
--- 已由 DatabaseInitializer 迁移322 落地执行(幂等,自动 DROP children 表)
--- 以下 SQL 仅为迁移逻辑存档,勿手动重复执行
--- ============================================================
-
--- 1. family_members.capability_role → role_override (已在 DDL 中 ALTER)
--- 2. relationship_types.capability_role → default_role (已在 DDL 中 ALTER)
-
--- 2. 迁移 children 数据到 family_members(匹配更新:family_members 已存在该成员记录时更新)
-UPDATE family_members fm
-INNER JOIN children c ON fm.family_id = c.family_id AND fm.nickname = c.nickname AND fm.user_id = c.user_id
-SET
-    fm.id_card = c.id_card,
-    fm.penalty_enabled = c.penalty_enabled,
-    fm.theme = c.theme,
-    fm.system_points = c.system_points,
-    fm.streak_days = c.streak_days,
-    fm.last_task_date = c.last_task_date,
-    fm.focus_max_daily = c.focus_max_daily,
-    fm.focus_remaining = c.focus_remaining,
-    fm.focus_reset_date = c.focus_reset_date,
-    fm.total_points = c.total_points,
-    fm.show_to_family = c.show_to_family,
-    fm.birthday = c.birthday,
-    fm.gender = c.gender,
-    fm.phone = c.phone,
-    fm.role_override = 'child';
-
--- 3. 迁移 children 数据到 family_members(不匹配则插入新记录)
-INSERT INTO family_members (family_id, user_id, nickname, birthday, gender, phone,
-  id_card, penalty_enabled, theme, system_points, streak_days, last_task_date,
-  focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points,
-  role_override, created_at, updated_at)
-SELECT family_id, user_id, nickname, birthday, gender, phone,
-  id_card, penalty_enabled, theme, system_points, streak_days, last_task_date,
-  focus_max_daily, focus_remaining, focus_reset_date, show_to_family, total_points,
-  'child', created_at, updated_at
-FROM children
-WHERE NOT EXISTS (
-    SELECT 1 FROM family_members fm2
-    WHERE fm2.family_id = children.family_id
-      AND fm2.nickname = children.nickname
-      AND fm2.user_id = children.user_id
-);
-
--- 4. 插入 system_config 初始数据
-INSERT INTO system_config (config_key, config_value, description) VALUES
-  ('child_age_threshold', '18', '未成年年龄分界线(岁)'),
-  ('elderly_age_threshold', '65', '老年年龄分界线(岁)')
-ON DUPLICATE KEY UPDATE config_value = VALUES(config_value);
-
--- 5. 删除 children 表(已由 DatabaseInitializer 迁移322 自动执行,勿手动重复)
--- DROP TABLE IF EXISTS children;
-
--- ============================================================
--- 购物车表
--- ============================================================
-CREATE TABLE IF NOT EXISTS cart (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    quantity INT NOT NULL DEFAULT 1 COMMENT '数量',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_product (user_id, product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车';
-
--- ============================================================
--- 供应商销售体系
--- ============================================================
-
-CREATE TABLE IF NOT EXISTS supply_system (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '体系名称/供应商名称',
-    admin_id BIGINT NOT NULL COMMENT '管理员用户ID',
-    settlement_period_days INT NOT NULL DEFAULT 30 COMMENT '账期(天)',
-    platform_profit_rate DECIMAL(5,2) NOT NULL DEFAULT 0 COMMENT '平台留利比例(%)',
-    description TEXT COMMENT '描述',
-    status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active/disabled',
-    contact_name VARCHAR(50) COMMENT '联系人',
-    contact_phone VARCHAR(20) COMMENT '联系电话',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    KEY idx_admin_id (admin_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商体系(含电商供应商)';
-
-CREATE TABLE IF NOT EXISTS supply_system_member (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    system_id BIGINT NOT NULL COMMENT '体系ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    role VARCHAR(20) NOT NULL DEFAULT 'member' COMMENT '角色: admin/member',
-    status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT '状态: active/inactive',
-    joined_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_system_user (system_id, user_id),
-    KEY idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='体系成员';
-
-CREATE TABLE IF NOT EXISTS supply_settlement (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    system_id BIGINT NOT NULL COMMENT '体系ID',
-    period_start DATE NOT NULL COMMENT '结算周期开始',
-    period_end DATE NOT NULL COMMENT '结算周期结束',
-    total_sales INT NOT NULL DEFAULT 0 COMMENT '销售总额(分)',
-    platform_profit INT NOT NULL DEFAULT 0 COMMENT '平台留利金额(分)',
-    supplier_payout INT NOT NULL DEFAULT 0 COMMENT '供应商实付(分)',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT '状态: pending/settled',
-    settled_at DATETIME COMMENT '结算时间',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    KEY idx_system_id (system_id),
-    KEY idx_period (period_start, period_end)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算记录';
-
-CREATE TABLE IF NOT EXISTS supply_settlement_detail (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    settlement_id BIGINT NOT NULL COMMENT '结算ID',
-    order_id BIGINT NOT NULL COMMENT '订单ID',
-    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
-    product_name VARCHAR(200) NOT NULL COMMENT '商品名称',
-    amount INT NOT NULL COMMENT '订单金额(分)',
-    platform_fee INT NOT NULL COMMENT '平台留利(分)',
-    supplier_id BIGINT COMMENT '收款供应商用户ID',
-    supplier_name VARCHAR(100) COMMENT '收款供应商名称',
-    payout INT NOT NULL COMMENT '供应商实付(分)',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    KEY idx_settlement_id (settlement_id),
-    KEY idx_order_id (order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='结算明细';
-
--- =============================================
--- 收货人与购买信息采集
--- =============================================
-
-CREATE TABLE IF NOT EXISTS consignees (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '所属用户ID',
-    name VARCHAR(100) NOT NULL COMMENT '收货人姓名',
-    phone VARCHAR(20) COMMENT '手机号',
-    id_card VARCHAR(20) COMMENT '身份证号',
-    hand_signature TEXT COMMENT '手签名(base64图片或URL)',
-    ethnicity VARCHAR(20) COMMENT '民族',
-    blood_type VARCHAR(20) COMMENT '血型',
-    address VARCHAR(500) COMMENT '收货地址',
-    province VARCHAR(50) DEFAULT NULL COMMENT '省份',
-    city VARCHAR(50) DEFAULT NULL COMMENT '城市',
-    district VARCHAR(50) DEFAULT NULL COMMENT '区县',
-    street VARCHAR(100) DEFAULT NULL COMMENT '详细地址',
-    is_default TINYINT(1) DEFAULT 0 COMMENT '是否默认收货人',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收货人信息(含购买所需特殊信息)';
-
-CREATE TABLE IF NOT EXISTS product_purchase_fields (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    field_key VARCHAR(50) NOT NULL COMMENT '字段标识: name/phone/id_card/hand_signature/ethnicity/blood_type',
-    field_name VARCHAR(100) NOT NULL COMMENT '显示名: 收货人姓名/手机号/身份证号/手签名/民族/血型',
-    is_required TINYINT(1) DEFAULT 1 COMMENT '是否必填 1=是 0=否',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_product_id (product_id),
-    UNIQUE KEY uk_product_field (product_id, field_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品购买信息字段配置';
-
--- AI管家会话表
-CREATE TABLE IF NOT EXISTS butler_sessions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    title VARCHAR(200) DEFAULT '新会话' COMMENT '会话标题',
-    conversation_id VARCHAR(100) COMMENT 'Dify对话ID',
-    context TEXT COMMENT '上下文信息(JSON)',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active(进行中)/archived(已归档)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_status (status),
-    INDEX idx_user_status (user_id, status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI管家会话表';
-
--- 管家服务提供商档案
-CREATE TABLE IF NOT EXISTS butler_profiles (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    tier VARCHAR(10),
-    status VARCHAR(20) DEFAULT 'pending',
-    member_count INT DEFAULT 0,
-    max_members INT DEFAULT 50,
-    annual_fee_l1 BIGINT,
-    annual_fee_l2 BIGINT,
-    description TEXT,
-    certificates TEXT,
-    reject_reason VARCHAR(500),
-    commission_rate_l1 INT DEFAULT 1000,
-    commission_rate_l2 INT DEFAULT 5000,
-    accepting TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否接受新家庭绑定: 0=停接/1=接单',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    approved_at DATETIME,
-    UNIQUE KEY uk_user_id (user_id),
-    INDEX idx_status (status),
-    INDEX idx_tier (tier)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家服务提供商档案';
-
--- 管家服务记录
-CREATE TABLE IF NOT EXISTS butler_service_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    butler_id BIGINT NOT NULL,
-    member_user_id BIGINT NOT NULL,
-    subscription_id BIGINT,
-    service_type VARCHAR(20) NOT NULL,
-    amount_p BIGINT NOT NULL,
-    platform_fee_p BIGINT DEFAULT 0,
-    butler_amount_p BIGINT DEFAULT 0,
-    member_tier VARCHAR(10),
-    `year_month` VARCHAR(7),
-    remark VARCHAR(500),
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_butler_id (butler_id),
-    INDEX idx_member_user_id (member_user_id),
-    INDEX idx_year_month (`year_month`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家服务记录';
-
--- 管家月度佣金结算单
-CREATE TABLE IF NOT EXISTS butler_commission_settlements (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    butler_id BIGINT NOT NULL,
-    `year_month` VARCHAR(7) NOT NULL,
-    member_count INT DEFAULT 0,
-    annual_base_amount_p BIGINT DEFAULT 0,
-    annual_butler_amount_p BIGINT DEFAULT 0,
-    annual_platform_amount_p BIGINT DEFAULT 0,
-    per_session_total_p BIGINT DEFAULT 0,
-    per_session_platform_total_p BIGINT DEFAULT 0,
-    per_session_butler_total_p BIGINT DEFAULT 0,
-    total_butler_amount_p BIGINT DEFAULT 0,
-    status VARCHAR(20) DEFAULT 'pending',
-    settled_at DATETIME,
-    settled_by BIGINT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_butler_month (butler_id, `year_month`),
-    INDEX idx_status (status),
-    INDEX idx_year_month (`year_month`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='管家月度佣金结算单';
-
--- 会员-管家分配记录
-CREATE TABLE IF NOT EXISTS butler_assignments (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭 ID',
-    butler_user_id BIGINT NOT NULL COMMENT '管家用户 ID',
-    subscription_id BIGINT COMMENT '关联订阅 ID',
-    level VARCHAR(10) NOT NULL COMMENT '订阅级别 L1/L2',
-    assigned_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family_assignment (family_id),
-    INDEX idx_butler_user_id (butler_user_id),
-    INDEX idx_subscription_id (subscription_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员 - 管家分配记录';
-
--- 家庭订阅记录
-CREATE TABLE IF NOT EXISTS member_subscription (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    `level` VARCHAR(10) NOT NULL DEFAULT 'L1' COMMENT 'L1=一生一世, L2=久久一生',
-    status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT 'active/expired/cancelled',
-    start_time DATETIME DEFAULT NULL COMMENT '开始时间',
-    expire_time DATETIME DEFAULT NULL COMMENT '到期时间',
-    payment_id BIGINT DEFAULT NULL COMMENT '关联订单ID',
-    auto_renew TINYINT(1) DEFAULT 0 COMMENT '自动续费(L2)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id),
-    INDEX idx_status (status),
-    INDEX idx_expire_time (expire_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭订阅记录';
-
--- 订阅订单
-CREATE TABLE IF NOT EXISTS member_subscription_order (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    `level` VARCHAR(10) NOT NULL COMMENT 'L1/L2',
-    amount INT NOT NULL COMMENT '金额(分)',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/paid/cancelled/refunded',
-    payment_type VARCHAR(20) DEFAULT NULL COMMENT '支付方式 wechat/alipay',
-    transaction_id VARCHAR(64) DEFAULT NULL COMMENT '微信支付订单号',
-    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    paid_at DATETIME DEFAULT NULL,
-    UNIQUE KEY uk_order_no (order_no),
-    INDEX idx_family_id (family_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订阅订单';
-
--- 权益使用日志
-CREATE TABLE IF NOT EXISTS subscription_benefit_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    subscription_id BIGINT NOT NULL COMMENT '订阅ID',
-    benefit_code VARCHAR(50) NOT NULL COMMENT '权益代码',
-    used_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    detail TEXT COMMENT '使用详情(JSON)',
-    INDEX idx_subscription_id (subscription_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权益使用日志';
-
--- 推广等级 R0-R4
-CREATE TABLE IF NOT EXISTS promotion_tier (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    tier VARCHAR(20) NOT NULL DEFAULT 'R0' COMMENT 'R0利他者/R1传福人/R2聚能师/R3启慧者/R4传承者',
-    total_team_size INT DEFAULT 0 COMMENT '三层累计总人数',
-    total_referral_earnings INT DEFAULT 0 COMMENT '累计推荐佣金(分)',
-    total_share_earnings INT DEFAULT 0 COMMENT '累计消费返利(分)',
-    rate_percent INT DEFAULT 0 COMMENT '当前返佣比例(%)',
-    promoted_at DATETIME DEFAULT NULL COMMENT '最近晋级时间',
-    last_change_at DATETIME DEFAULT NULL COMMENT '最后变更时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_user_id (user_id),
-    INDEX idx_tier (tier)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广等级';
-
--- 推广等级变更记录
-CREATE TABLE IF NOT EXISTS promotion_tier_change_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    old_tier VARCHAR(20) DEFAULT NULL COMMENT '变更前等级',
-    new_tier VARCHAR(20) NOT NULL COMMENT '变更后等级',
-    reason VARCHAR(50) DEFAULT NULL COMMENT 'qualify升级/demote降级/admin管理员调整',
-    changed_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广等级变更记录';
-
--- 推荐关系树(三层)
-CREATE TABLE IF NOT EXISTS referral_tree (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    parent_id BIGINT NOT NULL COMMENT '推荐人ID',
-    child_id BIGINT NOT NULL COMMENT '被推荐人ID',
-    level INT NOT NULL COMMENT '层级深度(1/2/3)',
-    path VARCHAR(255) DEFAULT NULL COMMENT 'materialized path如/1/2/3/',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_parent_child (parent_id, child_id),
-    INDEX idx_parent_id (parent_id),
-    INDEX idx_level (level)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐关系树';
-
--- 产品P点配置
-CREATE TABLE IF NOT EXISTS product_ppoint (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '产品ID',
-    ppoint INT NOT NULL DEFAULT 0 COMMENT 'P点值(平台利润分)',
-    start_date DATE DEFAULT NULL COMMENT '生效日期',
-    end_date DATE DEFAULT NULL COMMENT '失效日期',
-    created_by BIGINT DEFAULT NULL COMMENT '创建人',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_product_id (product_id),
-    INDEX idx_dates (start_date, end_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品P点配置';
-
--- 测评商品扩展信息
-CREATE TABLE IF NOT EXISTS assessment_products (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '关联products表',
-    assessment_type VARCHAR(20) NOT NULL COMMENT 'single=单包, bundle=套餐',
-    total_sessions INT NOT NULL DEFAULT 1 COMMENT '包含测评次数',
-    validity_days INT NOT NULL DEFAULT 365 COMMENT '有效期(天)',
-    guide_scope VARCHAR(50) DEFAULT 'all' COMMENT '规划师范围: all/assigned/auto',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product_id (product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评商品扩展信息';
-
--- 成长档案关联商品配置
-CREATE TABLE IF NOT EXISTS growth_archive_products (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '关联products表',
-    status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用',
-    sort_order INT DEFAULT 0 COMMENT '展示排序(升序)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_product_id (product_id),
-    KEY idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成长档案关联商品配置';
-
--- 测评额度表
-CREATE TABLE IF NOT EXISTS assessment_quotas (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    quota_no VARCHAR(32) NOT NULL COMMENT '额度编号',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    child_id BIGINT COMMENT '指定孩子ID(NULL=不限)',
-    product_order_id BIGINT NOT NULL COMMENT '来源订单ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    product_name VARCHAR(100) NOT NULL COMMENT '商品名快照',
-    total_sessions INT NOT NULL DEFAULT 1 COMMENT '总次数',
-    remaining_sessions INT NOT NULL DEFAULT 1 COMMENT '剩余次数',
-    validity_start DATETIME NOT NULL COMMENT '有效期开始',
-    validity_end DATETIME NOT NULL COMMENT '有效期截止',
-    status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT 'active/expired/used_all/cancelled',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family (family_id),
-    INDEX idx_order (product_order_id),
-    UNIQUE KEY uk_quota_no (quota_no)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评额度表';
-
--- 测评执行记录表
-CREATE TABLE IF NOT EXISTS assessment_executions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    quota_id BIGINT NOT NULL COMMENT '关联额度ID',
-    child_id BIGINT NOT NULL COMMENT '被测评孩子',
-    guide_id BIGINT COMMENT '执行规划师ID',
-    assessment_type VARCHAR(30) COMMENT '本次具体测评类型',
-    appointment_id BIGINT COMMENT '关联预约ID',
-    result_id BIGINT COMMENT '关联测评结果ID',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/in_progress/completed/cancelled',
-    scheduled_date DATETIME COMMENT '预约执行时间',
-    completed_at DATETIME COMMENT '实际完成时间',
-    notes VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_quota (quota_id),
-    INDEX idx_child (child_id),
-    INDEX idx_appointment (appointment_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评执行记录表';
-
--- 测评指导意见表(结构化存储)
-CREATE TABLE IF NOT EXISTS growth_guidances (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    result_id BIGINT NOT NULL COMMENT '关联测评结果ID',
-    dimension VARCHAR(30) NOT NULL COMMENT '维度: attention/focus/memory/logic/emotion/general',
-    score INT COMMENT '该维度得分(0-100)',
-    suggestion TEXT NOT NULL COMMENT '建议内容',
-    priority INT DEFAULT 0 COMMENT '优先级(0=普通, 1=重要, 2=紧急)',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_result (result_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评指导意见(结构化)';
-
--- 方案生成规则表
-CREATE TABLE IF NOT EXISTS assessment_plan_rules (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    dimension VARCHAR(30) NOT NULL COMMENT '测评维度: attention/focus/memory/logic/emotion',
-    score_min INT NOT NULL COMMENT '分数下限(含)',
-    score_max INT NOT NULL COMMENT '分数上限(含)',
-    template_id BIGINT NOT NULL COMMENT '关联TaskTemplatePackage ID',
-    priority INT DEFAULT 0 COMMENT '优先级',
-    is_active TINYINT(1) DEFAULT 1 COMMENT '是否启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_dimension (dimension),
-    INDEX idx_score (score_min, score_max)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='方案生成规则';
-
--- 家庭访问安全日志表
-CREATE TABLE IF NOT EXISTS family_access_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '访问方用户ID',
-    family_id BIGINT NOT NULL COMMENT '被访问的家庭ID',
-    request_uri VARCHAR(500) NOT NULL COMMENT '请求路径',
-    request_method VARCHAR(10) NOT NULL,
-    access_type VARCHAR(20) NOT NULL COMMENT 'check_type: query/path/body',
-    result VARCHAR(10) NOT NULL COMMENT 'allowed/denied/log_only',
-    client_ip VARCHAR(50),
-    user_agent VARCHAR(500),
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_time (user_id, created_at),
-    INDEX idx_family_time (family_id, created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭访问安全日志';
-
--- 五维能量分数历史记录表
-CREATE TABLE IF NOT EXISTS five_dimension_scores (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '成员ID(user或family_member)',
-    member_type VARCHAR(20) NOT NULL COMMENT '成员类型: user/member',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    dimension_code VARCHAR(20) NOT NULL COMMENT '维度编码: body/mind/wisdom/action/wealth',
-    score INT NOT NULL COMMENT '分数(0-100)',
-    assessed_at DATETIME NOT NULL COMMENT '评估时间',
-    source_type VARCHAR(50) COMMENT '来源类型: periodic/task/assessment/manual',
-    source_id BIGINT COMMENT '来源记录ID',
-    detail_json TEXT COMMENT '详细数据JSON',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_member_dim (member_id, member_type, dimension_code),
-    INDEX idx_family_time (family_id, assessed_at),
-    INDEX idx_source (source_type, source_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维能量分数历史记录';
-
--- 家庭邀请令牌表
-CREATE TABLE IF NOT EXISTS family_invitations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    token VARCHAR(64) NOT NULL UNIQUE COMMENT '邀请令牌(UUID)',
-    created_by BIGINT NOT NULL COMMENT '创建人用户ID',
-    status VARCHAR(16) DEFAULT 'active' COMMENT '状态: active/used/expired/revoked',
-    expires_at DATETIME COMMENT '过期时间',
-    max_use_count INT DEFAULT 1 COMMENT '最大使用次数',
-    used_count INT DEFAULT 0 COMMENT '已使用次数',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id),
-    INDEX idx_token (token),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭邀请令牌';
-
--- 规划师绑定家庭申请表
-CREATE TABLE IF NOT EXISTS teacher_family_binding_requests (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    teacher_id BIGINT NOT NULL COMMENT '规划师用户ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    invitation_token VARCHAR(128) COMMENT '关联邀请码/令牌',
-    status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/rejected/cancelled',
-    requested_at DATETIME COMMENT '申请时间',
-    decided_by BIGINT COMMENT '审批人用户ID',
-    decided_at DATETIME COMMENT '审批时间',
-    reject_reason VARCHAR(200) COMMENT '拒绝原因',
-    message VARCHAR(500) COMMENT '申请留言',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_teacher_family (teacher_id, family_id),
-    INDEX idx_family_status (family_id, status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规划师绑定家庭申请表';
-
--- Dify会话本地镜像表
-CREATE TABLE IF NOT EXISTS chat_conversations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    dify_conversation_id VARCHAR(64),
-    assistant_type VARCHAR(32) COMMENT 'family/nutrition/tongue',
-    title VARCHAR(200),
-    last_message_at DATETIME,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_dify_conv (dify_conversation_id),
-    INDEX idx_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Dify会话本地镜像';
-
-CREATE TABLE IF NOT EXISTS chat_messages (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    conversation_id BIGINT NOT NULL,
-    dify_message_id VARCHAR(64),
-    role VARCHAR(20) NOT NULL COMMENT 'user/assistant',
-    content TEXT NOT NULL,
-    inputs_json TEXT,
-    metadata TEXT,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_conv (conversation_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Dify消息本地镜像';
-
--- 迁移版本追踪表
-CREATE TABLE IF NOT EXISTS schema_versions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    version_code VARCHAR(64) NOT NULL UNIQUE,
-    description VARCHAR(500),
-    checksum VARCHAR(64),
-    applied_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    applied_by VARCHAR(100)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='迁移版本追踪表';
-
-
--- 待退款记录表
-CREATE TABLE IF NOT EXISTS pending_refund (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    withdrawal_request_id BIGINT COMMENT '提现申请ID',
-    amount INT NOT NULL COMMENT '退款金额(分)',
-    attempt_count INT DEFAULT 0 COMMENT '当前尝试次数',
-    max_attempts INT DEFAULT 10 COMMENT '最大重试次数',
-    next_retry_time DATETIME COMMENT '下次重试时间',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/processing/success/failed',
-    failure_reason VARCHAR(500) COMMENT '失败原因',
-    refunded_amount INT COMMENT '实际退款金额(分)',
-    refunded_at DATETIME COMMENT '退款时间',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_id (user_id),
-    INDEX idx_status (status),
-    INDEX idx_next_retry (next_retry_time),
-    INDEX idx_withdrawal_request (withdrawal_request_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='待退款记录表';
-
-
--- 家庭每日运势表(迁移 79)
-CREATE TABLE IF NOT EXISTS tianpan_daily_fortune (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    date VARCHAR(20) NOT NULL COMMENT '日期 YYYY-MM-DD',
-    lunar_date VARCHAR(50) COMMENT '农历日期',
-    day_ganzhi VARCHAR(10) COMMENT '日柱',
-    five_elements_main VARCHAR(20) COMMENT '当日五行主气',
-    five_elements_detail VARCHAR(100) COMMENT '五行详情',
-    auspicious TEXT COMMENT '宜做的事(JSON数组)',
-    inauspicious TEXT COMMENT '忌做的事(JSON数组)',
-    family_advice TEXT COMMENT '家庭建议',
-    focus_member_name VARCHAR(50) COMMENT '关注成员',
-    focus_member_tip TEXT COMMENT '成员提示',
-    wuxing_tip TEXT COMMENT '五行提示',
-    lucky_direction VARCHAR(20) COMMENT '幸运方向',
-    fortune_level VARCHAR(20) COMMENT '运势等级',
-    fortune_level_text VARCHAR(100) COMMENT '运势等级描述',
-    fortune_description TEXT COMMENT '运势描述',
-    mood_score INT DEFAULT 50 COMMENT '心情分数',
-    mood_emoji VARCHAR(10) COMMENT '心情emoji',
-    mood_text VARCHAR(50) COMMENT '心情文本',
-    weekly_tip TEXT COMMENT '每周提示',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family_date (family_id, date),
-    INDEX idx_family_id (family_id),
-    INDEX idx_date (date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭每日运势表';
-
-
--- 成员年度能量表(迁移 80)
-CREATE TABLE IF NOT EXISTS tianpan_member_annual_energy (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '成员ID',
-    year INT NOT NULL COMMENT '年份',
-    dimensions_body INT DEFAULT 0 COMMENT '身能量',
-    dimensions_mind INT DEFAULT 0 COMMENT '心能量',
-    dimensions_wisdom INT DEFAULT 0 COMMENT '智能量',
-    dimensions_action INT DEFAULT 0 COMMENT '行能量',
-    dimensions_wealth INT DEFAULT 0 COMMENT '富能量',
-    jupiter_phase VARCHAR(50) COMMENT '木星相位',
-    saturn_phase VARCHAR(50) COMMENT '土星相位',
-    highlights TEXT COMMENT '年度亮点(JSON数组)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_member_year (member_id, year),
-    INDEX idx_member_id (member_id),
-    INDEX idx_year (year)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成员年度能量表';
-
--- 维度权重表(管理端保存五维权重使用)
-CREATE TABLE IF NOT EXISTS dimension_weights (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    target_type VARCHAR(20) NOT NULL COMMENT '目标类型: activity/product/article',
-    target_id BIGINT NOT NULL COMMENT '目标ID',
-    dimension VARCHAR(20) NOT NULL COMMENT '维度: body/mind/wisdom/action/wealth',
-    weight INT DEFAULT 0 COMMENT '权重百分比',
-    enabled TINYINT(1) DEFAULT 0 COMMENT '是否启用',
-created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-INDEX idx_target (target_type, target_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='维度权重表';
-
--- 健康打卡表
-CREATE TABLE IF NOT EXISTS health_checkins (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID(家长)',
-    child_id BIGINT COMMENT '孩子ID',
-    checkin_date DATE COMMENT '打卡日期',
-    behaviors TEXT COMMENT '打卡行为JSON数组',
-    note VARCHAR(500) COMMENT '备注',
-    mood VARCHAR(20) COMMENT '心情: happy/normal/sad/angry/sick',
-    earned_energy INT DEFAULT 5 COMMENT '获得能量值',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_id (child_id),
-    INDEX idx_checkin_date (checkin_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康打卡表';
-
--- 每日健康打卡表(综合打卡:饮食/运动/睡眠/饮水/心情评分)
-CREATE TABLE IF NOT EXISTS daily_checkin (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_date DATE COMMENT '打卡日期',
-    diet_score INT COMMENT '饮食评分',
-    exercise_score INT COMMENT '运动评分',
-    sleep_score INT COMMENT '睡眠评分',
-    water_intake INT COMMENT '饮水量(ml)',
-    mood_score INT COMMENT '心情评分',
-    weight_kg DECIMAL(5,2) COMMENT '体重(kg)',
-    height_cm DECIMAL(5,2) COMMENT '身高(cm)',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日健康打卡表';
-
--- 健康打卡 - 睡眠记录
-CREATE TABLE IF NOT EXISTS sleep_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_id BIGINT COMMENT '关联打卡ID',
-    sleep_time TIME COMMENT '入睡时间',
-    wake_time TIME COMMENT '醒来时间',
-    duration_minutes INT COMMENT '总睡眠时长(分钟)',
-    deep_sleep_minutes INT COMMENT '深睡时长(分钟)',
-    light_sleep_minutes INT COMMENT '浅睡时长(分钟)',
-    rem_minutes INT COMMENT 'REM时长(分钟)',
-    quality_score INT COMMENT '睡眠质量评分1-10',
-    dream_count INT COMMENT '做梦次数',
-    remark TEXT COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='睡眠打卡记录';
-
--- 健康打卡 - 饮水记录
-CREATE TABLE IF NOT EXISTS water_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_id BIGINT COMMENT '关联打卡ID',
-    amount_ml INT COMMENT '饮水量(毫升)',
-    water_type VARCHAR(32) COMMENT '类型: plain/sparkling/tea/other',
-    drunk_at DATETIME COMMENT '饮水时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮水打卡记录';
-
--- 健康打卡 - 饮食记录
-CREATE TABLE IF NOT EXISTS health_meal_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_id BIGINT COMMENT '关联打卡ID',
-    meal_type VARCHAR(32) COMMENT '餐次: breakfast/lunch/dinner/snack',
-    food_items TEXT COMMENT '食物清单JSON',
-    total_calories INT COMMENT '总卡路里',
-    protein_g INT COMMENT '蛋白质克数',
-    fat_g INT COMMENT '脂肪克数',
-    carbs_g INT COMMENT '碳水克数',
-    fiber_g INT COMMENT '膳食纤维克数',
-    meal_time DATETIME COMMENT '用餐时间',
-    remark VARCHAR(500) COMMENT '备注',
-    photo_urls TEXT COMMENT '照片URL列表(逗号分隔)',
-    voice_url VARCHAR(500) COMMENT '语音URL',
-    voice_text TEXT COMMENT '语音转写文字',
-    record_date DATE COMMENT '用餐日期(补打时为实际用餐日,默认等于创建日)',
-    is_backfill TINYINT DEFAULT 0 COMMENT '是否补打: 1=补打(无能量值), 0=当日打卡',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id),
-    INDEX idx_meal_record_date (member_id, record_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食打卡记录';
-
--- 健康打卡 - 冥想记录
-CREATE TABLE IF NOT EXISTS health_meditation_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_id BIGINT COMMENT '关联打卡ID',
-    duration_minutes INT COMMENT '时长(分钟)',
-    type VARCHAR(32) COMMENT '类型: mindfulness/guided/breathing/body_scan',
-    mood VARCHAR(32) COMMENT '冥想后心情',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='冥想打卡记录';
-
--- 健康打卡 - 运动记录
-CREATE TABLE IF NOT EXISTS exercise_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    checkin_id BIGINT COMMENT '关联打卡ID',
-    exercise_type VARCHAR(50) COMMENT '运动类型',
-    duration_minutes INT COMMENT '时长(分钟)',
-    intensity VARCHAR(20) COMMENT '强度: low/medium/high',
-    calories_burned INT COMMENT '消耗卡路里',
-    heart_rate_avg INT COMMENT '平均心率',
-    heart_rate_max INT COMMENT '最大心率',
-    step_count INT COMMENT '微信运动步数',
-    start_time DATETIME COMMENT '开始时间',
-    end_time DATETIME COMMENT '结束时间',
-    remark TEXT COMMENT '备注',
-    photo_urls TEXT COMMENT '照片URL列表(逗号分隔)',
-    voice_url VARCHAR(500) COMMENT '语音URL',
-    voice_text TEXT COMMENT '语音转写文字',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运动打卡记录';
-
--- 电商供应商
-CREATE TABLE IF NOT EXISTS ecom_supplier (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '供应商名称',
-    contact_name VARCHAR(50) COMMENT '联系人',
-    contact_phone VARCHAR(20) COMMENT '联系电话',
-    status TINYINT DEFAULT 1 COMMENT '启用状态 1启用 0禁用',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='电商供应商';
-
--- 佣金返利配置
-CREATE TABLE IF NOT EXISTS rebate_commission_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '配置名称',
-    rate INT COMMENT '佣金比例(万分比)',
-    rate_type TINYINT DEFAULT 1 COMMENT '比例类型 1百分比 2固定金额',
-    min_amount INT COMMENT '最低金额(分)',
-    max_amount INT COMMENT '最高金额(分)',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='佣金返利配置';
-
--- DAN测评服务闭环表
-
-CREATE TABLE IF NOT EXISTS `dan_assessment_executions` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `assessment_execution_id` BIGINT NOT NULL COMMENT '执行记录ID',
-    `assessment_order_id` BIGINT NOT NULL COMMENT '订单ID',
-    `child_id` BIGINT NOT NULL COMMENT '孩子ID',
-    `family_id` BIGINT NOT NULL COMMENT '家庭ID',
-    `quota_id` BIGINT COMMENT '额度ID',
-    `appointment_id` BIGINT COMMENT '关联assessment_appointments.id',
-    `assessor_id` BIGINT NOT NULL COMMENT '测评师userId',
-    `assessor_status` ENUM('pending','completed','rejected') DEFAULT 'pending' COMMENT '测评师状态',
-    `assessor_completed_at` DATETIME COMMENT '测评师完成时间',
-    `assessor_notes` VARCHAR(200) COMMENT '测评摘要/服务备注',
-    `planner_id` BIGINT COMMENT '规划师userId',
-    `planner_status` ENUM('pending','completed','rejected') DEFAULT 'pending' COMMENT '规划师状态',
-    `planner_completed_at` DATETIME COMMENT '规划师完成时间',
-    `planner_notes` VARCHAR(200) COMMENT '规划服务备注',
-    `user_confirmed` TINYINT(1) DEFAULT 0 COMMENT '用户确认:0未确认,1已确认',
-    `user_confirmed_at` DATETIME COMMENT '用户确认时间',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    KEY `idx_assessment_execution_id` (`assessment_execution_id`),
-    KEY `idx_assessment_order_id` (`assessment_order_id`),
-    KEY `idx_assessor_id` (`assessor_id`),
-    KEY `idx_planner_id` (`planner_id`),
-    KEY `idx_child_id` (`child_id`),
-    KEY `idx_family_id` (`family_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DAN测评服务执行记录';
-
-CREATE TABLE IF NOT EXISTS `service_ratings` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `execution_id` BIGINT NOT NULL COMMENT '执行记录ID',
-    `assessment_order_id` BIGINT NOT NULL COMMENT '订单ID',
-    `user_id` BIGINT NOT NULL COMMENT '评分用户ID',
-    `assessor_id` BIGINT NOT NULL COMMENT '测评师userId',
-    `assessor_rating` TINYINT DEFAULT 0 COMMENT '测评师评分 1-5',
-    `assessor_comment` VARCHAR(500) COMMENT '评价内容',
-    `planner_id` BIGINT COMMENT '规划师userId',
-    `planner_rating` TINYINT COMMENT '规划师评分 1-5',
-    `planner_comment` VARCHAR(500) COMMENT '评价内容',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY `uniq_execution_user` (`execution_id`, `user_id`),
-    KEY `idx_assessor_id` (`assessor_id`),
-    KEY `idx_planner_id` (`planner_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务评分记录';
-
-CREATE TABLE IF NOT EXISTS `service_settlements` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `execution_id` BIGINT NOT NULL COMMENT '执行记录ID',
-    `assessment_order_id` BIGINT NOT NULL COMMENT '订单ID',
-    `provider_id` BIGINT NOT NULL COMMENT '服务提供方userId',
-    `provider_type` ENUM('assessor','planner') NOT NULL COMMENT '服务方类型',
-    `service_fee` BIGINT DEFAULT 0 COMMENT '服务费用(分)',
-    `commission_rate` INT COMMENT '佣金比例(bps)',
-    `commission_amount` BIGINT DEFAULT 0 COMMENT '结算金额(分)',
-    `status` ENUM('pending','settled','failed') DEFAULT 'pending' COMMENT '结算状态',
-    `settled_at` DATETIME COMMENT '结算时间',
-    `transaction_id` VARCHAR(100) COMMENT '转账交易ID',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    KEY `idx_execution_id` (`execution_id`),
-    KEY `idx_provider_id` (`provider_id`),
-    KEY `idx_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务结算记录';
-
--- 健康知识库 — 菌属/营养素/指标说明
-CREATE TABLE IF NOT EXISTS `health_knowledge_base` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `item_type` VARCHAR(50) NOT NULL COMMENT '类型: bacteria/nutrient/indicator/vitamin/amino_acid/disease',
-    `item_name` VARCHAR(200) NOT NULL COMMENT '项目名称(精确匹配)',
-    `category` VARCHAR(100) COMMENT '分类(如 有益菌/有害菌)',
-    `normal_range` VARCHAR(200) COMMENT '正常范围参考',
-    `description` TEXT COMMENT '详细说明',
-    `suggestion` TEXT COMMENT '相关建议',
-    `source` VARCHAR(100) COMMENT '数据来源',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY `uk_item_type_name` (`item_type`, `item_name`),
-    KEY `idx_item_type` (`item_type`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康知识库 - 菌属/营养素/指标说明';
-
--- 统一知识库 — 按模块存储JSON(12个顶层模块,DB为查询源,classpath种子兜底)
-CREATE TABLE IF NOT EXISTS `knowledge_base_section` (
-    `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
-    `module_key` VARCHAR(100) NOT NULL COMMENT '模块键(如 食物营养库/菌属功能库/报告指标分级标准)',
-    `module_name` VARCHAR(200) COMMENT '模块中文名',
-    `content` LONGTEXT COMMENT '模块内容(JSON序列化)',
-    `version` VARCHAR(50) COMMENT '数据版本(来自元数据.版本)',
-    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
-    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY `uk_module_key` (`module_key`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一知识库 - 按模块存储JSON';
--- =============================================
--- DAN报告上传独立化(拆分 PDF 报告生命周期与数值结果)
--- =============================================
-
--- DAN PDF 报告上传/解析/确认记录表
-CREATE TABLE IF NOT EXISTS dan_report_uploads (
-    id                   BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id            BIGINT       NOT NULL COMMENT '家庭ID',
-    family_member_id     BIGINT       NOT NULL COMMENT '家庭成员ID',
-    uploader_user_id     BIGINT       NOT NULL COMMENT '上传者用户ID',
-    dimension            VARCHAR(16)  NOT NULL COMMENT '维度: mind(心-A2)/wisdom(智-B4)',
-    report_type          VARCHAR(16)  COMMENT 'A2/B4 报告类型(解析后确认)',
-    file_url             VARCHAR(500) NOT NULL COMMENT 'PDF 文件URL',
-    file_id              VARCHAR(500) COMMENT '媒资文件ID或相对路径',
-    file_name            VARCHAR(200) COMMENT '原始文件名',
-    file_size            BIGINT       COMMENT '文件大小(字节)',
-    uploaded_at          DATETIME     DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
-    parsed_items         JSON         COMMENT '解析的指标项 [{code, name, value, category}]',
-    parsed_extra         JSON         COMMENT '解析的额外信息(姓名/性别/年龄/报告日期等)',
-    parsed_summary       TEXT         COMMENT '解析的总结文本',
-    parsed_suggestions   TEXT         COMMENT '解析的建议文本',
-    parser_version       VARCHAR(32)  COMMENT '解析器版本',
-    parse_status         VARCHAR(16)  DEFAULT 'pending' COMMENT 'pending/success/failed',
-    parse_error          VARCHAR(500) COMMENT '解析失败原因',
-    parsed_at            DATETIME     COMMENT '解析完成时间',
-    draft_status         VARCHAR(16)  DEFAULT 'pending' COMMENT 'pending/confirmed/discarded',
-    confirmed_at         DATETIME     COMMENT '确认时间',
-    confirmed_by         BIGINT       COMMENT '确认操作人用户ID',
-    edited_items         JSON         COMMENT '编辑后的指标项(覆盖 parsed_items)',
-    edited_extra         JSON         COMMENT '编辑后的额外信息',
-    edited_summary       TEXT         COMMENT '编辑后的总结',
-    edited_suggestions   TEXT         COMMENT '编辑后的建议',
-    edit_count           INT          DEFAULT 0 COMMENT '编辑次数',
-    linked_result_id     BIGINT       COMMENT '关联 dan_assessment_results.id',
-    created_at           DATETIME     DEFAULT CURRENT_TIMESTAMP,
-    updated_at           DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    deleted_at           DATETIME     COMMENT '软删除时间',
-    INDEX idx_family_id (family_id),
-    INDEX idx_member_id (family_member_id),
-    INDEX idx_draft_status (draft_status),
-    INDEX idx_dimension (dimension),
-    INDEX idx_parse_status (parse_status),
-    INDEX idx_linked_result (linked_result_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DAN测评PDF报告上传/解析/确认记录';
-
-CREATE TABLE IF NOT EXISTS review_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    order_id BIGINT NOT NULL COMMENT '订单ID',
-    reviewer_id BIGINT NOT NULL COMMENT '评价人ID',
-    rating INT COMMENT '总体评分',
-    review_text TEXT COMMENT '评价内容',
-    review_at DATETIME COMMENT '评价时间',
-    organization_rating INT COMMENT '活动组织评分(0-5)',
-    content_rating INT COMMENT '活动内容评分(0-5)',
-    experience_rating INT COMMENT '活动体验评分(0-5)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_order_id (order_id),
-    INDEX idx_reviewer_id (reviewer_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动订单评价表';
-
--- 微行动定义表
-CREATE TABLE IF NOT EXISTS micro_actions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    code VARCHAR(32) NOT NULL COMMENT '行动编码: DRINK_WATER, DEEP_BREATH, ...',
-    name VARCHAR(50) NOT NULL COMMENT '行动名称',
-    icon VARCHAR(10) COMMENT '图标emoji',
-    description VARCHAR(200) COMMENT '行动描述',
-    sort_order INT DEFAULT 0 COMMENT '排序号',
-    status TINYINT DEFAULT 1 COMMENT '状态: 1启用 0禁用',
-    dimension_code VARCHAR(32) COMMENT '维度code: body/wisdom/wealth/action/mind',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_code (code),
-    INDEX idx_status (status),
-    INDEX idx_dimension (dimension_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微行动定义(12个1秒健康行动)';
-
--- 微行动完成记录表
-CREATE TABLE IF NOT EXISTS micro_action_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    action_id BIGINT NOT NULL COMMENT '行动ID',
-    completed_date DATETIME NOT NULL COMMENT '完成日期',
-    earned_energy INT DEFAULT 1 COMMENT '获得能量值',
-    note VARCHAR(200) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_date (child_id, completed_date),
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微行动完成记录';
-
--- 每日反馈表(AI/预设健康反馈)
-CREATE TABLE IF NOT EXISTS daily_feedback (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    feedback_date DATETIME NOT NULL COMMENT '反馈日期',
-    feedback_type VARCHAR(20) DEFAULT 'daily' COMMENT '反馈类型: daily/weekly/milestone',
-    content VARCHAR(500) NOT NULL COMMENT 'AI生成的反馈文本',
-    milestone_event VARCHAR(100) COMMENT '关联的里程碑事件',
-    is_read TINYINT DEFAULT 0 COMMENT '是否已读: 0未读 1已读',
-    source VARCHAR(20) DEFAULT 'preset' COMMENT '来源: ai_generated / preset',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_date (child_id, feedback_date),
-    INDEX idx_feedback_type (feedback_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日健康反馈';
-
--- 健康预警记录表(P1-2 健康行为智能预警)
-CREATE TABLE IF NOT EXISTS health_alerts (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID',
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    rule_code VARCHAR(10) NOT NULL COMMENT '规则编码: R001-R006',
-    alert_text VARCHAR(200) NOT NULL COMMENT '预警文案',
-    action_suggestion VARCHAR(200) COMMENT '行动建议',
-    severity VARCHAR(10) DEFAULT 'medium' COMMENT '严重程度: high/medium/low',
-    dismissed TINYINT DEFAULT 0 COMMENT '是否已关闭: 0未关闭 1已关闭',
-    dismissed_at DATETIME COMMENT '关闭时间',
-    alert_date DATETIME NOT NULL COMMENT '预警日期',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_date (child_id, alert_date),
-    INDEX idx_rule (rule_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康预警记录';
-
--- 健康等级表(P2-1 身份重塑)
-CREATE TABLE IF NOT EXISTS health_level (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    level_num INT NOT NULL COMMENT '等级编号 1-5',
-    title VARCHAR(50) NOT NULL COMMENT '称号',
-    badge_icon VARCHAR(20) COMMENT '徽章图标',
-    min_score INT DEFAULT 0 COMMENT '所需最低健康积分',
-    max_score INT DEFAULT 99999 COMMENT '最高积分上限'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康等级定义';
-
--- 健康时间线事件表(P2-1 我的健康故事)
-CREATE TABLE IF NOT EXISTS health_timeline_event (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID',
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    event_type VARCHAR(30) NOT NULL COMMENT '事件类型: streak_7/level_2/first_report',
-    event_text VARCHAR(200) NOT NULL COMMENT '事件描述',
-    ref_id VARCHAR(50) COMMENT '关联ID',
-    event_date DATETIME NOT NULL COMMENT '事件日期',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_child_date (child_id, event_date),
-    INDEX idx_event_type (event_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康时间线事件';
-
--- 家庭挑战表(P2-2 家庭健康互动)
-CREATE TABLE IF NOT EXISTS family_challenge (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    challenge_type VARCHAR(50) NOT NULL COMMENT 'full_checkin/sports/health_week',
-    title VARCHAR(200) NOT NULL COMMENT '挑战标题',
-    description TEXT COMMENT '挑战描述',
-    duration_days INT DEFAULT 7 COMMENT '持续天数',
-    reward_points INT DEFAULT 0 COMMENT '奖励积分',
-    reward_badge VARCHAR(100) COMMENT '奖励徽章',
-    target_mode VARCHAR(20) DEFAULT 'aggregate' COMMENT '目标模式: aggregate=集体总合/all_members=全员个人目标',
-    target_value INT DEFAULT 0 COMMENT '目标值(aggregate=家庭合计值, all_members=每人目标值)',
-    start_date DATE COMMENT '开始日期',
-    end_date DATE COMMENT '结束日期',
-    status VARCHAR(20) DEFAULT 'active' COMMENT 'pending(待同意)/active(进行中)/completed(已完成)/cancelled(已取消)/not_launched(未成功发起)',
-    creator_id BIGINT COMMENT '创建者ID(NULL=系统创建)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    respond_deadline DATETIME NULL COMMENT '回复时效截止时间(超过后未回复的 pending 成员自动置为 rejected)',
-    INDEX idx_family_id (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战';
-
--- 家庭挑战进度表(P2-2 挑战进度)
-CREATE TABLE IF NOT EXISTS family_challenge_progress (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    challenge_id BIGINT NOT NULL COMMENT '挑战ID',
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    progress_value INT DEFAULT 0 COMMENT '进度值',
-    completed TINYINT(1) DEFAULT 0 COMMENT '是否完成',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_challenge_id (challenge_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战进度';
-
--- 家庭挑战参与成员表(参与机制重构:任意成员发起/可选参与/同意后开始)
-CREATE TABLE IF NOT EXISTS family_challenge_participant (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    challenge_id BIGINT NOT NULL COMMENT '挑战ID',
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    status VARCHAR(20) NOT NULL COMMENT 'pending/agreed/rejected',
-    agreed_at DATETIME NULL COMMENT '同意/拒绝时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_challenge_member (challenge_id, member_id),
-    INDEX idx_member (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战参与成员';
-
--- 方向性关系分数表(A对B ≠ B对A)
-CREATE TABLE IF NOT EXISTS family_relationship_scores (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    from_member_id BIGINT NULL COMMENT '分数持有方(A对B的行)',
-    to_member_id BIGINT NULL COMMENT '分数对象方',
-    trust_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的信任',
-    intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的亲近',
-    communication_score DECIMAL(5,2) DEFAULT 0 COMMENT 'A对B的沟通',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_from_to (from_member_id, to_member_id),
-    INDEX idx_family (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='方向性关系分数';
-
--- 家庭挑战评分配置表(后台可配置)
-CREATE TABLE IF NOT EXISTS family_challenge_score_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    action VARCHAR(20) NOT NULL COMMENT 'initiate/agree/reject',
-    score_type VARCHAR(20) NOT NULL COMMENT 'energy/trust/intimacy/communication',
-    value INT NOT NULL DEFAULT 0 COMMENT '增减值(可正可负,默认±1)',
-    enabled TINYINT DEFAULT 1,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_action_type (action, score_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭挑战评分配置';
-
--- 健康互动记录表(P2-2 点赞)
-CREATE TABLE IF NOT EXISTS health_interaction (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    from_user_id BIGINT NOT NULL COMMENT '点赞用户ID',
-    to_user_id BIGINT NOT NULL COMMENT '被赞用户ID',
-    action_type VARCHAR(50) NOT NULL COMMENT '行为类型',
-    action_id BIGINT COMMENT '关联行为记录ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_family_action (family_id, action_type, action_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康互动记录(点赞)';
-
--- 社交圈子表(social circle)
-CREATE TABLE IF NOT EXISTS social_circle (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '圈子名称',
-    type VARCHAR(50) NOT NULL COMMENT '类型: topic/activity/hobby/ability/product/health/provider',
-    match_source VARCHAR(50) COMMENT '匹配源',
-    source_id BIGINT COMMENT '匹配源ID',
-    member_count INT DEFAULT 0 COMMENT '成员数',
-    description VARCHAR(500) COMMENT '圈子描述',
-    cover_image VARCHAR(500) COMMENT '封面图URL',
-    join_condition TINYINT(1) DEFAULT 0 COMMENT '加入条件: 0=公开/1=审核/2=邀请',
-    review_required TINYINT(1) DEFAULT 0 COMMENT '是否需要审核: 0=否/1=是',
-    is_public TINYINT(1) DEFAULT 1 COMMENT '是否公开可见: 0=否/1=是',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_type (type),
-    INDEX idx_is_public (is_public)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社交圈子';
-
--- 社交圈子成员表(social circle member)
-CREATE TABLE IF NOT EXISTS social_circle_member (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL COMMENT '圈子ID',
-    member_id BIGINT NULL COMMENT '用户成员ID',
-    member_type VARCHAR(20) NOT NULL COMMENT 'parent/child',
-    status VARCHAR(20) DEFAULT 'approved' COMMENT '申请状态: pending/approved/rejected',
-    role VARCHAR(20) DEFAULT 'member' COMMENT '角色: member/admin',
-    joined_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_circle_member (circle_id, member_id),
-    INDEX idx_circle (circle_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社交圈子成员';
-
--- 社交圈子动态帖子表
-CREATE TABLE IF NOT EXISTS social_circle_post (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL COMMENT '圈子ID',
-    member_id BIGINT NULL COMMENT '发布者成员ID',
-    member_type VARCHAR(20) NOT NULL COMMENT 'parent/child',
-    type VARCHAR(50) NOT NULL COMMENT '帖子类型: checkin/diet/exercise/sleep/water/mood/text',
-    content TEXT COMMENT '文字内容',
-    checkin_id BIGINT COMMENT '关联打卡记录ID',
-    image_urls TEXT COMMENT '图片URL列表JSON',
-    like_count INT DEFAULT 0 COMMENT '点赞数',
-    comment_count INT DEFAULT 0 COMMENT '评论数',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    deleted TINYINT(1) DEFAULT 0,
-    INDEX idx_circle_time (circle_id, created_at),
-    INDEX idx_member_time (member_id, created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子动态帖子';
-
--- 社交圈子点赞表
-CREATE TABLE IF NOT EXISTS social_circle_like (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL,
-    post_id BIGINT NOT NULL COMMENT '被点赞的帖子ID',
-    member_id BIGINT NULL COMMENT '点赞成员ID',
-    member_type VARCHAR(20) NOT NULL,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_like (circle_id, post_id, member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子点赞记录';
-
--- 社交圈子评论表
-CREATE TABLE IF NOT EXISTS social_circle_comment (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL,
-    post_id BIGINT NOT NULL COMMENT '所属帖子ID',
-    parent_id BIGINT DEFAULT NULL COMMENT '回复的评论ID(NULL=一级评论)',
-    member_id BIGINT NULL COMMENT '评论者成员ID',
-    member_type VARCHAR(20) NOT NULL,
-    content TEXT NOT NULL COMMENT '评论内容',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_post_time (post_id, created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈子评论记录';
-
--- 健康圈表(P3 健康社区扩散)
-CREATE TABLE IF NOT EXISTS health_circle (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '圈名称',
-    description VARCHAR(500) COMMENT '圈描述',
-    creator_family_id BIGINT COMMENT '创建家庭ID',
-    invite_code VARCHAR(32) COMMENT '邀请码',
-    member_limit INT DEFAULT 50 COMMENT '成员上限',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/closed',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_invite_code (invite_code),
-    INDEX idx_creator (creator_family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康圈';
-
--- 健康圈成员表(P3)
-CREATE TABLE IF NOT EXISTS health_circle_member (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL COMMENT '圈ID',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    role VARCHAR(20) DEFAULT 'member' COMMENT '角色 member/admin',
-    joined_at DATETIME COMMENT '加入时间',
-    left_at DATETIME COMMENT '退出时间',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/inactive',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_circle_id (circle_id),
-    INDEX idx_family_id (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康圈成员';
-
--- 圈挑战表(P3)
-CREATE TABLE IF NOT EXISTS circle_challenge (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    circle_id BIGINT NOT NULL COMMENT '圈ID',
-    challenge_type VARCHAR(50) NOT NULL COMMENT '挑战类型 checkin/step/meditation',
-    title VARCHAR(200) NOT NULL COMMENT '挑战标题',
-    description VARCHAR(500) COMMENT '挑战描述',
-    duration_days INT DEFAULT 7 COMMENT '持续天数',
-    period VARCHAR(20) DEFAULT 'weekly' COMMENT '周期 weekly/monthly',
-    start_date DATETIME COMMENT '开始日期',
-    end_date DATETIME COMMENT '结束日期',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态 active/completed/cancelled',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_circle_id (circle_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='圈挑战';
-
--- 推广佣金记录表(P2-PROMO)
-CREATE TABLE IF NOT EXISTS family_commission (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    promoter_family_id BIGINT NOT NULL COMMENT '推广方家庭ID',
-    buyer_family_id BIGINT NOT NULL COMMENT '购买方家庭ID',
-    order_id BIGINT COMMENT '关联订单ID',
-    amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '订单金额',
-    commission_rate DECIMAL(5,2) DEFAULT 10.00 COMMENT '佣金比例%',
-    commission_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '佣金金额',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/paid/cancelled',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    paid_at DATETIME COMMENT '支付时间',
-    INDEX idx_promoter (promoter_family_id),
-    INDEX idx_buyer (buyer_family_id),
-    INDEX idx_order (order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭推广佣金记录';
-
--- 推广绑定关系表(P2-PROMO)
-CREATE TABLE IF NOT EXISTS promotion_binding (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    promoter_family_id BIGINT NOT NULL COMMENT '推广方家庭ID',
-    invitee_family_id BIGINT NOT NULL COMMENT '被邀请方家庭ID',
-    invite_code VARCHAR(32) COMMENT '使用的邀请码',
-    binding_type VARCHAR(20) DEFAULT 'direct' COMMENT 'direct/indirect',
-    status VARCHAR(20) DEFAULT 'active' COMMENT 'active/inactive',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    UNIQUE KEY uk_promoter_invitee (promoter_family_id, invitee_family_id),
-    INDEX idx_promoter (promoter_family_id),
-    INDEX idx_invitee (invitee_family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广绑定关系';
-
--- 健康维度评分表(7维健康模型)
-CREATE TABLE IF NOT EXISTS health_dimension_scores (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    dimension VARCHAR(20) NOT NULL COMMENT '维度编码: growth/sleep/vision/immunity/nutrition/gut/exercise',
-    score INT NOT NULL COMMENT '评分(0-100)',
-    percentile INT COMMENT '百分位',
-    data_source VARCHAR(20) COMMENT '数据来源: MANUAL/REPORT/PHOTO/VOICE/AVERAGE',
-    tier INT DEFAULT 3 COMMENT '数据可信度层级: 1=最高(报告) 2=中(AI分析) 3=基础(手动)',
-    raw_data TEXT COMMENT '原始数据JSON',
-    assess_date DATE COMMENT '评估日期',
-    expire_date DATE COMMENT '过期日期',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_member_dim (member_id, dimension),
-    INDEX idx_assess_date (assess_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康维度评分';
-
--- 健康数据源记录表(VOICE/PHOTO等多媒体数据源)
-CREATE TABLE IF NOT EXISTS health_data_sources (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    source_type VARCHAR(20) NOT NULL COMMENT '数据源类型: VOICE/PHOTO/REPORT/MANUAL',
-    dimension_codes VARCHAR(100) COMMENT '关联维度编码(逗号分隔)',
-    parsed_result TEXT COMMENT '解析结果JSON',
-    file_url VARCHAR(500) COMMENT '原始文件URL',
-    confidence DECIMAL(5,4) COMMENT 'AI解析置信度(0-1)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_source (member_id, source_type),
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康数据源记录';
-
--- 活动评价表
-CREATE TABLE IF NOT EXISTS activity_feedback (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    activity_id BIGINT NOT NULL COMMENT '活动ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    child_id BIGINT COMMENT '孩子ID',
-    ratings TEXT COMMENT '评分JSON: {"组织形式":5,"会场气氛":4}',
-    comment TEXT COMMENT '文字评价',
-    status TINYINT DEFAULT 0 COMMENT '状态: 0=待审核 1=已发布',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_activity_id (activity_id),
-    INDEX idx_user_id (user_id),
-    INDEX idx_child_id (child_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动评价表';
-
--- ============================================================
--- 情绪打卡记录表(迁移117)
--- ============================================================
-CREATE TABLE IF NOT EXISTS emotion_checkin (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    mood_weather VARCHAR(50) COMMENT '心情晴雨表: sunny/cloudy/rainy/stormy',
-    emotion_tags VARCHAR(200) COMMENT '情绪标签(逗号分隔)',
-    photo_url VARCHAR(500) COMMENT '配图URL',
-    note TEXT COMMENT '文字备注',
-    energy_awarded INT DEFAULT 0 COMMENT '奖励能量值',
-    checkin_date DATE COMMENT '打卡日期',
-    mood_score INT COMMENT '心情分数(1-10)',
-    emotion_type VARCHAR(50) COMMENT '情绪类型',
-    stress_level INT COMMENT '压力等级(1-10)',
-    arousal_level INT COMMENT '激活水平(1-10)',
-    energy_level INT COMMENT '精力水平(1-10)',
-    sleep_hours DECIMAL(4,1) COMMENT '睡眠时长',
-    sleep_quality INT COMMENT '睡眠质量(1-10)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_child_date (child_id, checkin_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪打卡记录';
-
--- ============================================================
--- 情绪告警表(迁移118)
--- ============================================================
-CREATE TABLE IF NOT EXISTS emotion_alert (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    child_id BIGINT NOT NULL COMMENT '家庭成员ID',
-    alert_type VARCHAR(50) NOT NULL COMMENT '告警类型: consecutive_low_mood/crisis_keyword/sharp_decline',
-    severity VARCHAR(20) NOT NULL DEFAULT 'low' COMMENT '严重级别: low/medium/high',
-    title VARCHAR(200) COMMENT '告警标题',
-    message TEXT COMMENT '告警具体描述',
-    related_checkin_id BIGINT COMMENT '关联情绪打卡ID',
-    resolved TINYINT(1) DEFAULT 0 COMMENT '是否已处理',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    resolved_at DATETIME COMMENT '处理时间',
-    INDEX idx_child (child_id),
-    INDEX idx_alert_type (alert_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪告警';
-
--- ============================================================
--- 会员等级配置表(迁移119)
--- ============================================================
-CREATE TABLE IF NOT EXISTS membership_levels (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    level_code VARCHAR(50) NOT NULL COMMENT '等级编码: FREE/PROFESSIONAL/ENTERPRISE',
-    level_name VARCHAR(100) NOT NULL COMMENT '等级名称',
-    level_desc TEXT COMMENT '等级描述',
-    price_monthly INT COMMENT '月费(分)',
-    price_quarterly INT COMMENT '季费(分)',
-    price_yearly INT COMMENT '年费(分)',
-    original_price_monthly INT COMMENT '原价-月费(分)',
-    original_price_quarterly INT COMMENT '原价-季费(分)',
-    original_price_yearly INT COMMENT '原价-年费(分)',
-    features TEXT COMMENT '功能权限列表(JSON)',
-    max_children INT DEFAULT 0 COMMENT '可添加孩子数量',
-    max_tasks_per_day INT DEFAULT 0 COMMENT '每日任务上限',
-    ai_review_enabled TINYINT(1) DEFAULT 0 COMMENT 'AI审核功能',
-    priority_support TINYINT(1) DEFAULT 0 COMMENT '优先客服',
-    teacher_consultation TINYINT(1) DEFAULT 0 COMMENT '老师咨询',
-    level_order INT DEFAULT 1 COMMENT '级别数字(越小级别越低): FREE=1 FAMILY=2 PROVIDER=3 PREMIUM=4 LIFETIME=5',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_level_code (level_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员等级配置';
-
--- ============================================================
--- 会员权益配置表(会员等级独立权益管理)
--- ============================================================
-CREATE TABLE IF NOT EXISTS membership_benefits (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    level_code VARCHAR(50) NOT NULL COMMENT '会员等级: FREE/PROFESSIONAL/ENTERPRISE',
-    benefit_code VARCHAR(50) NOT NULL COMMENT '权益编码: AI_CHAT,FAMILY_MEMBERS等',
-    benefit_name VARCHAR(100) NOT NULL COMMENT '权益名称',
-    benefit_desc VARCHAR(500) COMMENT '权益描述',
-    icon VARCHAR(50) COMMENT '图标emoji',
-    bg_color VARCHAR(20) COMMENT '背景色',
-    sort_order INT DEFAULT 0 COMMENT '排序顺序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_level_benefit (level_code, benefit_code),
-    INDEX idx_level (level_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员权益配置';
-
--- 会员权益种子数据
-INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES
-('FREE',  'NO_BENEFIT', '暂无会员权益', '开通会员解锁更多权益', '🔒', '#F3F4F6', 0),
-('FREE',  'UPGRADE_HINT', '升级会员', '开通会员享专属权益', '👑', '#FEF3C7', 99),
-('FAMILY', 'AI_CHAT', 'AI 健康顾问', '7×24 小时不限次数问答', '🤖', '#DBEAFE', 1),
-('FAMILY', 'FAMILY_MEMBERS', '家庭档案管理', '管理最多 10 位家庭成员', '👨‍👩‍👧‍👦', '#D1FAE5', 2),
-('FAMILY', 'HEALTH_PLAN', '月度健康计划', '个性化健康改善方案', '📋', '#FEF3C7', 3),
-('FAMILY', 'REPORT_READING', '报告智能解读', '体检/菌群/测评报告 AI 解读', '📊', '#FCE7F3', 4),
-('FAMILY', 'MANAGER_SERVICE', '专属健康教练服务', '认证健康教练月度随访', '👨‍🏫', '#FFEDD5', 5),
-('FAMILY', 'PRODUCT_DISCOUNT', '商品会员折扣', '全场商品 8-9 折优惠', '🛒', '#E0E7FF', 6),
-('FAMILY', 'COUPON_ACCESS', '优惠券使用权限', '可使用平台优惠券享更多优惠', '🎫', '#FEE2E2', 7),
-('PREMIUM', 'AI_CHAT', 'AI 健康顾问', '7×24 小时不限次数问答', '🤖', '#DBEAFE', 1),
-('PREMIUM', 'FAMILY_MEMBERS', '家庭档案管理', '管理最多 20 位家庭成员', '👨‍👩‍👧‍👦', '#D1FAE5', 2),
-('PREMIUM', 'HEALTH_PLAN', '月度健康计划', '个性化健康改善方案 + 定制营养建议', '📋', '#FEF3C7', 3),
-('PREMIUM', 'REPORT_READING', '报告智能解读', '体检/菌群/测评报告 AI 深度解读', '📊', '#FCE7F3', 4),
-('PREMIUM', 'MANAGER_SERVICE', '专属健康教练服务', '每周 1 次电话随访 + 在线答疑', '👨‍🏫', '#FFEDD5', 5),
-('PREMIUM', 'PRODUCT_DISCOUNT', '商品会员折扣', '全场商品 6-8 折优惠', '🛒', '#E0E7FF', 6),
-('PREMIUM', 'COUPON_ACCESS', '优惠券使用权限', '可使用平台优惠券 + 会员专属券', '🎫', '#FEE2E2', 7),
-('PREMIUM', 'PRIORITY_SUPPORT', '优先客服', '专属客服通道,快速响应', '🎧', '#EDE9FE', 8),
-('PREMIUM', 'TEACHER_CONSULT', '规划师一对一咨询', '每月 1 次成长规划师专业咨询', '👩‍🏫', '#FBCFE8', 9),
-('PREMIUM', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题 + 优先响应', '🎯', '#FEF3C7', 10),
-('FAMILY', 'GROWTH_COACH', '7X24小时成长教练', 'AI智能教练随时解答家庭教育问题', '🎯', '#FEF3C7', 10);
-
--- ============================================================
--- 家庭会员订阅表(迁移120)
--- ============================================================
-CREATE TABLE IF NOT EXISTS family_memberships (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    level_code VARCHAR(50) NOT NULL DEFAULT 'FREE' COMMENT '会员等级编码',
-    start_date DATETIME COMMENT '开始时间',
-    end_date DATETIME COMMENT '结束时间',
-    payment_method VARCHAR(50) COMMENT '支付方式: wechat/alipay/card',
-    payment_status VARCHAR(20) DEFAULT 'pending' COMMENT '支付状态: pending/paid/expired/refunded',
-    order_no VARCHAR(100) COMMENT '订单号',
-    transaction_id VARCHAR(200) COMMENT '交易流水号',
-    amount INT COMMENT '支付金额(分)',
-    auto_renew TINYINT(1) DEFAULT 0 COMMENT '自动续费',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id),
-    INDEX idx_end_date (end_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭会员订阅';
-
--- ============================================================
--- 分享事件表(迁移121)
--- ============================================================
-CREATE TABLE IF NOT EXISTS share_events (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '分享用户ID',
-    target_type VARCHAR(50) NOT NULL COMMENT '分享目标类型: article/growth/product',
-    target_id BIGINT NOT NULL COMMENT '分享目标ID',
-    share_channel VARCHAR(50) COMMENT '分享渠道: wechat/timeline/qq/url',
-    share_title VARCHAR(200) COMMENT '分享标题',
-    share_url VARCHAR(500) COMMENT '分享URL',
-    click_count INT DEFAULT 0 COMMENT '点击次数',
-    read_count INT DEFAULT 0 COMMENT '阅读次数',
-    reward_points INT DEFAULT 0 COMMENT '奖励积分',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/expired',
-    expires_at DATETIME COMMENT '过期时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user (user_id),
-    INDEX idx_target (target_type, target_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享事件';
-
--- ============================================================
--- 分享阅读记录表(迁移122)
--- ============================================================
-CREATE TABLE IF NOT EXISTS share_reads (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    share_event_id BIGINT NOT NULL COMMENT '分享事件ID',
-    reader_id BIGINT COMMENT '阅读者用户ID',
-    reader_ip VARCHAR(50) COMMENT '阅读者IP',
-    read_duration INT COMMENT '阅读时长(秒)',
-    read_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '阅读时间',
-    INDEX idx_share_event (share_event_id),
-    INDEX idx_reader (reader_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='分享阅读记录';
-
--- ============================================================
--- 饮食推荐指数表(迁移123)
--- ============================================================
-CREATE TABLE IF NOT EXISTS food_recommend_idx (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    food_id BIGINT NOT NULL COMMENT '食材ID',
-    food_name VARCHAR(100) COMMENT '食材名称',
-    index_score INT COMMENT '推荐指数(0-100)',
-    health_report_id BIGINT COMMENT '关联健康报告ID',
-    calculated_at DATETIME COMMENT '计算时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user (user_id),
-    INDEX idx_food (food_id),
-    INDEX idx_report (health_report_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食推荐指数';
-
--- 报告食材适宜度
-CREATE TABLE IF NOT EXISTS report_food_suitability (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    report_id BIGINT NOT NULL COMMENT '健康报告ID',
-    food_id BIGINT COMMENT '食材ID',
-    food_name VARCHAR(100) NOT NULL COMMENT '食材名称',
-    category VARCHAR(50) COMMENT '分类',
-    score INT NOT NULL COMMENT '适宜度评分',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_report (report_id),
-    INDEX idx_food (food_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告食材适宜度';
-
--- ============================================================
--- 家庭共餐选中食材表(持久化共餐场景食材选择)
--- ============================================================
-CREATE TABLE IF NOT EXISTS diet_family_selected_ingredients (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    food_id BIGINT NOT NULL COMMENT '食材ID',
-    food_name VARCHAR(100) COMMENT '食材名称',
-    score INT COMMENT '推荐分',
-    reason VARCHAR(255) COMMENT '推荐理由',
-    category VARCHAR(50) COMMENT '分类',
-    calories_per_100g INT COMMENT '每100克卡路里',
-    cooking_level TINYINT COMMENT '烹饪难度(1=快手,2=中等,3=耗时)',
-    nutrition_score INT COMMENT '营养密度分(0-100)',
-    balance_reason VARCHAR(255) COMMENT '均衡化推荐理由',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family_food (family_id, food_id),
-    INDEX idx_family (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭共餐选中食材';
-
--- ============================================================
--- 积分兑换商品表(迁移124)
--- ============================================================
-CREATE TABLE IF NOT EXISTS points_exchange_products (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(200) NOT NULL COMMENT '商品名称',
-    description TEXT COMMENT '商品描述',
-    cover_image VARCHAR(500) COMMENT '封面图片',
-    points_price INT NOT NULL COMMENT '积分价格',
-    stock INT DEFAULT 0 COMMENT '库存',
-    product_type VARCHAR(50) COMMENT '商品类型',
-    category VARCHAR(50) COMMENT '分类',
-    expiry_days INT COMMENT '有效期(天)',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/disabled',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_status (status),
-    INDEX idx_category (category)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换商品';
-
--- ============================================================
--- 积分兑换记录表(迁移125)
--- ============================================================
-CREATE TABLE IF NOT EXISTS points_exchange_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID',
-    child_id BIGINT COMMENT '孩子ID',
-    family_member_id BIGINT COMMENT '家庭成员ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    product_name VARCHAR(200) COMMENT '商品名称快照',
-    points_cost INT NOT NULL COMMENT '消耗积分',
-    quantity INT DEFAULT 1 COMMENT '数量',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/cancelled',
-    redeem_code VARCHAR(100) COMMENT '兑换码',
-    expired_at DATETIME COMMENT '过期时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user (user_id),
-    INDEX idx_product (product_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='积分兑换记录';
-
--- 文章阅读记录表
-CREATE TABLE IF NOT EXISTS article_reading_records (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  article_id BIGINT DEFAULT NULL COMMENT '文章ID',
-  user_id BIGINT COMMENT '用户ID',
-  child_id BIGINT NOT NULL COMMENT '孩子ID',
-  content VARCHAR(500) COMMENT '阅读内容摘要',
-  duration_seconds INT DEFAULT 0 COMMENT '阅读时长(秒)',
-  task_id BIGINT DEFAULT NULL COMMENT '关联的任务ID',
-  reading_completed TINYINT DEFAULT 0 COMMENT '是否已阅读达标(达到最低时长阈值)',
-  read_at DATETIME COMMENT '阅读时间',
-  updated_at DATETIME DEFAULT NULL COMMENT '更新时间',
-  created_at DATETIME,
-  INDEX idx_child_id (child_id),
-  INDEX idx_read_at (read_at),
-  INDEX idx_article_child_date (article_id, child_id, read_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章阅读记录表';
-
--- 文章答题记录表
-CREATE TABLE IF NOT EXISTS article_quiz_records (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  article_id BIGINT DEFAULT NULL COMMENT '文章ID',
-  user_id BIGINT DEFAULT NULL COMMENT '用户ID',
-  member_id BIGINT DEFAULT NULL COMMENT '家庭成员ID(作答人)',
-  questions TEXT COMMENT '题目快照JSON(含正确答案与维度)',
-  answers TEXT COMMENT '用户作答JSON(含每题所选选项),作答前为NULL',
-  score INT DEFAULT 0 COMMENT '答对题数',
-  total_questions INT DEFAULT 0 COMMENT '题目总数',
-  cf_earned INT DEFAULT 0 COMMENT '发放的CF值',
-  energy_earned INT DEFAULT 0 COMMENT '发放的能量值',
-  created_at DATETIME,
-  updated_at DATETIME,
-  INDEX idx_member (member_id),
-  INDEX idx_article (article_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章答题记录表';
-
--- ============================================================
--- 统一报告汇总表(report_summary)
--- ============================================================
-CREATE TABLE IF NOT EXISTS report_summary (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-  report_type VARCHAR(32) NOT NULL COMMENT '报告类型',
-  source_table VARCHAR(32) NOT NULL COMMENT '来源表',
-  source_id BIGINT NOT NULL COMMENT '来源表记录ID',
-  user_id BIGINT NOT NULL COMMENT '创建者用户ID',
-  family_id BIGINT COMMENT '家庭ID',
-  subject_id BIGINT COMMENT '报告主体ID',
-  subject_name VARCHAR(50) COMMENT '报告主体名称',
-  title VARCHAR(200) COMMENT '报告标题',
-  summary TEXT COMMENT '摘要',
-  file_url VARCHAR(500) COMMENT '文件URL',
-  file_size BIGINT COMMENT '文件大小',
-  file_name VARCHAR(200) COMMENT '文件名',
-  has_file TINYINT DEFAULT 0 COMMENT '是否有文件',
-  overall_score INT COMMENT '综合评分',
-  report_date DATE COMMENT '报告日期',
-  status VARCHAR(20) COMMENT '状态',
-  detail_route VARCHAR(100) COMMENT '详情页路由',
-  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  INDEX idx_user_id (user_id),
-  INDEX idx_family_id (family_id),
-  INDEX idx_subject_id (subject_id),
-  INDEX idx_report_type (report_type),
-  INDEX idx_report_date (report_date),
-  INDEX idx_status (status),
-  UNIQUE KEY uk_source (source_table, source_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='统一报告汇总表';
--- report_summary 表已由 DatabaseInitializer 迁移创建
-
--- category_ppoint: 品类P点比例配置(P点体系)
-CREATE TABLE IF NOT EXISTS category_ppoint (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    category_id BIGINT NOT NULL COMMENT '商品类目ID',
-    ratio INT DEFAULT 0 COMMENT 'P点比例(千分比)',
-    start_date DATETIME COMMENT '生效日期',
-    end_date DATETIME COMMENT '失效日期(null=永不过期)',
-    created_by BIGINT COMMENT '创建人',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_category_id (category_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='品类P点比例配置';
-
--- commission_dist_log: P点分润记录(P点体系)
-CREATE TABLE IF NOT EXISTS commission_dist_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    buyer_id BIGINT NOT NULL COMMENT '买家用户ID',
-    order_id BIGINT COMMENT '订单ID',
-    product_id BIGINT COMMENT '商品ID',
-    source_ppoint INT DEFAULT 0 COMMENT '本次产生的原始P点数量',
-    level1_user_id BIGINT COMMENT '一级推荐人用户ID',
-    level1_ppoint INT DEFAULT 0 COMMENT '一级推荐人获得P点',
-    level1_wealth_percent INT DEFAULT 0 COMMENT '一级推荐人当时财富等级(profitSharePercent)',
-    level2_user_id BIGINT COMMENT '二级推荐人用户ID',
-    level2_ppoint INT DEFAULT 0 COMMENT '二级推荐人获得P点',
-    level2_wealth_percent INT DEFAULT 0 COMMENT '二级推荐人当时财富等级(profitSharePercent)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/completed/failed',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_buyer (buyer_id),
-    INDEX idx_order (order_id),
-    INDEX idx_level1 (level1_user_id),
-    INDEX idx_level2 (level2_user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='P点分润记录';
-
--- 会员订单表
-CREATE TABLE IF NOT EXISTS payment_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    order_no VARCHAR(64) NOT NULL COMMENT '订单号',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    level_code VARCHAR(50) DEFAULT 'FREE' COMMENT '会员等级编码',
-    payment_type VARCHAR(20) DEFAULT 'yearly' COMMENT '支付类型: yearly/monthly/trial',
-    period VARCHAR(20) DEFAULT 'yearly' COMMENT '订阅周期: monthly/quarterly/yearly',
-    amount INT COMMENT '支付金额(分)',
-    user_coupon_id BIGINT COMMENT '使用的用户优惠券ID',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/paid/expired',
-    group_no VARCHAR(64) COMMENT '拆单组号(同一拆单组共享)',
-    period_no INT DEFAULT 1 COMMENT '期数序号(1开始)',
-    pay_method VARCHAR(20) COMMENT '支付方式',
-    transaction_id VARCHAR(200) COMMENT '交易流水号',
-    paid_at DATETIME COMMENT '支付时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_order_no (order_no),
-    INDEX idx_family_id (family_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员支付订单';
-
--- 能量行为配置表(可配置每种行为的能量发放规则)
-CREATE TABLE IF NOT EXISTS energy_behavior_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    behavior_code VARCHAR(32) NOT NULL COMMENT '行为编码: task_complete/game_finish/...',
-    behavior_name VARCHAR(50) NOT NULL COMMENT '行为名称',
-    description VARCHAR(200) COMMENT '行为描述',
-    default_amount INT DEFAULT 5 COMMENT '默认能量值',
-    amount_source VARCHAR(32) DEFAULT 'fixed' COMMENT '能量值来源: fixed(固定)/points(跟随积分)/order_amount(跟随金额)/config(从配置表读取)',
-    dimension_assign JSON COMMENT '维度分配: [{"dim":"action","ratio":100}]',
-    daily_limit INT DEFAULT 0 COMMENT '每日上限(0=不限制)',
-    cooldown_seconds INT DEFAULT 0 COMMENT '冷却时间(秒,0=无冷却)',
-    expire_days INT DEFAULT 0 COMMENT '过期天数(0=永久)',
-    enabled TINYINT DEFAULT 1 COMMENT '是否启用: 0=禁用 1=启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_behavior_code (behavior_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量行为配置表';
-
--- 文章评论表
-CREATE TABLE IF NOT EXISTS article_comments (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    article_id BIGINT NOT NULL COMMENT '文章ID',
-    parent_id BIGINT COMMENT '父评论ID',
-    reply_to_id BIGINT COMMENT '引用的评论ID',
-    user_id BIGINT NOT NULL COMMENT '评论用户ID',
-    content TEXT NOT NULL COMMENT '评论内容',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/approved/rejected',
-    audit_by BIGINT COMMENT '审核人ID',
-    audit_at DATETIME COMMENT '审核时间',
-    earned_energy INT DEFAULT 0 COMMENT '获得的能量',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_article (article_id),
-    INDEX idx_article_status (article_id, status),
-    INDEX idx_parent (parent_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章评论';
-
--- ============================================================
--- 服务角色申请表(统一角色申请入口)
--- ============================================================
-CREATE TABLE IF NOT EXISTS `service_role_applications` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `user_id` int(11) NOT NULL COMMENT '申请人ID',
-  `roles` varchar(255) NOT NULL COMMENT '申请角色,JSON数组 e.g. ["planner","nutritionist"]',
-  `id_card` varchar(18) DEFAULT '' COMMENT '身份证号',
-  `id_card_images` text COMMENT '身份证照片,JSON数组[正面URL,反面URL]',
-  `certificate_images` text COMMENT '资质证书照片,JSON数组',
-  `province` varchar(50) DEFAULT '' COMMENT '省',
-  `city` varchar(50) DEFAULT '' COMMENT '市',
-  `district` varchar(50) DEFAULT '' COMMENT '区',
-  `street` varchar(50) DEFAULT '' COMMENT '街道',
-  `address_detail` varchar(200) DEFAULT '' COMMENT '详细地址',
-  `status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '0-pending, 1-approved, 2-rejected',
-  `reject_reason` varchar(500) DEFAULT '' COMMENT '驳回原因',
-  `reviewed_by` int(11) DEFAULT NULL COMMENT '审核人ID',
-  `reviewed_at` datetime DEFAULT NULL COMMENT '审核时间',
-  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  KEY `idx_user_id` (`user_id`),
-  KEY `idx_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务角色申请表';
-
--- 用户表新增字段(服务角色申请状态)
--- ALTER TABLE users ADD COLUMN article_admin_status VARCHAR(20) DEFAULT NULL COMMENT '文章管理员状态: pending/approved/rejected';
--- ALTER TABLE users ADD COLUMN activity_provider_status VARCHAR(20) DEFAULT NULL COMMENT '活动提供商状态: pending/approved/rejected';
-
--- ============================================================
--- 周期性服务续费配置
--- ============================================================
-CREATE TABLE IF NOT EXISTS periodic_services (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '关联商品ID',
-    service_name VARCHAR(100) COMMENT '服务名称',
-    cycle_days INT NOT NULL COMMENT '周期天数(如365=年度服务)',
-    remind_before_days INT DEFAULT 30 COMMENT '提前提醒天数',
-    auto_renew TINYINT DEFAULT 0 COMMENT '是否支持自动续费: 0=否 1=是',
-    enabled TINYINT DEFAULT 1 COMMENT '是否启用: 0=禁用 1=启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product (product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='周期性服务续费配置';
-
--- ============================================================
--- 推荐行为记录
--- ============================================================
-CREATE TABLE IF NOT EXISTS recommendation_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT COMMENT '用户ID',
-    family_id BIGINT COMMENT '家庭ID',
-    child_id BIGINT COMMENT '孩子ID',
-    content_type VARCHAR(20) NOT NULL COMMENT '内容类型: article/task/product/activity',
-    content_id BIGINT NOT NULL COMMENT '内容ID',
-    recommend_score INT COMMENT '推荐分值',
-    action VARCHAR(20) COMMENT '行为: show/click/consume',
-    recommend_type VARCHAR(20) DEFAULT 'tag' COMMENT '推荐方式: profile/dimension/tag',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_user_content (user_id, content_type, content_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐行为记录';
-
--- products表添加family_scope列(推荐系统-家庭消费去重)
--- ALTER TABLE products ADD COLUMN family_scope TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员消费过即排除, 0=仅按个人消费排除';
-
--- activities表添加family_scope列(推荐系统-家庭参与去重)
--- ALTER TABLE activities ADD COLUMN family_scope TINYINT DEFAULT 1 COMMENT '是否面向家庭: 1=家庭成员参与过即排除, 0=仅按个人参与排除';
-
--- ============================================================
--- 活动报名订单表(付费报名:先支付后报名,迁移143)
--- ============================================================
-CREATE TABLE IF NOT EXISTS activity_orders (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    order_no VARCHAR(64) NOT NULL UNIQUE COMMENT '订单号(ACT+时间戳+随机)',
-    activity_id BIGINT NOT NULL COMMENT '活动ID',
-    user_id BIGINT NOT NULL COMMENT '下单人userId',
-    total_amount INT NOT NULL COMMENT '实付金额(分)',
-    registrants_json TEXT COMMENT '报名人快照JSON: [{name, phone, childId, type: child/parent, fee}]',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/paid/cancelled',
-    transaction_id VARCHAR(64) COMMENT '微信支付单号',
-    paid_at DATETIME COMMENT '支付时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_activity (activity_id),
-    INDEX idx_user (user_id),
-    INDEX idx_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动报名订单表';
-
--- ============================================================
--- 活动总结资料表(总结中阶段发布人上传资料,迁移144)
--- ============================================================
-CREATE TABLE IF NOT EXISTS activity_materials (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    activity_id BIGINT NOT NULL COMMENT '活动ID',
-    title VARCHAR(200) COMMENT '标题',
-    file_url VARCHAR(500) NOT NULL COMMENT '文件地址(图片/PDF/外链URL)',
-    file_type VARCHAR(20) DEFAULT 'image' COMMENT '类型: image/pdf/link',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_activity (activity_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动总结资料表';
-
--- ============================================================
--- 小程序虚拟支付道具映射
--- ============================================================
-CREATE TABLE IF NOT EXISTS virtual_goods_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    goods_type VARCHAR(32) NOT NULL COMMENT 'ASSESSMENT_PACKAGE / MEMBERSHIP / SUBSCRIPTION',
-    biz_key VARCHAR(64) NOT NULL COMMENT '业务SKU标识: 测评套餐ID / 会员等级code / 订阅档位code',
-    product_id VARCHAR(64) NOT NULL COMMENT '微信商户后台道具ID',
-    goods_name VARCHAR(128) NOT NULL COMMENT '道具名称',
-    goods_price INT COMMENT '道具价格(分), 用于拆单判断',
-    status TINYINT NOT NULL DEFAULT 1 COMMENT '1=启用 0=停用',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_goods_type_biz (goods_type, biz_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小程序虚拟支付道具映射';
-
--- ============================================================
--- 家庭天盘周报导出记录表(迁移144)
--- ============================================================
-CREATE TABLE IF NOT EXISTS family_fortune_report (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id INT NOT NULL COMMENT '家庭ID',
-    element VARCHAR(32) COMMENT '主导五行元素',
-    lucky_direction VARCHAR(64) COMMENT '本周吉位',
-    pdf_path VARCHAR(255) COMMENT 'PDF周报文件路径',
-    file_size BIGINT COMMENT '文件大小(字节)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_family_id (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭天盘周报导出记录';
-
--- ============================================================
--- 五维家庭自检记录表(迁移146,P0-1 五维自检问卷,书稿终章15题)
--- ============================================================
-CREATE TABLE IF NOT EXISTS five_dimension_self_checks (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '答卷人用户ID',
-    family_member_id BIGINT COMMENT '关联家庭成员ID(可选)',
-    answers_json TEXT COMMENT '用户答案JSON',
-    scores_json VARCHAR(512) COMMENT '各维度得分JSON',
-    total_score INT COMMENT '五维总分(满分45)',
-    advice_json TEXT COMMENT '五行相生寻源建议JSON',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    question_ids_json VARCHAR(255) DEFAULT NULL COMMENT '本次自检使用的题号JSON: [1,5,9,...]',
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维家庭自检记录';
-
--- 商品赠送会员规则
-CREATE TABLE IF NOT EXISTS product_gift_rules (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '关联products表',
-    level_code VARCHAR(50) NOT NULL COMMENT '赠送会员等级编码(FAMILY/PREMIUM等)',
-    status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_product_level (product_id, level_code),
-    INDEX idx_product_id (product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠送会员规则';
-
--- 商品赠品配置(商品×等级)
-CREATE TABLE IF NOT EXISTS product_gift_configs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '关联products表',
-    level_code VARCHAR(50) NOT NULL COMMENT '会员等级编码(FAMILY/PREMIUM等)',
-    status TINYINT(1) DEFAULT 1 COMMENT '1=启用 0=停用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_product_level (product_id, level_code),
-    INDEX idx_product_id (product_id),
-    INDEX idx_level_code (level_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠品配置(商品×等级)';
-
--- 商品赠品项
-CREATE TABLE IF NOT EXISTS product_gift_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    config_id BIGINT NOT NULL COMMENT '关联product_gift_configs.id',
-    gift_type VARCHAR(20) NOT NULL COMMENT 'product=赠品商品 cf=CF值',
-    gift_product_id BIGINT COMMENT '赠品商品ID(gift_type=product时必填)',
-    gift_product_name VARCHAR(200) COMMENT '赠品商品名快照',
-    gift_product_image VARCHAR(500) COMMENT '赠品商品图快照',
-    cf_value INT DEFAULT 0 COMMENT 'CF值数量(gift_type=cf时必填,单位分)',
-    sort_order INT DEFAULT 0 COMMENT '排序(值越小越靠前)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_config_id (config_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品赠品项';
-
--- 订单赠品记录
-CREATE TABLE IF NOT EXISTS product_order_gifts (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    order_id BIGINT NOT NULL COMMENT '关联product_orders.id',
-    order_no VARCHAR(64) NOT NULL COMMENT '订单号快照',
-    gift_type VARCHAR(20) NOT NULL COMMENT 'product=赠品商品 cf=CF值',
-    gift_product_id BIGINT COMMENT '赠品商品ID',
-    gift_product_name VARCHAR(200) COMMENT '赠品商品名快照',
-    gift_product_image VARCHAR(500) COMMENT '赠品商品图快照',
-    cf_value INT DEFAULT 0 COMMENT 'CF值数量(gift_type=cf时)',
-    quantity INT DEFAULT 1 COMMENT '数量(默认1)',
-    fulfilled TINYINT(1) DEFAULT 0 COMMENT '0=已选未发放 1=已发放',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_order_id (order_id),
-    INDEX idx_order_no (order_no)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单赠品记录';
-
-CREATE TABLE IF NOT EXISTS interaction_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '所属家庭ID',
-    from_member_id BIGINT NULL COMMENT '互动发起方成员ID',
-    to_member_id BIGINT NULL COMMENT '互动接收方成员ID',
-    interaction_type VARCHAR(20) NOT NULL COMMENT '互动类型: dining/outgoing/call/video/chat/play/gift',
-    description VARCHAR(500) COMMENT '互动描述',
-    happened_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '互动发生时间',
-    photo_urls TEXT COMMENT '照片URL列表(逗号分隔)',
-    video_url VARCHAR(500) COMMENT '视频URL',
-    audio_url VARCHAR(500) COMMENT '音频URL',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_ilog_family (family_id),
-    INDEX idx_ilog_to_member (to_member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭成员互动记录';
-
-CREATE TABLE IF NOT EXISTS relationship_questionnaire_snapshots (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_member_id BIGINT NULL COMMENT '家庭成员ID',
-    respondent_id BIGINT NOT NULL COMMENT '答卷人用户ID',
-    member_name VARCHAR(50) COMMENT '成员名称',
-    relationship_type VARCHAR(20) COMMENT '关系类型: parent/child',
-    ai_generated_json TEXT COMMENT 'AI生成的题目JSON',
-    version VARCHAR(20) COMMENT '版本号',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_q_snap_member (family_member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关系问卷快照';
-
-CREATE TABLE IF NOT EXISTS relationship_questionnaire_responses (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    snapshot_id BIGINT NOT NULL COMMENT '问卷快照ID',
-    respondent_id BIGINT NOT NULL COMMENT '答卷人用户ID',
-    answers_json TEXT COMMENT '用户回答JSON',
-    trust_score DECIMAL(5,2) DEFAULT 0 COMMENT '信任度得分',
-    intimacy_score DECIMAL(5,2) DEFAULT 0 COMMENT '亲密度得分',
-    communication_score DECIMAL(5,2) DEFAULT 0 COMMENT '沟通质量得分',
-    interaction_bonus DECIMAL(5,2) DEFAULT 0 COMMENT '互动记录加分',
-    total_score DECIMAL(5,2) DEFAULT 0 COMMENT '综合得分',
-    calculated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_q_resp_snap (snapshot_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关系问卷回答记录';
-
--- =============================================
--- 优惠券发放流水表(会员体系重构: 统一价+优惠券发放/积分兑换)
--- =============================================
-
-CREATE TABLE IF NOT EXISTS coupon_grant_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '收券用户ID',
-    coupon_id BIGINT NOT NULL COMMENT '券模板ID',
-    grant_type VARCHAR(16) NOT NULL COMMENT 'JOIN/PERIODIC/POPULATION/EXCHANGE',
-    period VARCHAR(16) COMMENT '周期标识(YYYY-MM或YYYY-Qn),PERIODIC防重用',
-    quantity INT DEFAULT 1 COMMENT '发放数量',
-    source VARCHAR(64) COMMENT '触发来源(订单号/成员ID等)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_grant (user_id, coupon_id, grant_type, period),
-    INDEX idx_coupon (coupon_id),
-    INDEX idx_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='优惠券发放流水表';
-
--- =============================================
--- 家庭优惠券表(全链路改为家庭维度:2026-08-31)
--- =============================================
-
-CREATE TABLE IF NOT EXISTS family_coupon (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '所属家庭ID',
-    coupon_id BIGINT NOT NULL COMMENT '券模板ID',
-    status VARCHAR(16) DEFAULT 'AVAILABLE' COMMENT 'AVAILABLE/USED',
-    received_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    used_at DATETIME,
-    order_id BIGINT COMMENT '核销时写入的订单号',
-    INDEX idx_family_coupon (family_id, coupon_id),
-    INDEX idx_status (status),
-    INDEX idx_order_id (order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭优惠券表';
-
-CREATE TABLE IF NOT EXISTS family_coupon_grant_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '受赠家庭ID',
-    coupon_id BIGINT NOT NULL COMMENT '券模板ID',
-    grant_type VARCHAR(16) NOT NULL COMMENT 'JOIN/PERIODIC/POPULATION/EXCHANGE/CF_EXCHANGE',
-    period VARCHAR(16) COMMENT '周期标识(YYYY-MM或YYYY-Qn),PERIODIC防重用',
-    quantity INT DEFAULT 1 COMMENT '发放数量',
-    source VARCHAR(64) COMMENT '触发来源(订单号/成员ID等)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family_grant (family_id, coupon_id, grant_type, period),
-    INDEX idx_coupon (coupon_id),
-    INDEX idx_family (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭优惠券发放流水表';
-
--- 家庭加入请求(邀请人审批,旧数据由家庭管理员兜底)
-CREATE TABLE IF NOT EXISTS family_join_requests (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    requester_user_id BIGINT NOT NULL COMMENT '申请加入的用户ID',
-    target_family_id BIGINT NOT NULL COMMENT '目标家庭ID',
-    join_method VARCHAR(20) NOT NULL COMMENT '加入方式: by_code/by_token',
-    invite_ref VARCHAR(50) COMMENT '邀请码或令牌',
-    inviter_user_id BIGINT COMMENT '邀请人用户ID(分享邀请令牌的人)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected/cancelled',
-    approver_user_id BIGINT COMMENT '审批人ID',
-    comment TEXT COMMENT '审批备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_requester (requester_user_id),
-    INDEX idx_target_family (target_family_id),
-    INDEX idx_status (status),
-    INDEX idx_inviter (inviter_user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭加入请求(待审批)';
-
--- 用户同意记录表
-CREATE TABLE IF NOT EXISTS user_consent_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    consent_type VARCHAR(50) NOT NULL COMMENT '同意类型: privacy/agreement/children_data/ai_processing',
-    version VARCHAR(20) NOT NULL COMMENT '协议版本号',
-    status VARCHAR(20) NOT NULL DEFAULT 'agreed' COMMENT 'agreed/withdrawn/archived',
-    ip_address VARCHAR(45) COMMENT '用户IP地址',
-    created_at DATETIME NOT NULL,
-    updated_at DATETIME,
-    INDEX idx_user_consent (user_id, consent_type),
-    INDEX idx_consent_type (consent_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户同意记录';
-
--- 用户数据授权表
-CREATE TABLE IF NOT EXISTS user_data_permissions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    allow_ai_analysis TINYINT(1) DEFAULT 0 COMMENT '允许AI分析对话数据',
-    allow_personalized_recommend TINYINT(1) DEFAULT 1 COMMENT '允许个性化推荐',
-    allow_share_teacher TINYINT(1) DEFAULT 1 COMMENT '允许向成长规划师共享数据',
-    allow_third_party_share TINYINT(1) DEFAULT 0 COMMENT '允许与第三方共享数据',
-    created_at DATETIME NOT NULL,
-    updated_at DATETIME,
-    INDEX idx_user_perm (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户数据使用授权';
-
--- ===== 饮食模块 =====
-
--- 食材库表
-CREATE TABLE IF NOT EXISTS foods (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '食材名称',
-    category VARCHAR(50) COMMENT '分类: 蔬菜/水果/肉禽/水产/蛋奶/豆类/谷物/调味/其他',
-    unit VARCHAR(20) DEFAULT 'g' COMMENT '计量单位',
-    calories DECIMAL(8,2) COMMENT '热量(kcal/100g)',
-    protein DECIMAL(8,2) COMMENT '蛋白质(g/100g)',
-    fat DECIMAL(8,2) COMMENT '脂肪(g/100g)',
-    carbs DECIMAL(8,2) COMMENT '碳水(g/100g)',
-    fiber DECIMAL(8,2) COMMENT '膳食纤维(g/100g)',
-    energy_kj DECIMAL(8,2) COMMENT '能量(kJ/100g)',
-    starch DECIMAL(8,2) COMMENT '淀粉(g/100g)',
-    cholesterol DECIMAL(8,2) COMMENT '胆固醇(mg/100g)',
-    price_level TINYINT COMMENT '价格等级 1-5',
-    nutrition_tags VARCHAR(500) COMMENT '营养标签JSON',
-    suitable_for VARCHAR(200) COMMENT '适宜人群JSON',
-    allergens VARCHAR(200) COMMENT '过敏原JSON',
-    external_source VARCHAR(100) COMMENT '数据来源',
-    external_id VARCHAR(100) COMMENT '外部ID',
-    cover_image VARCHAR(500) COMMENT '食材图片',
-    report_id BIGINT COMMENT '关联报告ID(从PDF解析的食物推荐)',
-    score INT COMMENT '食物评分',
-    status VARCHAR(20) DEFAULT 'active',
-    sort_order INT DEFAULT 0,
-    diet_type VARCHAR(50) COMMENT '饮食类型',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_category (category),
-    INDEX idx_price (price_level)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材库表';
-
--- 食材营养素表(每食材多营养素)
-CREATE TABLE IF NOT EXISTS food_nutrients (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    food_id BIGINT NOT NULL COMMENT '食材ID',
-    nutrient_code VARCHAR(20) NOT NULL COMMENT '营养素编码',
-    amount_per100g DECIMAL(10,4) NOT NULL COMMENT '每100g含量',
-    unit VARCHAR(20) NOT NULL COMMENT '单位',
-    source VARCHAR(50) DEFAULT 'importer' COMMENT '数据来源',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_food_nutrient (food_id, nutrient_code),
-    INDEX idx_nutrient (nutrient_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食材营养素表';
-
--- 饮食偏好调研表(每成员一份)
-CREATE TABLE IF NOT EXISTS diet_preferences (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_member_id BIGINT NULL COMMENT '绑定家庭成员',
-    allergies JSON COMMENT '过敏原列表',
-    absolute_avoid JSON COMMENT '绝对忌口列表',
-    must_eat JSON COMMENT '必吃食物列表',
-    religious_diet VARCHAR(50) DEFAULT 'none' COMMENT '宗教饮食:none/清真/素食/纯素/印度素',
-    spice_level TINYINT DEFAULT NULL COMMENT '辣度 0-5',
-    flavor_pref JSON COMMENT '口味偏好(酸/甜/咸/鲜/苦)',
-    cuisine_pref JSON COMMENT '菜系偏好(川/粤/淮扬/日料/西餐)',
-    cooking_methods JSON COMMENT '偏好烹饪方式(炒/蒸/煮/烤/凉拌)',
-    health_goals JSON COMMENT '健康目标(减脂/增肌/控糖/肠道调理/护肝)',
-    goal_source VARCHAR(20) DEFAULT NULL COMMENT 'manual/system_recommend',
-    goal_confirmed TINYINT(1) DEFAULT 0 COMMENT '用户已确认',
-    no_preference TINYINT(1) DEFAULT 0 COMMENT '无特殊偏好标记(1=用户明确选择无特殊偏好)',
-    filled_at TIMESTAMP NULL COMMENT '首次填写时间',
-    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_member (family_member_id),
-    INDEX idx_updated (updated_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食偏好调研表';
-
--- 共餐配置表(按家庭+日期类型+餐次;config_date非NULL时为当天临时配置,优先级高于默认配置)
-CREATE TABLE IF NOT EXISTS meal_configs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    config_date_type VARCHAR(20) NOT NULL COMMENT '工作日/周末/节假日',
-    config_date DATE DEFAULT NULL COMMENT '当天临时配置日期(NULL=默认工作日/周末配置)',
-    config_date_eff DATE GENERATED ALWAYS AS (COALESCE(config_date, '9999-12-31')) STORED COMMENT '生效日期(NULL映射为9999-12-31,用于唯一约束)',
-    meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner',
-    participant_member_ids JSON NOT NULL COMMENT '参与成员ID列表',
-    notes VARCHAR(255) DEFAULT NULL COMMENT '备注',
-    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_config (family_id, config_date_eff, meal_type),
-    INDEX idx_family (family_id),
-    INDEX idx_config_date (config_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共餐配置表';
-
--- 食谱推荐方案表
-CREATE TABLE IF NOT EXISTS diet_recommendations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    recommendation_date DATE NOT NULL COMMENT '推荐日期',
-    meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner',
-    participant_member_ids JSON COMMENT '参与成员ID列表',
-    menu_json MEDIUMTEXT NOT NULL COMMENT '菜品列表JSON',
-    nutrition_summary JSON COMMENT '营养汇总',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/accepted/adjusted/completed/skipped',
-    version INT DEFAULT 1 COMMENT '版本号(重新生成+1)',
-    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_date (family_id, recommendation_date),
-    INDEX idx_meal (meal_type, recommendation_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='食谱推荐方案表';
-
--- 饮食记录表
-CREATE TABLE IF NOT EXISTS diet_records (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    member_id BIGINT NULL COMMENT '吃的成员ID',
-    meal_type VARCHAR(20) NOT NULL COMMENT 'breakfast/lunch/dinner/snack',
-    record_date DATE NOT NULL COMMENT '记录日期',
-    record_method VARCHAR(20) DEFAULT NULL COMMENT 'photo/manual/from_recommendation',
-    image_url VARCHAR(500) DEFAULT NULL COMMENT '原图OSS路径',
-    ai_recognized_foods JSON DEFAULT NULL COMMENT 'AI识别结果',
-    user_confirmed_foods JSON NOT NULL COMMENT '用户最终确认食材',
-    notes VARCHAR(500) DEFAULT NULL COMMENT '备注',
-    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_date (member_id, record_date),
-    INDEX idx_family_date (family_id, record_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食记录表';
-
--- 饮食记录食材明细表
-CREATE TABLE IF NOT EXISTS diet_record_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    record_id BIGINT NOT NULL COMMENT 'diet_records.id',
-    food_name VARCHAR(100) NOT NULL COMMENT '食材名称',
-    food_id BIGINT DEFAULT NULL COMMENT '关联foods表ID',
-    confidence DECIMAL(3,2) DEFAULT NULL COMMENT 'AI置信度0-1',
-    source VARCHAR(20) DEFAULT NULL COMMENT 'ai_recognized/manual/from_recommendation',
-    INDEX idx_record (record_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='饮食记录食材明细表';
-
--- 报告指纹检测与解析器调度系统
-
--- 报告类型注册表
-CREATE TABLE IF NOT EXISTS report_type_registry (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    type_id VARCHAR(64) NOT NULL COMMENT '类型标识,如 dan_a1/gut_beijing',
-    family VARCHAR(32) DEFAULT NULL COMMENT '报告家族: dan/gut_flora/其他',
-    display_name VARCHAR(100) NOT NULL COMMENT '显示名称',
-    description VARCHAR(500) DEFAULT NULL COMMENT '描述',
-    parser_path VARCHAR(255) DEFAULT NULL COMMENT 'Python解析器脚本路径',
-    min_confidence INT DEFAULT 10 COMMENT '识别阈值',
-    is_active TINYINT(1) DEFAULT 1 COMMENT '启用状态',
-    source VARCHAR(20) DEFAULT 'prebuilt' COMMENT '来源: prebuilt/imported/auto_generated',
-    review_status VARCHAR(20) DEFAULT 'approved' COMMENT '审核状态: approved/pending/rejected',
-    version VARCHAR(20) DEFAULT '1.0' COMMENT '版本',
-    created_by BIGINT DEFAULT NULL COMMENT '创建人ID',
-    script_status VARCHAR(20) DEFAULT NULL COMMENT '采集脚本生成状态: generating/ready/failed',
-    expected_indicators TEXT DEFAULT NULL COMMENT '该报告类型应采集的指标项定义(JSON数组),用于数据采集完整性校验',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_type_id (type_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告类型注册表';
-
--- 报告指纹规则表
-CREATE TABLE IF NOT EXISTS report_fingerprint (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    type_id VARCHAR(64) NOT NULL COMMENT '关联report_type_registry.type_id',
-    pattern VARCHAR(200) NOT NULL COMMENT '文本特征',
-    weight INT DEFAULT 10 COMMENT '权重(正=加分,负=排除扣分)',
-    is_exclusion TINYINT(1) DEFAULT 0 COMMENT '是否为排除规则',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_fp_type (type_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告指纹规则表';
-
--- 未知报告聚类表
-CREATE TABLE IF NOT EXISTS report_unknown_cluster (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    cluster_key VARCHAR(64) NOT NULL COMMENT '聚类哈希键(同类报告分组)',
-    common_signatures TEXT COMMENT '公共文本特征JSON(用于生成指纹)',
-    llm_template TEXT COMMENT 'LLM解析结果模板JSON',
-    report_count INT DEFAULT 0 COMMENT '累计报告数',
-    status VARCHAR(20) DEFAULT 'collecting' COMMENT '状态: collecting/ready/generated/imported',
-    generated_type_id VARCHAR(64) DEFAULT NULL COMMENT '生成的类型ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_cluster_key (cluster_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='未知报告聚类表';
-
--- 未知报告上传明细表
-CREATE TABLE IF NOT EXISTS report_unknown_upload (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    cluster_id BIGINT DEFAULT NULL COMMENT '关联report_unknown_cluster.id',
-    file_url VARCHAR(500) DEFAULT NULL COMMENT '文件路径',
-    file_hash VARCHAR(64) DEFAULT NULL COMMENT '文件哈希',
-    llm_result TEXT COMMENT 'LLM解析结果JSON',
-    annotation TEXT COMMENT '管理员标注: 手动指定类型+确认提取结果JSON',
-    uploaded_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_unknown_cluster (cluster_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='未知报告上传明细表';
-
--- ========== 报告展示模板表 ==========
-CREATE TABLE IF NOT EXISTS report_template (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '模板名称',
-    report_type VARCHAR(50) NOT NULL COMMENT '报告类型: gut_flora/dan/physical_exam/tongue',
-    config JSON NOT NULL COMMENT '模板配置JSON: fixedBlocks+freeDisplay',
-    is_active TINYINT DEFAULT 1 COMMENT '0=停用 1=启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_report_type (report_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告展示模板';
-
--- 报告解析器导入记录表
-CREATE TABLE IF NOT EXISTS report_parser_import (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    package_name VARCHAR(100) NOT NULL COMMENT '导入包名称',
-    package_file_url VARCHAR(500) DEFAULT NULL COMMENT '导入包文件路径',
-    fingerprint_json TEXT COMMENT '指纹规则JSON',
-    parser_script TEXT COMMENT '解析器脚本内容',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT '状态: pending/approved/rejected',
-    imported_by BIGINT DEFAULT NULL COMMENT '导入人ID',
-    reviewed_by BIGINT DEFAULT NULL COMMENT '审核人ID',
-    review_note VARCHAR(500) DEFAULT NULL COMMENT '审核意见',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告解析器导入记录表';
-
--- ===== CF值(平台积分)体系 =====
-
-CREATE TABLE IF NOT EXISTS user_platform_balance (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id       BIGINT       NOT NULL COMMENT '用户ID',
-    family_id     BIGINT       COMMENT '归属家庭ID',
-    total_earned  INT DEFAULT 0 COMMENT '累计获得',
-    available     INT DEFAULT 0 COMMENT '可用余额',
-    frozen        INT DEFAULT 0 COMMENT '冻结(提现审核中)',
-    withdrawn     INT DEFAULT 0 COMMENT '已提现',
-    exchanged     INT DEFAULT 0 COMMENT '已兑换',
-    updated_at    DATETIME,
-    created_at    DATETIME,
-    UNIQUE KEY uk_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户CF值余额';
-
-CREATE TABLE IF NOT EXISTS platform_balance_log (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id       BIGINT       NOT NULL COMMENT '用户ID',
-    family_id     BIGINT       COMMENT '归属家庭ID',
-    type          VARCHAR(20)  NOT NULL COMMENT 'earn/spend/freeze/unfreeze/withdraw',
-    amount        INT          NOT NULL COMMENT '变动数量',
-    balance_after INT          NOT NULL COMMENT '变动后可用余额',
-    ref_type      VARCHAR(30)  COMMENT 'product_order/activity/withdrawal/migration',
-    ref_id        BIGINT       COMMENT '关联业务ID',
-    remark        VARCHAR(255) COMMENT '备注',
-    created_at    DATETIME,
-    INDEX idx_user_time (user_id, created_at),
-    UNIQUE KEY uk_user_ref (user_id, ref_type, ref_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流水';
-
-
-
--- ===== 家庭平台积分池(CF值家庭维度)=====
-
-CREATE TABLE IF NOT EXISTS family_platform_balance (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id     BIGINT       NOT NULL COMMENT '家庭ID',
-    total_earned  INT DEFAULT 0 COMMENT '累计获得',
-    available     INT DEFAULT 0 COMMENT '可用余额',
-    frozen        INT DEFAULT 0 COMMENT '冻结(提现审核中)',
-    withdrawn     INT DEFAULT 0 COMMENT '已提现',
-    exchanged     INT DEFAULT 0 COMMENT '已兑换(抵扣/积分消耗)',
-    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at    DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family (family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭平台积分池余额';
-
-CREATE TABLE IF NOT EXISTS family_platform_balance_log (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id     BIGINT       NOT NULL COMMENT '家庭ID',
-    type          VARCHAR(20)  NOT NULL COMMENT 'earn/spend/freeze/unfreeze/withdraw/adjust/migration',
-    amount        INT          NOT NULL COMMENT '变动数量',
-    balance_after INT          NOT NULL COMMENT '变动后可用余额',
-    ref_type      VARCHAR(50)  COMMENT 'product_order/referral_dist/activity/withdrawal/adjust/migration/refund',
-    ref_id        BIGINT       COMMENT '关联业务ID',
-    remark        VARCHAR(255) COMMENT '备注',
-    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_family (family_id),
-    INDEX idx_ref (ref_type, ref_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭平台积分流水';
-
--- ===== 家庭平台积分兑换记录 =====
-
-CREATE TABLE IF NOT EXISTS family_platform_exchange_record (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id       BIGINT       NOT NULL COMMENT '操作用户ID',
-    family_id     BIGINT       NOT NULL COMMENT '家庭ID',
-    coupon_id     BIGINT       NOT NULL COMMENT '关联优惠券ID',
-    coupon_name   VARCHAR(200) COMMENT '优惠券名称',
-    cf_cost       INT          NOT NULL COMMENT '消耗CF值数量',
-    status        VARCHAR(20)  NOT NULL DEFAULT 'completed' COMMENT 'completed/failed',
-    redeem_code   VARCHAR(32)  COMMENT '兑换码',
-    remark        VARCHAR(255) COMMENT '备注',
-    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at    DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_family_time (family_id, created_at),
-    INDEX idx_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭CF值兑换记录';
-
--- ===== 健康方案汇总 =====
-
-CREATE TABLE IF NOT EXISTS health_plans (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id     BIGINT       NOT NULL COMMENT '家庭ID',
-    member_ids    VARCHAR(200) NOT NULL COMMENT '目标成员ID列表(逗号分隔)',
-    dimensions    VARCHAR(100) NOT NULL COMMENT '维度列表(逗号分隔)',
-    goal          TEXT         NOT NULL COMMENT '用户输入的目标',
-    plan_content  TEXT         COMMENT 'LangGraph生成的方案内容',
-    member_name   VARCHAR(50)  COMMENT '成员名称摘要',
-    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
-    plan_json     TEXT         COMMENT '结构化方案内容(JSON)',
-    total_days    INT          DEFAULT NULL COMMENT '方案周期天数,驱动服务任务周期边界与截止日期(默认14)',
-    status        VARCHAR(20)  DEFAULT 'draft' COMMENT '方案状态: draft(草稿)/confirmed(已确认)',
-    reviewed_by   BIGINT DEFAULT NULL COMMENT '审核人ID(规划师/营养师)',
-    reviewed_at   DATETIME DEFAULT NULL COMMENT '审核时间',
-    review_comment TEXT DEFAULT NULL COMMENT '审核意见',
-    teacher_id    BIGINT DEFAULT NULL COMMENT '指定规划师ID(用户选择)',
-    updated_at    DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_family (family_id),
-    INDEX idx_created (created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康方案汇总记录';
-
--- 定期调研模板
-CREATE TABLE IF NOT EXISTS survey_templates (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    title         VARCHAR(100) NOT NULL COMMENT '调研标题',
-    dimension     VARCHAR(20) COMMENT '适用维度(身/智/富/行/心)',
-    questions_json TEXT COMMENT '题目JSON(含选项)',
-    cycle_type    VARCHAR(20) DEFAULT 'weekly' COMMENT '周期: weekly/biweekly/monthly',
-    ai_generated  TINYINT(1) DEFAULT 0 COMMENT '是否AI生成',
-    enabled       TINYINT(1) DEFAULT 1 COMMENT '是否启用',
-    created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at    DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='定期调研模板';
-
--- 定期调研记录
-CREATE TABLE IF NOT EXISTS survey_records (
-    id            BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id     BIGINT NOT NULL COMMENT '家庭ID',
-    member_id     BIGINT NOT NULL COMMENT '成员ID',
-    template_id   BIGINT NOT NULL COMMENT '调研模板ID',
-    answers_json  TEXT COMMENT '答案JSON',
-    submitted_at  DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '提交时间',
-    period_start  DATE COMMENT '周期开始',
-    period_end    DATE COMMENT '周期结束',
-    INDEX idx_member (member_id),
-    INDEX idx_template (template_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='定期调研记录';
-
--- 报告通用展示块(迁移211)
-CREATE TABLE IF NOT EXISTS report_blocks (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    report_type VARCHAR(32) NOT NULL COMMENT 'gut_flora/dan/physical_exam/tongue',
-    report_id   BIGINT NOT NULL COMMENT '各类型报告主键ID',
-    blocks      JSON NOT NULL COMMENT '块数组 [{type,title,items,extra}]',
-    version     INT DEFAULT 1,
-    created_at  DATETIME,
-    updated_at  DATETIME,
-    UNIQUE KEY uk_report_type_id (report_type, report_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告通用展示块';
-
--- 营养产品分类(迁移214)
-CREATE TABLE IF NOT EXISTS nutrition_category (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(50) NOT NULL COMMENT '分类名',
-    parent_id BIGINT DEFAULT NULL COMMENT '父分类ID',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品分类';
-
--- 营养产品品牌(迁移215)
-CREATE TABLE IF NOT EXISTS nutrition_brand (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(100) NOT NULL COMMENT '品牌名',
-    logo_url VARCHAR(500) DEFAULT NULL COMMENT '品牌Logo',
-    description TEXT COMMENT '品牌简介',
-    country VARCHAR(50) DEFAULT NULL COMMENT '产地国',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品品牌';
-
--- 营养产品主表(迁移216)
-CREATE TABLE IF NOT EXISTS nutrition_product (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(200) NOT NULL COMMENT '产品名称',
-    brand_id BIGINT DEFAULT NULL COMMENT '品牌ID',
-    category_id BIGINT DEFAULT NULL COMMENT '分类ID',
-    sub_category VARCHAR(50) DEFAULT NULL COMMENT '子分类',
-    form VARCHAR(30) DEFAULT NULL COMMENT '剂型',
-    net_content VARCHAR(50) DEFAULT NULL COMMENT '净含量',
-    shelf_life VARCHAR(50) DEFAULT NULL COMMENT '保质期',
-    suitable_for TEXT DEFAULT NULL COMMENT '适用人群',
-    ingredients TEXT DEFAULT NULL COMMENT '成份/配料表(从详情页图片提取)',
-    image_url VARCHAR(500) DEFAULT NULL COMMENT '产品图',
-    description TEXT COMMENT '产品描述',
-    status TINYINT DEFAULT 1 COMMENT '状态 0下架/1上架',
-    local_product_id BIGINT DEFAULT NULL COMMENT '本平台商品ID,关联products.id',
-    price DECIMAL(10,2) DEFAULT 0 COMMENT '当前售价',
-    original_price INT DEFAULT 0 COMMENT '原价(整数)',
-    sold_num INT DEFAULT 0 COMMENT '已售数量',
-    source_platform VARCHAR(50) DEFAULT '' COMMENT '来源平台',
-    source_id VARCHAR(100) DEFAULT '' COMMENT '来源平台商品ID',
-    source_url VARCHAR(500) DEFAULT '' COMMENT '来源平台商品链接',
-    product_images TEXT COMMENT '商品图片URL(JSON数组)',
-    spec VARCHAR(200) DEFAULT '' COMMENT '规格',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_brand (brand_id),
-    INDEX idx_category (category_id),
-    INDEX idx_source (source_platform, source_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品';
-
--- 营养产品成分明细(迁移217)
-CREATE TABLE IF NOT EXISTS nutrition_ingredient (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '产品ID',
-    ingredient_type VARCHAR(20) COMMENT '成分类型',
-    name VARCHAR(100) NOT NULL COMMENT '成分名',
-    strain VARCHAR(100) DEFAULT NULL COMMENT '菌株号',
-    amount_per_serving DECIMAL(10,2) DEFAULT NULL COMMENT '每份含量',
-    unit VARCHAR(20) DEFAULT NULL COMMENT '单位',
-    daily_value VARCHAR(50) DEFAULT NULL COMMENT '每日参考值%',
-    purpose VARCHAR(200) DEFAULT NULL COMMENT '功效说明',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_product (product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品成分明细';
-
--- 营养产品平台在售信息(迁移218)
-CREATE TABLE IF NOT EXISTS nutrition_platform_listing (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    product_id BIGINT NOT NULL COMMENT '产品ID',
-    platform VARCHAR(30) COMMENT '平台',
-    platform_url VARCHAR(500) DEFAULT NULL COMMENT '商品链接',
-    current_price DECIMAL(10,2) DEFAULT NULL COMMENT '当前价格',
-    original_price DECIMAL(10,2) DEFAULT NULL COMMENT '原价/划线价',
-    price_unit VARCHAR(30) DEFAULT NULL COMMENT '价格单位',
-    price_per_unit DECIMAL(10,2) DEFAULT NULL COMMENT '每单位价格',
-    sales_count INT DEFAULT NULL COMMENT '销量',
-    stock_status VARCHAR(20) DEFAULT NULL COMMENT '库存状态',
-    last_checked DATETIME DEFAULT NULL COMMENT '最后爬取时间',
-    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_product (product_id),
-    INDEX idx_platform (platform)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品平台在售信息';
-
--- 营养产品评价(迁移219)
-CREATE TABLE IF NOT EXISTS nutrition_product_review (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    platform_listing_id BIGINT NOT NULL COMMENT '平台在售ID',
-    source VARCHAR(30) DEFAULT NULL COMMENT '来源平台',
-    rating DECIMAL(2,1) DEFAULT NULL COMMENT '评分',
-    review_count INT DEFAULT NULL COMMENT '评价数',
-    good_rate VARCHAR(10) DEFAULT NULL COMMENT '好评率',
-    last_updated DATETIME DEFAULT NULL COMMENT '最后更新时间',
-    INDEX idx_listing (platform_listing_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='营养产品评价';
-
--- 文件记录表(迁移220:去重 + 维护)
-CREATE TABLE IF NOT EXISTS file_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    hash VARCHAR(64) NOT NULL COMMENT 'SHA-256 文件哈希',
-    url VARCHAR(500) NOT NULL COMMENT '文件访问URL',
-    file_size BIGINT NOT NULL COMMENT '文件大小(字节)',
-    content_type VARCHAR(100) DEFAULT NULL COMMENT 'MIME类型',
-    original_filename VARCHAR(255) DEFAULT NULL COMMENT '原始文件名',
-    category VARCHAR(50) DEFAULT 'general' COMMENT '分类: articles/dan-reports/assessment-reports/health-reports/general',
-    file_type VARCHAR(50) DEFAULT NULL COMMENT '文件类型: image/pdf/video/audio/other',
-    description VARCHAR(500) DEFAULT NULL COMMENT '描述',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_hash (hash),
-    INDEX idx_category (category),
-    INDEX idx_created_at (created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件记录表(去重&维护)';
-
--- 文件标签字典(迁移222)
-CREATE TABLE IF NOT EXISTS file_tag (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    name VARCHAR(50) NOT NULL COMMENT '标签名称',
-    color VARCHAR(7) DEFAULT '#409EFF' COMMENT '标签颜色(十六进制)',
-    sort_order INT DEFAULT 0 COMMENT '排序号',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_name (name)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件标签字典';
-
--- 文件-标签关联(迁移223)
-CREATE TABLE IF NOT EXISTS file_tag_rel (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    file_id BIGINT NOT NULL COMMENT 'file_record.id',
-    tag_id BIGINT NOT NULL COMMENT 'file_tag.id',
-    UNIQUE KEY uk_file_tag (file_id, tag_id),
-    INDEX idx_tag (tag_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件-标签关联';
-
--- 通关解锁关卡定义
-CREATE TABLE IF NOT EXISTS unlock_gates (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    gate_type VARCHAR(32) NOT NULL COMMENT 'SELF_CHECK/INVITE_FAMILY/CREATE_FAMILY_MEMBER/PURCHASE/MEMBERSHIP/REPORT_UPLOAD/MICRO_ACTION/STREAK_DAYS',
-    name VARCHAR(50) NOT NULL COMMENT '关卡名称',
-    description VARCHAR(200) COMMENT '关卡说明',
-    icon VARCHAR(10) COMMENT '图标emoji',
-    sort_order INT DEFAULT 0 COMMENT '排序号',
-    enabled TINYINT DEFAULT 1 COMMENT '启用:1 禁用:0',
-    is_required TINYINT DEFAULT 1 COMMENT '主线:1 增值:0',
-    is_soft TINYINT DEFAULT 0 COMMENT '硬门禁:0 软引导:1',
-    unlock_target VARCHAR(32) COMMENT 'PERSONAL_SANDBOX/FAMILY_SANDBOX/CHILD_MICRO_ACTION/...',
-    condition_params VARCHAR(500) COMMENT '条件参数JSON',
-    reward_points INT DEFAULT 0 COMMENT '通关奖励积分',
-    reward_energy INT DEFAULT 0 COMMENT '通关奖励能量',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_sort (enabled, is_required, is_soft, sort_order)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通关解锁关卡定义';
-
--- 家庭关卡通关进度
-CREATE TABLE IF NOT EXISTS family_gate_progress (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    gate_id BIGINT NOT NULL COMMENT '关卡ID',
-    status VARCHAR(16) DEFAULT 'LOCKED' COMMENT 'LOCKED/UNLOCKED',
-    unlocked_by BIGINT COMMENT '解锁人user_id',
-    unlocked_at DATETIME COMMENT '解锁时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_family_gate (family_id, gate_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭关卡通关进度';
-
--- 菌群知识库文章管理
-CREATE TABLE IF NOT EXISTS microbiome_article (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    title VARCHAR(255) NOT NULL COMMENT '文章标题',
-    content MEDIUMTEXT COMMENT '文章原文Markdown',
-    category VARCHAR(50) DEFAULT '科普' COMMENT '分类',
-    tags VARCHAR(500) COMMENT '逗号分隔标签',
-    source_url VARCHAR(500) COMMENT '来源URL',
-    pub_date VARCHAR(20) COMMENT '发布日期',
-    status TINYINT DEFAULT 1 COMMENT '1=启用 0=禁用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_category (category),
-    INDEX idx_status (status),
-    FULLTEXT INDEX ft_content (title, content)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='菌群知识库文章';
-
--- 后台侧边栏菜单表
-CREATE TABLE IF NOT EXISTS sys_menu (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    parent_id BIGINT NOT NULL DEFAULT 0 COMMENT '父菜单ID,0=顶级',
-    title VARCHAR(50) COMMENT '目录标题(有子菜单时用,对应 el-submenu)',
-    label VARCHAR(50) COMMENT '叶子菜单显示名(对应 el-menu-item)',
-    path VARCHAR(200) COMMENT '路由路径(叶子菜单必填,如 /families)',
-    icon VARCHAR(100) COMMENT 'Element UI 图标类名,如 el-icon-s-custom',
-    perm VARCHAR(100) COMMENT '权限标识,如 family:list / task:* / system:config',
-    sort INT DEFAULT 0 COMMENT '排序号,小的在前',
-    visible TINYINT DEFAULT 1 COMMENT '是否显示 1=显示 0=隐藏',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_parent (parent_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='后台侧边栏菜单表';
-
--- 角色-菜单授权表
-CREATE TABLE IF NOT EXISTS sys_role_menu (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    role VARCHAR(50) NOT NULL COMMENT '角色标识: admin/teacher/nutritionist/article_manager/activity_manager/supplier_admin',
-    menu_id BIGINT NOT NULL COMMENT 'sys_menu.id',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_role_menu (role, menu_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色-菜单授权表';
-
-
-
-
-
--- =============================================
--- 改版v1: 需求驱动·逐步解锁(问题域/用户意图/站内通知)
--- =============================================
-
-CREATE TABLE IF NOT EXISTS problem_domains (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  code VARCHAR(50) NOT NULL COMMENT '唯一编码: weight_loss/sleep/constipation',
-  name VARCHAR(50) NOT NULL COMMENT '名称: 减肥/睡眠/便秘',
-  icon VARCHAR(255) DEFAULT '' COMMENT '图标',
-  description VARCHAR(500) DEFAULT '' COMMENT '一句话描述',
-  flow_intro_json TEXT COMMENT '服务流程介绍(7步) JSON',
-  survey_template_id BIGINT DEFAULT NULL COMMENT '专项调研问卷模板ID(SurveyTemplate.id)',
-  content_tags VARCHAR(500) DEFAULT '' COMMENT '内容标签,逗号分隔(过滤文章/知识库)',
-  recommended_product_ids VARCHAR(500) DEFAULT '' COMMENT '推荐产品ID,逗号分隔(Product.id)',
-  task_template_package_ids VARCHAR(500) DEFAULT '' COMMENT '套餐绑定的任务模板包ID(TaskTemplatePackage.id)',
-  reward_cf_value INT DEFAULT 0 COMMENT '全部完成奖励CF值',
-  status TINYINT DEFAULT 1 COMMENT '1启用 0停用',
-  sort_order INT DEFAULT 0,
-  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  UNIQUE KEY uk_code (code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题域定义(改版v1)';
-
-CREATE TABLE IF NOT EXISTS user_intents (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  user_id BIGINT NOT NULL COMMENT '用户ID',
-  intent_type VARCHAR(20) DEFAULT '' COMMENT 'A/B/C 用户类型',
-  problem_domain_code VARCHAR(50) DEFAULT '' COMMENT '问题域编码(仅C类)',
-  journey_stage INT DEFAULT 0 COMMENT '旅程阶段 0-7',
-  stage_updated_at DATETIME DEFAULT NULL COMMENT '最近阶段变化时间',
-  survey_template_id BIGINT DEFAULT NULL COMMENT '最近作答问卷模板ID',
-  survey_submitted_at DATETIME DEFAULT NULL COMMENT '最近问卷提交时间',
-  survey_result_json TEXT COMMENT '问卷答案→推荐结果快照',
-  skip_count INT DEFAULT 0 COMMENT '跳过意图问卷次数',
-  last_skip_at DATETIME DEFAULT NULL COMMENT '最近一次跳过意图问卷时间',
-  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  UNIQUE KEY uk_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户意图与服务旅程(改版v1)';
-
-CREATE TABLE IF NOT EXISTS user_notifications (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  user_id BIGINT NOT NULL COMMENT '接收用户ID',
-  type VARCHAR(30) DEFAULT 'report_ready' COMMENT 'report_ready/reward_granted/logistics/system/energy_change/points_change/cf_change',
-  title VARCHAR(200) NOT NULL,
-  content VARCHAR(1000) DEFAULT '',
-  ref_type VARCHAR(30) DEFAULT '' COMMENT '关联对象类型: report/package/task',
-  ref_id BIGINT DEFAULT NULL COMMENT '关联对象ID',
-  is_read TINYINT DEFAULT 0,
-  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  INDEX idx_user_read (user_id, is_read)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内通知(改版v1)';
-
--- 通知模板(迁移245 W3)
-CREATE TABLE IF NOT EXISTS notification_templates (
-  id BIGINT AUTO_INCREMENT PRIMARY KEY,
-  type VARCHAR(30) NOT NULL COMMENT '通知类型: report_ready/reward_granted/system',
-  title VARCHAR(200) NOT NULL COMMENT '默认标题(支持占位符)',
-  content VARCHAR(1000) NOT NULL COMMENT '默认内容模板(支持占位符)',
-  channels VARCHAR(100) DEFAULT 'in_app' COMMENT '推送通道: in_app,sms,wechat,gzh,phone 逗号分隔',
-  status TINYINT DEFAULT 1 COMMENT '1启用 0停用',
-  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-  updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  UNIQUE KEY uk_type (type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通知模板(改版v1 W3)';
-
--- 当前状态调研-健康现状档案(迁移239)
-CREATE TABLE IF NOT EXISTS health_status (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '所属账号',
-    member_id BIGINT DEFAULT NULL COMMENT '家庭成员ID(NULL=账号级,非空=成员级归档)',
-    height_cm DECIMAL(5,1) DEFAULT NULL COMMENT '身高(cm)',
-    weight_kg DECIMAL(5,1) DEFAULT NULL COMMENT '体重(kg)',
-    blood_pressure VARCHAR(20) DEFAULT NULL COMMENT '血压,如 120/80',
-    blood_glucose DECIMAL(4,1) DEFAULT NULL COMMENT '空腹血糖(mmol/L)',
-    blood_lipids JSON DEFAULT NULL COMMENT '血脂 [{name,value,unit,note}]',
-    disease_history JSON DEFAULT NULL COMMENT '疾病史 [{name,note}]',
-    medications JSON DEFAULT NULL COMMENT '在服药物/治疗 [{name,note}]',
-    notes VARCHAR(500) DEFAULT NULL COMMENT '其他补充说明',
-    filled_at DATETIME DEFAULT NULL COMMENT '首次填写时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_user_member (user_id, member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='当前状态调研-健康现状档案';
-
--- 系统提示词管理表(cfc-web 后台可维护,langgraph 动态加载)
-CREATE TABLE IF NOT EXISTS system_prompts (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    prompt_key VARCHAR(64) NOT NULL COMMENT '提示词键(如 health_coach/analysis/chat)',
-    title VARCHAR(100) NOT NULL COMMENT '提示词标题',
-    content TEXT NOT NULL COMMENT '提示词内容',
-    default_content TEXT COMMENT '出厂默认内容(重置时恢复)',
-    version INT NOT NULL DEFAULT 1 COMMENT '版本号',
-    status TINYINT NOT NULL DEFAULT 1 COMMENT '1=启用 0=禁用',
-    remark VARCHAR(255) COMMENT '备注',
-    updated_by VARCHAR(64) COMMENT '更新人',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_prompt_key (prompt_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统提示词管理';
--- 系统提示词版本历史表(版本管理:修改前自动备份,支持回滚)
-CREATE TABLE IF NOT EXISTS system_prompt_versions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    prompt_key VARCHAR(64) NOT NULL COMMENT '提示词键',
-    version INT NOT NULL COMMENT '版本号',
-    title VARCHAR(100) NOT NULL COMMENT '提示词标题',
-    content TEXT NOT NULL COMMENT '提示词内容',
-    operator VARCHAR(100) COMMENT '操作人',
-    remark VARCHAR(500) COMMENT '变更说明',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_prompt_key (prompt_key),
-    INDEX idx_version (prompt_key, version)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='系统提示词版本历史';
--- 套餐商品组成明细表(套餐 = 商品 productType=bundle,子商品在 product_bundle_items 中配置)
-CREATE TABLE IF NOT EXISTS product_bundle_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    bundle_product_id BIGINT NOT NULL COMMENT '套餐商品ID',
-    child_product_id BIGINT NOT NULL COMMENT '子商品ID',
-    child_sku_id BIGINT DEFAULT NULL COMMENT '子SKU ID(为空时直接扣 product.stock)',
-    quantity INT NOT NULL DEFAULT 1 COMMENT '子商品数量',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_bundle (bundle_product_id),
-    INDEX idx_child (child_product_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='套餐商品组成明细';
-
--- 联系人表(cfclub 联系人管理)
-CREATE TABLE IF NOT EXISTS contacts (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    name VARCHAR(100) NOT NULL COMMENT '姓名',
-    phone VARCHAR(20) COMMENT '电话',
-    avatar VARCHAR(500) COMMENT '头像',
-    relationship_type VARCHAR(20) COMMENT '关系类型: family/friend/partner/colleague/other',
-    known_since DATETIME COMMENT '认识时间',
-    bio VARCHAR(500) COMMENT '简介',
-    birthday DATE COMMENT '生日',
-    intimacy_level INT DEFAULT 0 COMMENT '亲密度(0-100)',
-    contact_source VARCHAR(20) DEFAULT 'manual' COMMENT '来源: phone/manual',
-    tags VARCHAR(500) COMMENT '标签(逗号分隔)',
-    last_contact_at DATETIME COMMENT '最近联系时间',
-    contact_count INT DEFAULT 0 COMMENT '联系次数',
-    notes TEXT COMMENT '备注',
-    created_at DATETIME,
-    updated_at DATETIME,
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='联系人表';
-
--- 联系人帮助记录表(章鱼图数据源)
-CREATE TABLE IF NOT EXISTS contact_help_logs (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '被帮助者(当前用户)',
-    contact_id BIGINT NOT NULL COMMENT '帮助者(联系人)',
-    help_type VARCHAR(32) COMMENT '帮助类型: MONEY/ITEM/EMOTION/RESOURCE/SKILL/TIME',
-    amount DECIMAL(10,2) DEFAULT 0 COMMENT '帮助金额(非金钱类为0)',
-    description VARCHAR(255) COMMENT '帮助内容简述',
-    happened_at DATETIME COMMENT '帮助发生时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_chl_user (user_id),
-    INDEX idx_chl_contact (contact_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='联系人帮助记录(章鱼图数据源)';
-
--- 珍珠图资源登记表(社会连接资源)
-CREATE TABLE IF NOT EXISTS resource_items (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '资源拥有者(当前用户)',
-    type VARCHAR(16) NOT NULL COMMENT '资源类型: INFO(信息)/PLACE(场所)/SKILL(技能)',
-    connection_type VARCHAR(50) NOT NULL DEFAULT '' COMMENT '连接类型枚举名(ConnectionType)',
-    priority TINYINT DEFAULT 2 COMMENT '优先级: 1=高 2=中 3=低(手动覆盖)',
-    value_score INT DEFAULT 0 COMMENT '价值分 0-100(自动计算,可手动覆盖)',
-    last_interaction_at DATETIME DEFAULT NULL COMMENT '最近互动时间',
-    interaction_count INT DEFAULT 0 COMMENT '互动总次数',
-    name VARCHAR(100) NOT NULL COMMENT '资源名称',
-    description VARCHAR(255) COMMENT '资源描述(可调用方式/说明)',
-    contact_id BIGINT DEFAULT NULL COMMENT '关联联系人ID(可选)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_ri_user (user_id),
-    INDEX idx_ri_connection_type (connection_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图资源登记表(社会连接资源)';
-
--- 关键人拓展-成效记录
-CREATE TABLE IF NOT EXISTS octopus_effect_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '当前用户(租户键)',
-    member_order_id BIGINT COMMENT '关联 MemberSubscriptionOrder.id(会员订单)',
-    effect_type TINYINT UNSIGNED NOT NULL COMMENT '成效类型 bitmask:1=金额大,2=频次高,4=新成交(支持多选)',
-    effect_amount DECIMAL(10,2) DEFAULT 0 COMMENT '成效金额(元)',
-    effect_desc VARCHAR(500) COMMENT '成效描述',
-    status TINYINT DEFAULT 1 COMMENT '1=有效,0=无效',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    happened_at DATETIME COMMENT '成效发生时间',
-    INDEX idx_oer_user (user_id),
-    INDEX idx_oer_order (member_order_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关键人拓展-成效记录';
-
--- 关键人画像
-CREATE TABLE IF NOT EXISTS octopus_key_person (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '当前用户(租户键)',
-    name VARCHAR(64) NOT NULL COMMENT '关键人姓名',
-    organization VARCHAR(128) COMMENT '单位/公司',
-    department VARCHAR(64) COMMENT '部门',
-    title VARCHAR(64) COMMENT '职务/职位',
-    first_meet_scene VARCHAR(128) COMMENT '初识场合',
-    know_way VARCHAR(255) COMMENT '如何认识(认识路径)',
-    contact_info VARCHAR(255) COMMENT '联系方式(可选)',
-    first_meet_time DATETIME DEFAULT NULL COMMENT '相识具体时间',
-    referrer_id BIGINT DEFAULT NULL COMMENT '介绍人关键人ID(指向同用户另一条关键人)',
-    system_user_id BIGINT DEFAULT NULL COMMENT '匹配到的系统用户ID(如有)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_okp_user (user_id),
-    INDEX idx_okp_org (organization)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关键人画像';
-
--- 成效-关键人关联
-CREATE TABLE IF NOT EXISTS octopus_effect_key_person (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    effect_id BIGINT NOT NULL COMMENT '关联 octopus_effect_record.id',
-    key_person_id BIGINT NOT NULL COMMENT '关联 octopus_key_person.id',
-    role TINYINT NOT NULL COMMENT '1=引荐,2=决策,3=其他',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_oekp_effect (effect_id),
-    INDEX idx_oekp_person (key_person_id),
-    UNIQUE KEY uk_oekp (effect_id,key_person_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='成效-关键人关联';
-
--- 维度配置表(cfclub 五维能量体系)
-CREATE TABLE IF NOT EXISTS product_dimension_config (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    dimension_code VARCHAR(50) NOT NULL UNIQUE COMMENT '维度代码: body/mind/wisdom/action/wealth',
-    dimension_name VARCHAR(100) NOT NULL COMMENT '维度名称',
-    dimension_type VARCHAR(50) NOT NULL DEFAULT 'five' COMMENT '类型: five(五维)/action(行动)/other',
-    parent_id BIGINT COMMENT '父级ID,无父级为NULL',
-    sort INT DEFAULT 0 COMMENT '排序',
-    enabled TINYINT(1) DEFAULT 1 COMMENT '启用: 0禁用 1启用',
-    dify_dataset_id VARCHAR(100) COMMENT 'Dify Dataset ID,不填则不同步',
-    remark VARCHAR(500) COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='维度配置表';
-
--- 知识库表
-CREATE TABLE IF NOT EXISTS dan_knowledge_base (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    title VARCHAR(200) NOT NULL COMMENT '知识标题',
-    content MEDIUMTEXT NOT NULL COMMENT '知识内容',
-    sort INT DEFAULT 0 COMMENT '排序',
-    status TINYINT(1) DEFAULT 1 COMMENT '状态: 0禁用 1启用',
-    remark VARCHAR(500) COMMENT '备注',
-    file_url VARCHAR(500) COMMENT 'fileUrl',
-    file_name VARCHAR(255) COMMENT 'fileName',
-    source_url VARCHAR(500) COMMENT 'sourceUrl',
-    source_type VARCHAR(20) COMMENT 'sourceType',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库表';
-
--- 标签表
-CREATE TABLE IF NOT EXISTS dan_knowledge_tag (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    tag_name VARCHAR(100) NOT NULL UNIQUE COMMENT '标签名',
-    tag_type VARCHAR(50) DEFAULT 'custom' COMMENT '标签类型: custom/auto',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='标签表';
-
--- 知识-维度关联表
-CREATE TABLE IF NOT EXISTS dan_knowledge_base_dimension (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    knowledge_id BIGINT NOT NULL COMMENT '知识库ID',
-    dimension_id BIGINT NOT NULL COMMENT '维度配置ID',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_knowledge_dimension (knowledge_id, dimension_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识-维度关联表';
-
--- 知识-标签关联表
-CREATE TABLE IF NOT EXISTS dan_knowledge_base_tag (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    knowledge_id BIGINT NOT NULL,
-    tag_id BIGINT NOT NULL,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_knowledge_tag (knowledge_id, tag_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识-标签关联表';
-
--- 用户画像最新快照表
-CREATE TABLE IF NOT EXISTS profile_snapshot (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    member_id BIGINT NOT NULL UNIQUE COMMENT '家庭成员ID',
-    dimension_scores JSON DEFAULT NULL COMMENT '五维能力评分',
-    body_metrics JSON DEFAULT NULL COMMENT '近30天身体指标',
-    mind_metrics JSON DEFAULT NULL COMMENT '近30天心理指标',
-    wisdom_metrics JSON DEFAULT NULL COMMENT '最近测评成绩',
-    action_metrics JSON DEFAULT NULL COMMENT '近7天行为指标',
-    wealth_metrics JSON DEFAULT NULL COMMENT '近30天财商指标',
-    problem_domains VARCHAR(500) DEFAULT NULL COMMENT '关注的问题域标签',
-    quiz_summary JSON DEFAULT NULL COMMENT '答题认知雷达汇总',
-    computed_at DATETIME DEFAULT NULL COMMENT '最后一次计算时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_member_id (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户画像最新快照';
-
--- 画像历史表(保留365天)
-CREATE TABLE IF NOT EXISTS profile_history (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    snapshot_date DATE NOT NULL COMMENT '日期',
-    all_metrics JSON NOT NULL COMMENT '当日所有指标完整快照',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_member_date (member_id, snapshot_date),
-    INDEX idx_date (snapshot_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户画像历史快照';
-
--- 健康启航计划购买订单表
-CREATE TABLE IF NOT EXISTS purchase_orders (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    order_no VARCHAR(64) NOT NULL UNIQUE,
-    user_id BIGINT NOT NULL,
-    family_id BIGINT NOT NULL,
-    amount INT NOT NULL,
-    status VARCHAR(20) DEFAULT 'pending',
-    payment_method VARCHAR(20),
-    transaction_id VARCHAR(64),
-    start_date DATETIME NOT NULL,
-    end_date DATETIME NOT NULL,
-    is_early_renewal TINYINT DEFAULT 0,
-    cf_reward_given INT DEFAULT 0,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    paid_at DATETIME,
-    INDEX idx_user_id (user_id),
-    INDEX idx_family_id (family_id),
-    INDEX idx_order_no (order_no)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- 闯关任务进度表
-CREATE TABLE IF NOT EXISTS challenge_progress (
-    id BIGINT PRIMARY KEY AUTO_INCREMENT,
-    purchase_id BIGINT NOT NULL,
-    member_id BIGINT NOT NULL,
-    week_num INT NOT NULL,
-    task_type VARCHAR(50) NOT NULL,
-    task_key VARCHAR(100) NOT NULL,
-    task_title VARCHAR(255) NOT NULL,
-    target_value INT DEFAULT 0,
-    current_value INT DEFAULT 0,
-    reward_cf INT DEFAULT 0,
-    status VARCHAR(20) DEFAULT 'pending',
-    completed_at DATETIME,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_purchase_id (purchase_id),
-    INDEX idx_member_id (member_id),
-    UNIQUE KEY uk_member_task (member_id, task_key, week_num)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-
--- =============================================
--- 先天画像体系(迁移270-272)
--- =============================================
-
--- 先天画像来源权重配置表
-CREATE TABLE IF NOT EXISTS innate_portrait_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    source_type VARCHAR(20) NOT NULL COMMENT '来源: zodiac/bazi/blood/numsoul',
-    source_name VARCHAR(50) NOT NULL COMMENT '来源名称',
-    weight INT DEFAULT 25 COMMENT '权重(基点,2500=25%)',
-    enabled TINYINT(1) DEFAULT 1 COMMENT '是否启用',
-    ai_enabled TINYINT(1) DEFAULT 1 COMMENT '是否启用AI解读',
-    sort_order INT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_source (source_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='先天画像来源权重配置';
-
--- 先天画像报告缓存表
-CREATE TABLE IF NOT EXISTS innate_portrait_report (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '成员ID',
-    member_type VARCHAR(10) NOT NULL COMMENT '成员类型: child/parent',
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    portrait_json TEXT COMMENT '先天画像数据JSON',
-    ai_reading TEXT COMMENT 'AI解读文案',
-    generated_at DATETIME COMMENT '生成时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_member (member_id, member_type)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='先天画像报告缓存';
-
--- 数字能量详细配置表
-CREATE TABLE IF NOT EXISTS numsoul_detail_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    number_type VARCHAR(20) NOT NULL COMMENT '类型: life_path/talent/birthday/destiny',
-    number_value INT NOT NULL COMMENT '数字值 1-9 或主数 11/22/33',
-    title VARCHAR(50) COMMENT '称号',
-    keywords VARCHAR(200) COMMENT '性格关键词',
-    mind_base INT DEFAULT 0 COMMENT '心先天基础分(百分位)',
-    mind_advice TEXT COMMENT '心维度成长建议',
-    color_hex VARCHAR(10) COMMENT '代表色',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_type_num (number_type, number_value)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数字能量详细配置';
-
--- ============================================================
--- 五维自检忽略提醒记录表(迁移277)
--- ============================================================
-CREATE TABLE IF NOT EXISTS self_check_ignores (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    check_id BIGINT COMMENT '忽略的自检记录ID(可空)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '忽略时间',
-    INDEX idx_user_id (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维自检忽略提醒记录';
-
--- ============================================================
--- CF值分佣体系重构(迁移279-282)
--- ============================================================
-
--- CF值返佣阶梯配置表(迁移279,替代 promotion_tier_config)
-CREATE TABLE IF NOT EXISTS cf_rate_tier (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    tier_name VARCHAR(50) NOT NULL COMMENT '档位名称',
-    min_team_size INT NOT NULL DEFAULT 0 COMMENT '团队规模下限(含)',
-    rate_percent INT NOT NULL DEFAULT 0 COMMENT '返佣比例(%)',
-    sort_order INT NOT NULL DEFAULT 0 COMMENT '排序,越大越高',
-    enabled TINYINT DEFAULT 1 COMMENT '1启用/0停用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_min_size (min_team_size)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值返佣阶梯配置';
-
--- CF值流转记录表(迁移280)
-CREATE TABLE IF NOT EXISTS cf_transfer_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    from_user_id BIGINT COMMENT '转出用户ID(null=平台)',
-    to_user_id BIGINT COMMENT '转入用户ID',
-    family_id BIGINT COMMENT '所属家庭ID',
-    amount INT NOT NULL COMMENT 'CF值数量',
-    type VARCHAR(16) NOT NULL COMMENT 'transfer/allocate/refund',
-    ref_type VARCHAR(50) COMMENT '关联业务类型',
-    ref_id BIGINT COMMENT '关联业务ID',
-    remark VARCHAR(255),
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_from (from_user_id),
-    INDEX idx_to (to_user_id),
-    INDEX idx_family (family_id),
-    UNIQUE KEY uk_ref_type_id (ref_type, ref_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流转记录';
-
--- 五维基础能量分表(迁移305)
-CREATE TABLE IF NOT EXISTS family_member_dimension_base_scores (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    member_id BIGINT NULL COMMENT '家庭成员ID',
-    member_type VARCHAR(20) NOT NULL COMMENT '成员类型: child/parent',
-    dimension_code VARCHAR(20) NOT NULL COMMENT '维度: body/mind/wisdom/action/wealth',
-    base_score INT NOT NULL COMMENT '基础能量分(0-100)',
-    last_calculated_at DATETIME NOT NULL COMMENT '最后计算时间',
-    calculated_by VARCHAR(50) DEFAULT 'system' COMMENT '计算来源(system/manual)',
-    UNIQUE KEY uk_member_dimension (member_id, dimension_code),
-    INDEX idx_member (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维基础能量分(落库,支持重算)';
-
--- 珍珠图互动日志表
-CREATE TABLE IF NOT EXISTS pearl_interaction_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '操作人',
-    resource_item_id BIGINT NOT NULL COMMENT '关联资源',
-    interaction_type VARCHAR(20) NOT NULL COMMENT 'PHONE/WECHAT/MEETING/OTHER',
-    content VARCHAR(500) DEFAULT NULL COMMENT '互动内容简记',
-    happened_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '互动发生时间',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    INDEX idx_pil_user (user_id),
-    INDEX idx_pil_resource (resource_item_id),
-    INDEX idx_pil_happened (happened_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动日志';
-
--- 珍珠图互动提醒表
-CREATE TABLE IF NOT EXISTS pearl_interaction_reminder (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL,
-    resource_item_id BIGINT NOT NULL,
-    connection_type VARCHAR(50) NOT NULL,
-    suggest_interval_month INT NOT NULL COMMENT '建议互动周期(月)',
-    last_interaction_at DATETIME DEFAULT NULL,
-    days_since_last INT NOT NULL COMMENT '距上次互动天数',
-    status VARCHAR(20) DEFAULT 'PENDING' COMMENT 'PENDING/DONE/DISMISSED',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_pir_user_status (user_id, status),
-    INDEX idx_pir_resource (resource_item_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='珍珠图互动提醒';
-
--- ============================================================
--- BASIC 体验会员(迁移360 恢复,对应提交 f86dd164b 的反向还原)
--- ============================================================
-
-INSERT IGNORE INTO membership_levels
-(level_code, level_name, level_desc, price_monthly, features, max_children, max_tasks_per_day)
-VALUES (
-    'BASIC',
-    '体验会员',
-    '9.9元/月体验版,解锁核心功能,限次使用AI与报告解读',
-    990,
-    '["free_activities","free_courses","discount_purchase","invite_family","mascot_ai_lite","ai_report_reading_lite","assessment_quota_lite","health_report_upload_lite","growth_plan_lite","task_template_lite","referral_commission"]',
-    3,
-    3
-);
-
-INSERT IGNORE INTO membership_benefits (level_code, benefit_code, benefit_name, benefit_desc, icon, bg_color, sort_order) VALUES
-('BASIC', 'AI_CHAT_LITE', 'AI健康顾问(限3次/月)', '每月3次AI健康顾问问答', '🤖', '#DBEAFE', 1),
-('BASIC', 'REPORT_READING_LITE', '报告解读(限1次/月)', '每月1次体检/测评报告AI解读', '📊', '#FCE7F3', 4),
-('BASIC', 'GROWTH_PLAN_LITE', '基础成长计划', '创建成长计划但模板有限', '📋', '#FEF3C7', 3),
-('BASIC', 'ASSESSMENT_QUOTA_LITE', '测评预约(限1次)', '每月可预约1次测试', '📅', '#E0E7FF', 8);
-
--- ============================================================
-
-CREATE TABLE IF NOT EXISTS basic_quota_usage (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '家长用户ID(非family_id)',
-    quota_type VARCHAR(30) NOT NULL COMMENT '配额类型: AI_CHAT/REPORT_READING/ASSESSMENT_QUOTA/FOOD_RECOGNIZE',
-    used_count INT DEFAULT 0 COMMENT '本月已用次数',
-    total_count INT NOT NULL COMMENT '月度总配额',
-    period_start DATE NOT NULL COMMENT '周期开始日期(每月1号)',
-    period_end DATE NOT NULL COMMENT '周期结束日期(月末)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_user_type_period (user_id, quota_type, period_start),
-    INDEX idx_user_period (user_id, period_start)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='月度配额使用记录';
-
--- 菌群健康调研项目(单次付费问卷)
-CREATE TABLE IF NOT EXISTS gut_health_projects (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '购买用户ID',
-    family_id BIGINT COMMENT '关联家庭ID',
-    member_id BIGINT COMMENT '测评对象(家庭成员ID)',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/paused/completed',
-    questions JSON COMMENT '本次问卷题目+答案JSON',
-    health_recommendations JSON COMMENT 'AI生成的健康建议',
-    risk_scores JSON COMMENT '各维度风险评分(0-100)',
-    microbe_test_recommended TINYINT DEFAULT 0 COMMENT '是否推荐菌群检测',
-    paid_at DATETIME COMMENT '付费时间',
-    completed_at DATETIME COMMENT '完成时间',
-    -- 新增字段:问卷完成后的奖励资格
-    member_discount_qualified TINYINT DEFAULT 0 COMMENT '是否获得会员价购买菌群检测资格',
-    family_membership_qualified TINYINT DEFAULT 0 COMMENT '是否获得一年家庭会员资格',
-    family_membership_activated TINYINT DEFAULT 0 COMMENT '是否已激活家庭会员',
-    -- 新增字段:打卡任务系统
-    cf_refund_amount INT DEFAULT 0 COMMENT 'CF值返还金额(分),19.9元=1990分',
-    cf_refunded TINYINT DEFAULT 0 COMMENT 'CF值是否已返还',
-    completed_tasks_count INT DEFAULT 0 COMMENT '已完成任务数/总任务数',
-    action_tasks JSON COMMENT 'AI生成的一周行动任务列表',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_user_created (user_id, created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菌群健康调研项目';
-
--- DOA 个人目标-周计划-周复盘(迁移318,家庭打卡个人目标模块)
--- ============================================================
-CREATE TABLE IF NOT EXISTS doa_stage (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    family_id BIGINT NOT NULL COMMENT '家庭ID',
-    member_id BIGINT NULL COMMENT '目标归属成员ID(family_members.id)',
-    title VARCHAR(200) COMMENT '阶段主题(可选)',
-    start_date DATE NOT NULL COMMENT '阶段开始日期',
-    end_date DATE NOT NULL COMMENT '阶段结束日期',
-    duration_weeks TINYINT NOT NULL COMMENT '周期周数:2/4/8/12',
-    status VARCHAR(20) DEFAULT 'active' COMMENT 'active/completed/cancelled',
-    created_by BIGINT NOT NULL COMMENT '创建人userId(代管时为代管人)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_ds_family_member (family_id, member_id),
-    INDEX idx_ds_status (status)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 阶段';
-
-CREATE TABLE IF NOT EXISTS doa_goal (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    stage_id BIGINT NOT NULL COMMENT '所属阶段ID',
-    domain VARCHAR(20) NOT NULL COMMENT '领域:health/wealth/family/social/help',
-    content VARCHAR(500) NOT NULL COMMENT '量化目标内容',
-    status VARCHAR(20) DEFAULT 'active' COMMENT 'active/achieved/abandoned',
-    sort_order TINYINT DEFAULT 0 COMMENT '排序',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_dg_stage (stage_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 阶段目标';
-
-CREATE TABLE IF NOT EXISTS doa_week (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    stage_id BIGINT NOT NULL COMMENT '所属阶段ID',
-    week_no TINYINT NOT NULL COMMENT '第几周(1起)',
-    week_start DATE NOT NULL COMMENT '本周开始(周一)',
-    week_end DATE NOT NULL COMMENT '本周结束(周日)',
-    plan TEXT COMMENT '周行动宣告计划(A表)',
-    achieved TEXT COMMENT '复盘:本周达成了什么',
-    experience TEXT COMMENT '复盘:有什么体验',
-    worked TEXT COMMENT '复盘:行得通的',
-    improve TEXT COMMENT '复盘:要提升/行不通的',
-    next_challenge TEXT COMMENT '复盘:下周挑战自己什么',
-    status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/planned/reviewed',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_dw_stage_week (stage_id, week_no),
-    INDEX idx_dw_stage (stage_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='DOA 周记录';
-
-CREATE TABLE IF NOT EXISTS shop_discount_rules (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
-    name VARCHAR(64) NOT NULL COMMENT '规则名称',
-    type VARCHAR(32) NOT NULL COMMENT '类型: PERCENT/FIXED/THRESHOLD',
-    value INT NOT NULL COMMENT '折扣值(PERCENT=百分比数字, FIXED/THRESHOLD=减免金额分)',
-    threshold_amount INT COMMENT '满减门槛(分,仅THRESHOLD)',
-    category_id BIGINT COMMENT '适用类目ID(null=全部)',
-    distribution_system_id BIGINT COMMENT '适用体系ID(null=全部)',
-    product_ids TEXT COMMENT '适用商品ID(逗号分隔,null=全部)',
-    start_time DATETIME COMMENT '开始时间',
-    end_time DATETIME COMMENT '结束时间',
-    max_uses INT DEFAULT 0 COMMENT '最大使用次数(0=不限)',
-    used_count INT DEFAULT 0 COMMENT '已使用次数',
-    enabled TINYINT(1) DEFAULT 1 COMMENT '启用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    INDEX idx_category (category_id),
-    INDEX idx_enabled (enabled),
-    INDEX idx_distribution (distribution_system_id),
-    INDEX idx_end_time (end_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='限时折扣规则表';
-
--- 首页快捷方式自定义配置(每应用一条记录,locked=置顶)
-CREATE TABLE IF NOT EXISTS user_shortcut_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    app_key VARCHAR(64) NOT NULL COMMENT '应用key',
-    locked TINYINT DEFAULT 0 COMMENT '是否锁定置顶(1=锁定,0=普通)',
-    sort_order INT DEFAULT 0 COMMENT '手动排序序号',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_user_app (user_id, app_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页快捷方式自定义配置';
-
--- 应用使用频度记录
-CREATE TABLE IF NOT EXISTS user_app_usage (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '用户ID',
-    app_key VARCHAR(64) NOT NULL COMMENT '应用key',
-    enter_count INT DEFAULT 0 COMMENT '累计进入次数',
-    last_enter_at DATETIME COMMENT '最近进入时间',
-    UNIQUE KEY uk_user_app (user_id, app_key)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用使用频度记录';
--- ===== 任务编排系统(task orchestration)=====
-
-CREATE TABLE IF NOT EXISTS `task_orchestration_flows` (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `name` varchar(100) NOT NULL,
-  `description` text,
-  `creator_id` bigint NOT NULL,
-  `family_id` bigint DEFAULT NULL,
-  `version` int NOT NULL DEFAULT 1,
-  `status` varchar(20) NOT NULL DEFAULT 'draft',
-  `schedule_cron` varchar(64) DEFAULT NULL,
-  `config_json` json DEFAULT NULL,
-  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  KEY `idx_family_id` (`family_id`),
-  KEY `idx_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流定义';
-
-CREATE TABLE IF NOT EXISTS `task_orchestration_edges` (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `flow_id` bigint NOT NULL,
-  `from_node_id` varchar(64) NOT NULL,
-  `to_node_id` varchar(64) NOT NULL,
-  `edge_type` varchar(20) NOT NULL,
-  `operator` varchar(10) NOT NULL DEFAULT 'AND',
-  `sort_order` int NOT NULL DEFAULT 0,
-  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  KEY `idx_flow_id` (`flow_id`),
-  UNIQUE KEY `uk_flow_edge` (`flow_id`, `from_node_id`, `to_node_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流边定义';
-
-CREATE TABLE IF NOT EXISTS `task_orchestration_executions` (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `flow_id` bigint NOT NULL,
-  `flow_version` int NOT NULL DEFAULT 1,
-  `family_id` bigint NOT NULL,
-  `family_member_id` bigint NOT NULL,
-  `trigger_source` varchar(20) NOT NULL DEFAULT 'manual',
-  `status` varchar(20) NOT NULL DEFAULT 'running',
-  `started_at` datetime NOT NULL,
-  `finished_at` datetime DEFAULT NULL,
-  `error_reason` varchar(255) DEFAULT NULL,
-  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  KEY `idx_execution_flow` (`flow_id`),
-  KEY `idx_execution_status` (`status`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流执行记录';
-
-CREATE TABLE IF NOT EXISTS `task_orchestration_node_instances` (
-  `id` bigint NOT NULL AUTO_INCREMENT,
-  `execution_id` bigint NOT NULL,
-  `node_id` varchar(64) NOT NULL,
-  `task_id` bigint DEFAULT NULL,
-  `status` varchar(20) NOT NULL DEFAULT 'pending',
-  `generation` int NOT NULL DEFAULT 0,
-  `condition_met_at` datetime DEFAULT NULL COMMENT '条件终止:外部API通知条件达成时间',
-  `loop_termination_reason` varchar(50) DEFAULT NULL,
-  `started_at` datetime DEFAULT NULL,
-  `completed_at` datetime DEFAULT NULL,
-  `error_reason` varchar(255) DEFAULT NULL,
-  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`),
-  UNIQUE KEY `uk_node_instance` (`execution_id`, `node_id`, `generation`),
-  KEY `idx_execution_id` (`execution_id`),
-  KEY `idx_task_id` (`task_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务编排流节点实例';
--- 报告反馈与AI解答(迁移327)
--- ============================================================
-CREATE TABLE IF NOT EXISTS report_feedback (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    user_id BIGINT NOT NULL COMMENT '提交人 users.id',
-    member_id BIGINT DEFAULT NULL COMMENT '关联家庭成员 family_members.id',
-    report_id BIGINT DEFAULT NULL COMMENT '健康报告ID',
-    draft_id BIGINT DEFAULT NULL COMMENT '草稿ID',
-    feedback_type VARCHAR(20) DEFAULT 'question' COMMENT 'question=疑问 / suggestion=建议',
-    content VARCHAR(500) NOT NULL COMMENT '反馈内容',
-    ai_answer TEXT COMMENT 'AI 解答',
-    ai_status VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/answered/failed',
-    conversation_id VARCHAR(64) DEFAULT NULL COMMENT 'AI 会话ID(付费多轮)',
-    created_at DATETIME NOT NULL COMMENT '创建时间',
-    INDEX idx_rf_user (user_id, created_at),
-    INDEX idx_rf_report (report_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='报告反馈与AI解答';
-
--- ============================================================
--- 引导弹窗配置化管理(迁移329-332)
--- ============================================================
-
--- 迁移329: 引导弹窗配置表
-CREATE TABLE IF NOT EXISTS guide_popup (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    slug VARCHAR(64) NOT NULL UNIQUE COMMENT '唯一标识',
-    title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '弹窗标题',
-    description TEXT COMMENT '主描述文案',
-    icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '图标:emoji或图片URL',
-    icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片',
-    theme_color VARCHAR(20) NOT NULL DEFAULT '#F97316' COMMENT '主题色',
-    btn_text VARCHAR(64) NOT NULL DEFAULT '知道了' COMMENT '按钮文案',
-    btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '点击跳转路径,空=关闭',
-    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0=禁用 1=启用',
-    sort_order INT NOT NULL DEFAULT 0 COMMENT '排序优先级',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_status_sort (status, sort_order)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗配置表';
-
--- 迁移330: 引导弹窗步骤表
-CREATE TABLE IF NOT EXISTS guide_popup_step (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id',
-    step_order INT NOT NULL DEFAULT 0 COMMENT '步骤顺序',
-    title VARCHAR(128) NOT NULL DEFAULT '' COMMENT '步骤标题',
-    `desc` TEXT COMMENT '步骤描述',
-    icon VARCHAR(256) NOT NULL DEFAULT '' COMMENT '步骤图标',
-    icon_type TINYINT NOT NULL DEFAULT 0 COMMENT '图标类型:0=emoji 1=图片',
-    is_intro TINYINT NOT NULL DEFAULT 0 COMMENT '是否为开场身份定义页',
-    btn_text VARCHAR(64) NOT NULL DEFAULT '下一步' COMMENT '本步骤按钮文案',
-    btn_action VARCHAR(256) NOT NULL DEFAULT '' COMMENT '最后一步跳转链接',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_popup_order (popup_id, step_order)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗步骤表';
-
--- 迁移331: 引导弹窗触发条件表
-CREATE TABLE IF NOT EXISTS guide_popup_trigger (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id',
-    trigger_type VARCHAR(32) NOT NULL COMMENT '触发类型:page_enter/task_complete/assessment_done/first_login/daily_active/role_change',
-    target_page VARCHAR(128) DEFAULT '' COMMENT '目标页面路径',
-    target_action VARCHAR(128) DEFAULT '' COMMENT '触发行为标识',
-    min_role VARCHAR(32) DEFAULT 'parent' COMMENT '最低角色要求',
-    extra_config JSON DEFAULT NULL COMMENT '扩展条件',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_popup_trigger (popup_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗触发条件表';
-
--- 迁移332: 引导弹窗用户消费记录表
-CREATE TABLE IF NOT EXISTS guide_popup_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    popup_id BIGINT NOT NULL COMMENT '关联 guide_popup.id',
-    user_id BIGINT NOT NULL COMMENT '用户ID users.id',
-    member_id BIGINT DEFAULT NULL COMMENT '家庭成员ID family_members.id',
-    role VARCHAR(32) NOT NULL COMMENT '弹出时所在角色',
-    consumed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '消费时间',
-    button_clicked TINYINT NOT NULL DEFAULT 0 COMMENT '是否点击按钮',
-    INDEX idx_user_popup (user_id, popup_id),
-    INDEX idx_consume_time (consumed_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='引导弹窗用户消费记录表';
-
--- 迁移340: 首页广告栏配置表
-CREATE TABLE IF NOT EXISTS home_banners (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    title VARCHAR(100) NOT NULL COMMENT '展示标题',
-    banner_type VARCHAR(20) NOT NULL COMMENT '类型: activity/product/link',
-    ref_id BIGINT DEFAULT NULL COMMENT '关联活动/商品ID(banner_type=activity/product时有效)',
-    cover_image VARCHAR(500) DEFAULT NULL COMMENT '封面图URL(可覆盖默认封面)',
-    link_url VARCHAR(500) DEFAULT NULL COMMENT '跳转链接(banner_type=link时有效)',
-    sort_order INT NOT NULL DEFAULT 0 COMMENT '排序,值越小越靠前',
-    enabled TINYINT NOT NULL DEFAULT 1 COMMENT '启用状态:1=启用 0=禁用',
-    start_time DATETIME DEFAULT NULL COMMENT '投放开始时间(NULL=不限)',
-    end_time DATETIME DEFAULT NULL COMMENT '投放结束时间(NULL=不限)',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='首页广告栏配置表';
-
--- 迁移344: 创建 supply_customer_relation 表(供应商团队客户归属记录)
-CREATE TABLE IF NOT EXISTS supply_customer_relation (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    system_id BIGINT NOT NULL COMMENT '供应商体系ID(supply_system.id)',
-    parent_user_id BIGINT NOT NULL COMMENT '上级供应商用户ID(supply_hierarchy.parent_id)',
-    family_id BIGINT NOT NULL COMMENT '客户家庭ID(family_members.family_id)',
-    child_user_id BIGINT DEFAULT NULL COMMENT '下单用户ID(users.id),可为空',
-    relation_type VARCHAR(32) NOT NULL DEFAULT 'family' COMMENT '归属类型: family=家庭归属 order=订单关联',
-    source VARCHAR(32) NOT NULL DEFAULT 'manual' COMMENT '来源: manual=人工绑定 order=下单自动 referral=推荐码',
-    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_system_family (system_id, family_id),
-    INDEX idx_parent_user (parent_user_id),
-    INDEX idx_family_id (family_id),
-    UNIQUE KEY uk_system_family (system_id, family_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='供应商团队客户归属关系表';
-
--- 迁移345: 商品维度关联表(product_dimension_mapping)
-CREATE TABLE IF NOT EXISTS product_dimension_mapping (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    product_id BIGINT NOT NULL COMMENT '商品ID(products.id)',
-    dimension_code VARCHAR(32) NOT NULL COMMENT '维度编码: body/wisdom/mind/action/wealth',
-    match_score INT DEFAULT 100 COMMENT '匹配度 0-100',
-    match_reason VARCHAR(200) COMMENT '匹配原因说明',
-    tags VARCHAR(500) COMMENT '推荐标签JSON',
-    enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_product_id (product_id),
-    INDEX idx_dimension (dimension_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品维度关联表';
-
--- 迁移346: 推荐曝光日志表(product_recommendation_log)
-CREATE TABLE IF NOT EXISTS product_recommendation_log (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT DEFAULT NULL COMMENT '用户ID(users.id)',
-    family_id BIGINT DEFAULT NULL COMMENT '家庭ID(family_members.family_id)',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    scene VARCHAR(32) NOT NULL COMMENT '场景: dimension_page/ai_chat/report_upload/repurchase',
-    reason VARCHAR(200) COMMENT '推荐理由',
-    match_score INT DEFAULT NULL COMMENT '匹配分',
-    was_clicked TINYINT DEFAULT 0 COMMENT '是否点击 1=是 0=否',
-    was_purchased TINYINT DEFAULT 0 COMMENT '是否购买 1=是 0=否',
-    clicked_at DATETIME DEFAULT NULL COMMENT '点击时间',
-    purchased_at DATETIME DEFAULT NULL COMMENT '购买时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    ab_test_group VARCHAR(32) DEFAULT NULL COMMENT 'AB测试分组(A/B/C/控制组)',
-    recommendation_type VARCHAR(32) DEFAULT NULL COMMENT '推荐来源类型:dimension/co_purchase/repurchase/profile_gap/manual',
-    INDEX idx_user_scene (user_id, scene),
-    INDEX idx_product_purchased (product_id, was_purchased)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推荐曝光日志表';
-
--- 迁移347a: 复购提醒记录表(repurchase_reminder_record)
-CREATE TABLE IF NOT EXISTS repurchase_reminder_record (
+-- 迁移354: 用户内容偏好权重表(user_content_weights)
+CREATE TABLE IF NOT EXISTS user_content_weights (
     id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
     user_id BIGINT NOT NULL COMMENT '用户ID(users.id)',
-    product_id BIGINT NOT NULL COMMENT '商品ID',
-    order_id BIGINT DEFAULT NULL COMMENT '关联订单ID',
-    reminder_days INT DEFAULT 30 COMMENT '提醒天数',
-    sent_at DATETIME DEFAULT NULL COMMENT '发送时间',
-    clicked TINYINT DEFAULT 0 COMMENT '是否点击 1=是 0=否',
-    purchased TINYINT DEFAULT 0 COMMENT '是否购买 1=是 0=否',
-    INDEX idx_user_pending (user_id, purchased)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='复购提醒记录表';
-
--- 迁移347b: 复购提醒配置表(repurchase_reminder_config)
-CREATE TABLE IF NOT EXISTS repurchase_reminder_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    product_category VARCHAR(100) DEFAULT NULL COMMENT '商品类目',
-    product_id BIGINT DEFAULT NULL COMMENT '特定商品ID(优先于category)',
-    reminder_days INT DEFAULT 30 COMMENT '提醒天数',
-    reminder_template VARCHAR(500) DEFAULT NULL COMMENT '提醒话术模板',
-    max_reminders INT DEFAULT 3 COMMENT '最大提醒次数',
-    enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='复购提醒配置表';
-
--- 迁移348: 商品推荐关联关系表(recommendation_product_associations)
-CREATE TABLE IF NOT EXISTS recommendation_product_associations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    source_product_id BIGINT NOT NULL COMMENT '源商品ID(已购/关注商品)',
-    target_product_id BIGINT NOT NULL COMMENT '目标商品ID(被推荐商品)',
-    association_type VARCHAR(32) NOT NULL COMMENT '类型: co_purchase/repurchase/profile_gap/manual',
-    strength DECIMAL(5,2) DEFAULT 0.50 COMMENT '关联强度 0.00-1.00',
-    manual_override TINYINT DEFAULT 0 COMMENT '是否运营手动覆盖 1=是 0=否',
-    reason VARCHAR(500) DEFAULT NULL COMMENT '关联原因说明',
-    dimension_code VARCHAR(32) DEFAULT NULL COMMENT '关联维度(body/mind/wisdom/action/wealth)',
-    repurchase_days INT DEFAULT NULL COMMENT '复购周期天数(repurchase场景)',
-    co_purchase_window_days INT DEFAULT 30 COMMENT '共购时间窗口天数(co_purchase场景)',
-    co_purchase_count INT DEFAULT 0 COMMENT '共购次数(co_purchase场景自动累计)',
-    enabled TINYINT DEFAULT 1 COMMENT '启用状态 1=启用 0=禁用',
-    created_by BIGINT DEFAULT NULL COMMENT '创建人用户ID(manual场景记录运营)',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_source_target (source_product_id, target_product_id),
-    INDEX idx_type_enabled (association_type, enabled),
-    INDEX idx_dimension (dimension_code)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品推荐关联关系表';
-
--- 迁移353: 任务提醒配置表(用户级,一行/用户)
-CREATE TABLE IF NOT EXISTS task_reminder_config (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    user_id BIGINT NOT NULL COMMENT '用户ID(users.id),家长账号',
-    channels VARCHAR(100) DEFAULT 'wechat' COMMENT '提醒渠道(逗号分隔): in_app/wechat/sms/phone/email',
-    timing_mode VARCHAR(20) DEFAULT 'after_timeout' COMMENT '提醒时机: before_deadline=截止前提醒 after_timeout=超时后提醒',
-    offset_minutes INT DEFAULT 60 COMMENT '偏移分钟: before_deadline=截止前N分钟; after_timeout=超时后N分钟',
-    enabled TINYINT DEFAULT 1 COMMENT '是否启用 1=启用 0=停用',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    UNIQUE KEY uk_user (user_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='任务提醒配置表';
-
--- 迁移355: 减脂专题 - 体重记录表
-CREATE TABLE IF NOT EXISTS fat_weight_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    member_id BIGINT NOT NULL COMMENT '家庭成员ID(family_members.id)',
-    weight DECIMAL(5,2) NOT NULL COMMENT '体重(kg)',
-    body_fat_percent DECIMAL(4,2) DEFAULT NULL COMMENT '体脂率(%)',
-    waist_circumference DECIMAL(4,2) DEFAULT NULL COMMENT '腰围(cm)',
-    measure_date DATE NOT NULL COMMENT '测量日期',
-    remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_fat_weight_member (member_id, measure_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-体重体脂记录';
-
--- 迁移356: 减脂专题 - 饮食记录表
-CREATE TABLE IF NOT EXISTS fat_diet_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    member_id BIGINT NOT NULL COMMENT '家庭成员ID(family_members.id)',
-    meal_type VARCHAR(20) NOT NULL COMMENT 'meal_type: breakfast/lunch/dinner/snack',
-    food_name VARCHAR(255) NOT NULL COMMENT '食物名称',
-    food_weight DECIMAL(6,2) DEFAULT NULL COMMENT '食物重量(克)',
-    calories INT DEFAULT 0 COMMENT '热量(kcal)',
-    protein DECIMAL(6,2) DEFAULT 0 COMMENT '蛋白质(g)',
-    fat DECIMAL(6,2) DEFAULT 0 COMMENT '脂肪(g)',
-    carbs DECIMAL(6,2) DEFAULT 0 COMMENT '碳水(g)',
-    eat_date DATE NOT NULL COMMENT '进餐日期',
-    remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_fat_diet_member (member_id, eat_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-饮食记录';
-
--- 迁移357: 减脂专题 - 运动记录表
-CREATE TABLE IF NOT EXISTS fat_exercise_record (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    member_id BIGINT NOT NULL COMMENT '家庭成员ID(family_members.id)',
-    exercise_type VARCHAR(50) NOT NULL COMMENT '运动类型',
-    duration_min INT DEFAULT 0 COMMENT '运动时长(分钟)',
-    distance_km DECIMAL(5,2) DEFAULT NULL COMMENT '距离(km)',
-    calories_burned INT DEFAULT 0 COMMENT '消耗热量(kcal)',
-    exercise_date DATE NOT NULL COMMENT '运动日期',
-    remark VARCHAR(255) DEFAULT NULL COMMENT '备注',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    INDEX idx_fat_exercise_member (member_id, exercise_date)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-运动记录';
-
--- 迁移358: 减脂专题 - 减脂目标表
-CREATE TABLE IF NOT EXISTS fat_goal (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    member_id BIGINT NOT NULL COMMENT '家庭成员ID(family_members.id)',
-    target_weight DECIMAL(5,2) NOT NULL COMMENT '目标体重(kg)',
-    start_weight DECIMAL(5,2) NOT NULL COMMENT '初始体重(kg)',
-    target_body_fat DECIMAL(4,2) DEFAULT NULL COMMENT '目标体脂率(%)',
-    target_date DATE DEFAULT NULL COMMENT '目标达成日期',
-    status VARCHAR(20) DEFAULT 'active' COMMENT '状态: active/completed/abandoned',
-    start_date DATE NOT NULL COMMENT '开始日期',
+    family_id BIGINT NOT NULL COMMENT '家庭ID',
+    content_type VARCHAR(16) NOT NULL COMMENT '内容类型: product/activity/article',
+    item_id BIGINT NOT NULL COMMENT '内容ID(商品ID/活动ID/文章ID)',
+    dimension_code VARCHAR(32) DEFAULT NULL COMMENT '维度编码: body/mind/wisdom/action/wealth',
+    weight DECIMAL(5,2) NOT NULL DEFAULT 1.00 COMMENT '权重值 0.00-10.00,越大越优先',
+    reason VARCHAR(200) DEFAULT NULL COMMENT '权重来源: user_set/auto_click/auto_purchase/manual/auto_profile',
+    created_by BIGINT DEFAULT NULL COMMENT '创建人ID(manual场景记录运营人员)',
     created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
     updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
-    INDEX idx_fat_goal_member (member_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='减脂专题-减脂目标';
--- 迁移359: 跨小程序单点登录一次性票据(cfc ↔ train 双向免登)
--- cfc 与 train 共用本库(zxyj)。签发方写入 ticket,目标方原子占用(used 0→1)后按 cfc_user_id 建立登录态。
-CREATE TABLE IF NOT EXISTS sso_ticket (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
-    ticket VARCHAR(64) NOT NULL COMMENT '一次性票据(SecureRandom 生成)',
-    source_system VARCHAR(16) NOT NULL COMMENT '签发方系统: cfc / train',
-    target_system VARCHAR(16) NOT NULL COMMENT '目标系统: cfc / train',
-    source_user_id BIGINT NOT NULL COMMENT '签发方用户ID(cfc=users.id / train=train_user.id)',
-    cfc_user_id BIGINT NOT NULL COMMENT 'cfc 统一会员ID(users.id),跨系统换票依据',
-    used TINYINT NOT NULL DEFAULT 0 COMMENT '是否已使用: 0=未用 1=已用',
-    expire_at DATETIME NOT NULL COMMENT '过期时间',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-    UNIQUE KEY uk_ticket (ticket),
-    INDEX idx_expire (expire_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='跨小程序单点登录一次性票据';
-
--- 迁移359: 指标归一化映射规则(连接各来源原始名与统一 indicator_definitions)
-CREATE TABLE IF NOT EXISTS indicator_mapping_rules (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    source_type VARCHAR(32) NOT NULL COMMENT '来源: gut_flora|physical_exam|dan_a2|food_recommend|five_dimension|health_dimension',
-    raw_name VARCHAR(200) NOT NULL COMMENT '报告中的原始名称(指标名/菌名/食材名)',
-    alias_text TEXT COMMENT '别名 JSON 数组,用于模糊匹配',
-    definition_id BIGINT NOT NULL COMMENT 'FK → indicator_definitions.id',
-    match_type VARCHAR(20) DEFAULT 'exact' COMMENT 'exact|fuzzy|ai_fallback|auto_created',
-    priority INT DEFAULT 0 COMMENT '多规则冲突时取最高',
-    status TINYINT DEFAULT 1,
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_source_raw (source_type, raw_name),
-    INDEX idx_def (definition_id)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标归一化映射规则';
-
--- 迁移360: 指标关联关系(人工定义 + 数据校准)
-CREATE TABLE IF NOT EXISTS indicator_correlations (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    definition_id_a BIGINT NOT NULL COMMENT 'code 字典序较小的指标',
-    definition_id_b BIGINT NOT NULL COMMENT 'code 字典序较大的指标',
-    relation_type VARCHAR(20) DEFAULT 'correlation' COMMENT 'correlation|influence|same_source',
-    direction VARCHAR(10) NOT NULL COMMENT 'positive|negative',
-    manual_strength DECIMAL(3,2) NOT NULL COMMENT '人工标定强度 0~1',
-    computed_strength DECIMAL(4,3) NULL COMMENT '统计计算相关系数(Spearman rho)',
-    method VARCHAR(20) DEFAULT 'spearman' COMMENT 'pearson|spearman',
-    sample_size INT DEFAULT 0 COMMENT '参与计算的聚合有效样本数',
-    confidence VARCHAR(10) COMMENT 'high(>=30)|medium(10~29)|low(<10)',
-    effective_strength DECIMAL(4,3) NOT NULL COMMENT '展示值: 样本>=30 时取 computed 否则取 manual',
-    manual_locked TINYINT DEFAULT 0 COMMENT '1=人工锁定,校准不覆盖',
-    cohort_scope VARCHAR(20) DEFAULT 'subject' COMMENT 'subject|family|population',
-    status VARCHAR(20) DEFAULT 'active' COMMENT 'active|inactive|pending',
-    computed_at DATETIME NULL COMMENT '最后校准时间',
-    created_by BIGINT NULL COMMENT '创建者',
-    description VARCHAR(500) NULL COMMENT '给用户看的解释',
-    source_note VARCHAR(255) NULL COMMENT '依据/出处',
-    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_pair (definition_id_a, definition_id_b),
-    INDEX idx_def_a (definition_id_a),
-    INDEX idx_def_b (definition_id_b)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标关联关系(人工定义+数据校准)';
-
--- 迁移368: 药物-食物禁忌对照表
-CREATE TABLE IF NOT EXISTS drug_interactions (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    drug_class VARCHAR(50) NOT NULL COMMENT '药物类别(如CCB/他汀/抗凝药/抗生素/铁剂/甲状腺药/利尿剂/MAOI/头孢/降糖药)',
-    drug_specifics VARCHAR(100) NOT NULL COMMENT '具体药名(如硝苯地平/华法林)',
-    interacting_subst VARCHAR(100) NOT NULL COMMENT '禁忌/需间隔的食材或成分(如西柚/维生素K)',
-    risk_level TINYINT NOT NULL COMMENT '1=拦截 2=警告 3=需间隔',
-    action_type VARCHAR(20) NOT NULL COMMENT 'block=硬拦截 warn=软警告 space=间隔',
-    interval_minutes INT DEFAULT NULL COMMENT '需间隔时长(分钟)',
-    note VARCHAR(255) COMMENT '风险说明',
-    UNIQUE KEY uk_drug_food (drug_class, drug_specifics, interacting_subst),
-    INDEX idx_interacting (interacting_subst)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='药物-食物禁忌对照表';
-
--- 迁移369: 疾病-饮食摄入校验阈值表
-CREATE TABLE IF NOT EXISTS disease_intake_limits (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    disease_type VARCHAR(50) NOT NULL COMMENT '疾病类型(慢性肾病/糖尿病/高血压/痛风/肝病/甲状腺疾病)',
-    nutrient VARCHAR(20) NOT NULL COMMENT '校验营养素(protein/potassium/phosphorus/sodium/carb/glycemic/fructose/purine/alcohol/iodine)',
-    unit VARCHAR(20) NOT NULL COMMENT '单位',
-    threshold_max DECIMAL(8,2) DEFAULT NULL COMMENT '每日上限',
-    threshold_min DECIMAL(8,2) DEFAULT NULL COMMENT '每日下限',
-    block_foods VARCHAR(500) DEFAULT NULL COMMENT '硬拦截食材列表,逗号分隔(如杨桃)',
-    stage_dependent TINYINT(1) DEFAULT 0 COMMENT '是否按病情分期(1=是 0=否)',
-    INDEX idx_disease_nutrient (disease_type, nutrient)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='疾病-饮食摄入校验阈值表';
-
--- 迁移363: 创建采购任务表(商品组合推荐与采购任务生命周期管理)
-CREATE TABLE IF NOT EXISTS procurement_tasks (
-    id BIGINT AUTO_INCREMENT PRIMARY KEY,
-    task_id VARCHAR(64) NOT NULL COMMENT '任务唯一标识',
-    user_id BIGINT NOT NULL COMMENT '所属用户ID',
-    family_member_id BIGINT NOT NULL COMMENT '所属家庭成员ID',
-    combo_tier VARCHAR(20) NOT NULL COMMENT '选择的套餐等级: high|medium|low',
-    original_combo_tier VARCHAR(20) DEFAULT NULL COMMENT '原始套餐等级(用于自定义追踪)',
-    selected_product_sku_ids TEXT COMMENT '最终选中的产品SKU列表(JSON数组)',
-    custom_addition_sku_ids TEXT COMMENT '用户自新增的产品SKU列表(JSON数组)',
-    custom_removal_sku_ids TEXT COMMENT '用户移除的产品SKU列表(JSON数组)',
-    status VARCHAR(32) NOT NULL COMMENT '任务状态: SELECTED|PROCURING|PROCURED|EXECUTING|COMPLETED|CANCELLED',
-    create_time DATETIME NOT NULL COMMENT '创建时间',
-    complete_time DATETIME DEFAULT NULL COMMENT '完成时间',
-    message_reminder_sent TINYINT DEFAULT 0 COMMENT '是否已发送消息提醒',
-    execution_task_id VARCHAR(64) DEFAULT NULL COMMENT '关联的执行任务ID',
-    update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-    UNIQUE KEY uk_task_id (task_id),
-    INDEX idx_user_id (user_id),
-    INDEX idx_family_member_id (family_member_id),
-    INDEX idx_status (status),
-    INDEX idx_create_time (create_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='采购任务表(商品组合推荐与采购任务生命周期管理)';
+    INDEX idx_user_content (user_id, content_type, item_id),
+    INDEX idx_family_dimension (family_id, dimension_code),
+    UNIQUE KEY uk_user_item (user_id, content_type, item_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户内容偏好权重表';

+ 59 - 38
cfc-frontend/pages/action-detail/index.vue

@@ -843,9 +843,30 @@ export default {
 </script>
 
 <style scoped lang="scss">
+
+// 页面级局部调色板:仅本页专有色阶,跨页共性一律走 uni.scss 全局令牌
+// 信息蓝
+$c-info: #0EA5E9;
+$c-action-light: #34D399;
+$c-action-lighter: #6EE7B7;
+// 信息蓝·亮阶
+$c-info-light: #38BDF8;
+// 危险·亮阶(渐变尾)
+$c-danger-light: #F87171;
+// 次级文字
+$c-text-soft: #64748B;
+// 深次级文字
+$c-text-deep: #475569;
+// 下沉底 / 分隔
+$c-surface-sunken: #F1F5F9;
+// 成功·亮阶(渐变尾)
+$c-success-light: #A7F3D0;
+// 薄荷极浅底
+$c-tint-mint: #E6FFF2;
+
 .container {
   min-height: 100vh;
-  background: linear-gradient(180deg, #F0FFF4 0%, $app-bg 40%);
+  background: linear-gradient(180deg, $dim-action-tint 0%, $app-bg 40%);
   padding-bottom: 120rpx;
 }
 
@@ -853,7 +874,7 @@ export default {
 .brand-strap {
   margin: 24rpx 30rpx 0;
   padding: 28rpx 32rpx;
-  background: linear-gradient(135deg, $dim-action 0%, #34D399 50%, #6EE7B7 100%);
+  background: linear-gradient(135deg, $dim-action 0%, $c-action-light 50%, $c-action-lighter 100%);
   border-radius: 24rpx;
   box-shadow: 0 8rpx 24rpx rgba(16, 185, 129, 0.25);
   position: relative;
@@ -892,7 +913,7 @@ export default {
 .monthly-guidance {
   margin: 20rpx 30rpx 0;
   padding: 24rpx 28rpx;
-  background: linear-gradient(135deg, $app-surface 0%, #F0FFF4 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $dim-action-tint 100%);
   border-radius: 20rpx;
   border: 1rpx solid rgba(16, 185, 129, 0.15);
   box-shadow: 0 4rpx 16rpx rgba(16, 185, 129, 0.08);
@@ -903,7 +924,7 @@ export default {
 .guidance-icon { font-size: 36rpx; }
 .guidance-text {
   font-size: 26rpx;
-  color: #065F46;
+  color: $status-success-strong;
   font-weight: 500;
 }
 
@@ -920,7 +941,7 @@ export default {
   right: 24rpx;
   height: 3rpx;
   border-radius: 3rpx 3rpx 0 0;
-  background: linear-gradient(90deg, $dim-action, #34D399);
+  background: linear-gradient(90deg, $dim-action, $c-action-light);
   opacity: 0.7;
 }
 .section-header {
@@ -942,8 +963,8 @@ export default {
   width: 36rpx;
   height: 36rpx;
   border-radius: 50%;
-  border: 2rpx solid #D1D5DB;
-  color: #9CA3AF;
+  border: 2rpx solid $app-border-strong;
+  color: $app-text-muted;
   font-size: 22rpx;
   display: flex;
   align-items: center;
@@ -955,18 +976,18 @@ export default {
 .help-icon:active {
   border-color: $dim-action;
   color: $dim-action;
-  background: #F0FFF4;
+  background: $dim-action-tint;
   transform: scale(1.1);
 }
 .section-title {
   font-size: 34rpx;
   font-weight: 700;
-  color: #1E293B;
+  color: $app-text;
   letter-spacing: 0.5rpx;
 }
 .section-sub {
   font-size: 24rpx;
-  color: #94A3B8;
+  color: $app-text-subtle;
   margin-top: 4rpx;
   line-height: 1.4;
 }
@@ -986,41 +1007,41 @@ export default {
   transform: scale(0.98);
 }
 .section-link-octopus {
-  background: linear-gradient(135deg, #F97316, #FB923C);
+  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
   color: $app-surface;
   box-shadow: 0 4rpx 16rpx rgba(249,115,22,0.3);
 }
 .section-link-pearl {
-  background: linear-gradient(135deg, #0EA5E9, #38BDF8);
+  background: linear-gradient(135deg, $c-info, $c-info-light);
   color: $app-surface;
   box-shadow: 0 4rpx 16rpx rgba(14,165,233,0.3);
 }
 .section-link-ability {
-  background: linear-gradient(135deg, $dim-action, #34D399);
+  background: linear-gradient(135deg, $dim-action, $c-action-light);
   color: $app-surface;
   box-shadow: 0 4rpx 16rpx rgba(16,185,129,0.3);
 }
 
 /* 关系解读卡片 — 状态色 */
 .score-explain-card {
-  background: linear-gradient(135deg, $app-surface 0%, #F0FFF4 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $dim-action-tint 100%);
   border-radius: 20rpx;
   padding: 28rpx 32rpx;
   border: 1rpx solid rgba(16, 185, 129, 0.12);
   box-shadow: 0 4rpx 16rpx rgba(16, 185, 129, 0.08);
 }
 .score-explain-good {
-  background: linear-gradient(135deg, $app-surface 0%, #D1FAE5 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $status-success-soft 100%);
   border-color: rgba(16, 185, 129, 0.25);
   box-shadow: 0 4rpx 20rpx rgba(16, 185, 129, 0.15);
 }
 .score-explain-warn {
-  background: linear-gradient(135deg, $app-surface 0%, #FEF3C7 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $status-warning-soft 100%);
   border-color: rgba(245, 158, 11, 0.25);
   box-shadow: 0 4rpx 20rpx rgba(245, 158, 11, 0.12);
 }
 .score-explain-bad {
-  background: linear-gradient(135deg, $app-surface 0%, #FEE2E2 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $status-danger-soft 100%);
   border-color: rgba(239, 68, 68, 0.25);
   box-shadow: 0 4rpx 20rpx rgba(239, 68, 68, 0.12);
 }
@@ -1042,9 +1063,9 @@ export default {
   transition: transform 0.2s;
 }
 .explain-icon-wrap:active { transform: scale(0.95); }
-.explain-icon-good { background: linear-gradient(135deg, $dim-action, #34D399); box-shadow: 0 4rpx 12rpx rgba(16,185,129,0.3); }
-.explain-icon-warn { background: linear-gradient(135deg, #F59E0B, #FBBF24); box-shadow: 0 4rpx 12rpx rgba(245,158,11,0.3); }
-.explain-icon-bad { background: linear-gradient(135deg, #EF4444, #F87171); box-shadow: 0 4rpx 12rpx rgba(239,68,68,0.3); }
+.explain-icon-good { background: linear-gradient(135deg, $dim-action, $c-action-light); box-shadow: 0 4rpx 12rpx rgba(16,185,129,0.3); }
+.explain-icon-warn { background: linear-gradient(135deg, $dim-wealth, $status-warning); box-shadow: 0 4rpx 12rpx rgba(245,158,11,0.3); }
+.explain-icon-bad { background: linear-gradient(135deg, $status-danger, $c-danger-light); box-shadow: 0 4rpx 12rpx rgba(239,68,68,0.3); }
 .explain-icon {
   font-size: 28rpx;
   color: $app-surface;
@@ -1057,7 +1078,7 @@ export default {
 .explain-title {
   font-size: 28rpx;
   font-weight: 600;
-  color: #1E293B;
+  color: $app-text;
   line-height: 1.3;
 }
 .explain-score {
@@ -1067,18 +1088,18 @@ export default {
   letter-spacing: -2rpx;
 }
 .score-explain-good .explain-score { color: $dim-action; }
-.score-explain-warn .explain-score { color: #D97706; }
-.score-explain-bad .explain-score { color: #DC2626; }
+.score-explain-warn .explain-score { color: $status-warning-deep; }
+.score-explain-bad .explain-score { color: $status-danger-deep; }
 .explain-score-unit {
   font-size: 24rpx;
   font-weight: 500;
-  color: #94A3B8;
+  color: $app-text-subtle;
   margin-left: 2rpx;
   letter-spacing: 0;
 }
 .explain-text {
   font-size: 26rpx;
-  color: #64748B;
+  color: $c-text-soft;
   line-height: 1.7;
 }
 
@@ -1109,17 +1130,17 @@ export default {
   justify-content: space-between;
   align-items: center;
   padding: 28rpx 32rpx 20rpx;
-  border-bottom: 1rpx solid #F1F5F9;
-  background: linear-gradient(135deg, #F0FFF4, $app-surface);
+  border-bottom: 1rpx solid $c-surface-sunken;
+  background: linear-gradient(135deg, $dim-action-tint, $app-surface);
 }
 .help-dialog-title {
   font-size: 32rpx;
   font-weight: 700;
-  color: #1E293B;
+  color: $app-text;
 }
 .help-dialog-close {
   font-size: 36rpx;
-  color: #94A3B8;
+  color: $app-text-subtle;
   cursor: pointer;
   width: 48rpx;
   height: 48rpx;
@@ -1130,12 +1151,12 @@ export default {
   transition: background 0.2s;
 }
 .help-dialog-close:active {
-  background: #F1F5F9;
+  background: $c-surface-sunken;
 }
 .help-dialog-content {
   padding: 28rpx 32rpx;
   font-size: 28rpx;
-  color: #64748B;
+  color: $c-text-soft;
   line-height: 1.8;
 }
 
@@ -1147,7 +1168,7 @@ export default {
   display: flex;
   flex-direction: row;
   justify-content: space-around;
-  background: linear-gradient(135deg, $app-surface 0%, #F0FFF4 100%);
+  background: linear-gradient(135deg, $app-surface 0%, $dim-action-tint 100%);
   border-radius: 24rpx;
   padding: 32rpx 16rpx;
   box-shadow: 0 8rpx 24rpx rgba(16, 185, 129, 0.1);
@@ -1164,7 +1185,7 @@ export default {
   width: 96rpx;
   height: 96rpx;
   border-radius: 28rpx;
-  background: linear-gradient(135deg, #D1FAE5, #A7F3D0);
+  background: linear-gradient(135deg, $status-success-soft, $c-success-light);
   display: flex;
   align-items: center;
   justify-content: center;
@@ -1181,7 +1202,7 @@ export default {
 }
 .func-label {
   font-size: 24rpx;
-  color: #475569;
+  color: $c-text-deep;
   font-weight: 500;
 }
 
@@ -1233,7 +1254,7 @@ export default {
   justify-content: center;
   margin-right: 10rpx;
   font-size: 20rpx;
-  background: linear-gradient(135deg, #D1FAE5, #A7F3D0);
+  background: linear-gradient(135deg, $status-success-soft, $c-success-light);
 }
 .portrait-dim-name {
   font-size: 24rpx;
@@ -1248,7 +1269,7 @@ export default {
 }
 .portrait-dim-bar-track {
   height: 10rpx;
-  background: #D1FAE5;
+  background: $status-success-soft;
   border-radius: 5rpx;
   overflow: hidden;
   margin-bottom: 4rpx;
@@ -1266,14 +1287,14 @@ export default {
 }
 .portrait-tip {
   padding: 16rpx 20rpx;
-  background: linear-gradient(135deg, #F0FFF4, #E6FFF2);
+  background: linear-gradient(135deg, $dim-action-tint, $c-tint-mint);
   border-radius: 12rpx;
   border-left: 8rpx solid $dim-action;
   margin-top: 16rpx;
 }
 .portrait-tip-text {
   font-size: 22rpx;
-  color: #065F46;
+  color: $status-success-strong;
   line-height: 1.5;
 }
 </style>

+ 36 - 19
cfc-frontend/pages/body-detail/index.vue

@@ -625,6 +625,23 @@ export default {
 </script>
 
 <style scoped lang="scss">
+
+// 页面级局部调色板:仅本页专有色阶,跨页共性一律走 uni.scss 全局令牌
+// 身·亮阶(渐变尾)
+$c-body-light: #FFB366;
+$c-tint-peach: #FFF3E8;
+$c-tint-blush: #FFF9F5;
+// 身·深阶(渐变尾)
+$c-body-deep: #FF6B1A;
+// 暖调极浅底
+$c-tint-warm: #FFF5EE;
+// 暖调浅底
+$c-tint-soft: #FFF1E6;
+// 暖调描边
+$c-edge-warm: #FFE4CC;
+// 发丝分隔线
+$c-hairline: #eee;
+
 .body-container {
   min-height: 100vh;
   background-color: $app-bg;
@@ -643,7 +660,7 @@ export default {
 
 .overview-header {
   padding: 24rpx 24rpx 16rpx;
-  border-bottom: 1rpx solid #FFF0E4;
+  border-bottom: 1rpx solid $dim-body-tint;
 }
 
 .overview-title {
@@ -670,7 +687,7 @@ export default {
   margin: 0 0 20rpx 0;
   margin-right: 16rpx;
   padding: 20rpx;
-  background: linear-gradient(135deg, #FFF8F0 0%, #FFF3E8 100%);
+  background: linear-gradient(135deg, $dim-body-tint 0%, $c-tint-peach 100%);
   border-radius: 20rpx;
   box-shadow: 0 2rpx 8rpx rgba(255, 140, 66, 0.08);
 }
@@ -683,7 +700,7 @@ export default {
   width: 52rpx;
   height: 52rpx;
   border-radius: 50%;
-  background: linear-gradient(135deg, $dim-body, #FFB366);
+  background: linear-gradient(135deg, $dim-body, $c-body-light);
   display: flex;
   align-items: center;
   justify-content: center;
@@ -729,8 +746,8 @@ export default {
   flex-shrink: 0;
 }
 
-.trend-up { color: #10B981; }
-.trend-down { color: #FF6B6B; }
+.trend-up { color: $status-success; }
+.trend-down { color: $status-danger; }
 .trend-stable { color: $app-text-muted; }
 
 .trend-desc {
@@ -753,7 +770,7 @@ export default {
   display: flex;
   align-items: center;
   justify-content: center;
-  background: linear-gradient(135deg, $dim-body, #FF6B1A);
+  background: linear-gradient(135deg, $dim-body, $c-body-deep);
   border-radius: 48rpx;
   padding: 20rpx 0;
   box-shadow: 0 4rpx 16rpx rgba(255, 107, 26, 0.35);
@@ -835,7 +852,7 @@ export default {
   margin: 0 0 20rpx 0;
   margin-right: 16rpx;
   padding: 20rpx;
-  background: linear-gradient(135deg, #FFF9F5 0%, #FFF5EE 100%);
+  background: linear-gradient(135deg, $c-tint-blush 0%, $c-tint-warm 100%);
   border-radius: 20rpx;
   border: 2rpx solid rgba(255, 140, 66, 0.15);
 }
@@ -846,7 +863,7 @@ export default {
 
 .indicator-card.no-data {
   background: $app-surface-subtle;
-  border-color: #eee;
+  border-color: $c-hairline;
 }
 
 .indicator-header {
@@ -898,8 +915,8 @@ export default {
 
 .gut-summary {
   padding: 20rpx 24rpx;
-  background-color: #FFF8F0;
-  border-bottom: 1rpx solid #FFF0E4;
+  background-color: $dim-body-tint;
+  border-bottom: 1rpx solid $dim-body-tint;
   text-align: center;
 }
 
@@ -965,7 +982,7 @@ export default {
 }
 
 .gut-abnormal .gut-item-status {
-  color: #FF6B6B;
+  color: $status-danger;
 }
 
 .gut-empty-hint {
@@ -1018,7 +1035,7 @@ export default {
 .risk-value {
   font-size: 26rpx;
   font-weight: 600;
-  color: #FF6B6B;
+  color: $status-danger;
 }
 
 .risk-level {
@@ -1027,7 +1044,7 @@ export default {
   font-weight: 500;
 }
 
-.risk-severe .risk-level { color: #FF6B6B; }
+.risk-severe .risk-level { color: $status-danger; }
 .risk-attention .risk-level { color: $dim-body; }
 .risk-normal .risk-level { color: $app-text-muted; }
 
@@ -1089,7 +1106,7 @@ export default {
 }
 .portrait-dim-bar-track {
   height: 12rpx;
-  background: #FFF0E4;
+  background: $dim-body-tint;
   border-radius: 6rpx;
   overflow: hidden;
   margin-bottom: 6rpx;
@@ -1106,13 +1123,13 @@ export default {
 }
 .portrait-tip {
   padding: 16rpx 20rpx;
-  background: linear-gradient(135deg, #FFF7ED, #FFF0E4);
+  background: linear-gradient(135deg, $dim-wealth-tint, $dim-body-tint);
   border-radius: 12rpx;
   border-left: 8rpx solid $dim-body;
 }
 .portrait-tip-text {
   font-size: 24rpx;
-  color: #C2410C;
+  color: $brand-primary-deep;
   line-height: 1.5;
 }
 .monthly-guidance {
@@ -1120,9 +1137,9 @@ export default {
   align-items: center;
   padding: 20rpx 24rpx;
   margin: 0 20rpx 16rpx;
-  background: linear-gradient(135deg, #FFF8F0, #FFF3E8);
+  background: linear-gradient(135deg, $dim-body-tint, $c-tint-peach);
   border-radius: 16rpx;
-  border: 1rpx solid #FFE4CC;
+  border: 1rpx solid $c-edge-warm;
 }
 
 .guidance-icon {
@@ -1138,7 +1155,7 @@ export default {
 /* ─── 品牌定位语(登录前) ─── */
 .brand-strap {
   margin: 0 24rpx 16rpx;
-  background: linear-gradient(135deg, #FFF1E6, rgba(255, 140, 66, 0.10));
+  background: linear-gradient(135deg, $c-tint-soft, rgba(255, 140, 66, 0.10));
   border-radius: 16rpx;
   padding: 20rpx 24rpx;
 }

+ 143 - 80
cfc-frontend/pages/mind-detail/index.vue

@@ -1188,6 +1188,69 @@ var descList = descMap[this.dominantElement] || descMap.wood
 </script>
 
 <style scoped lang="scss">
+
+// 页面级局部调色板:仅本页专有色阶,跨页共性一律走 uni.scss 全局令牌
+// 页面强调色(情绪 / 成就)
+$c-accent: #FF6B35;
+// 金(与强调色成渐变)
+$c-gold: #FFD700;
+// 紫主
+$c-violet: #7C3AED;
+// 紫·亮阶
+$c-violet-light: #A855F7;
+// 心·极深文字
+$c-mind-ink: #9D174D;
+// 信息蓝
+$c-info: #3B82F6;
+// 洞察文案(棕金)
+$c-insight-ink: #8B6914;
+// 夜间渐变 起
+$c-night-1: #1a1a2e;
+// 夜间渐变 中
+$c-night-2: #16213e;
+// 夜间渐变 止
+$c-night-3: #0f3460;
+// 运势 0 前景
+$f0: #D32F2F;
+// 运势 0 背景
+$f0-bg: #FFEBEE;
+// 运势 1 前景
+$f1: #E65100;
+// 运势 1 背景
+$f1-bg: #FFF3E0;
+// 运势 2 前景
+$f2: #F9A825;
+// 运势 2 背景
+$f2-bg: #FFFDE7;
+// 运势 3 前景
+$f3: #7B1FA2;
+// 运势 3 背景
+$f3-bg: #F3E5F5;
+// 运势 4 前景
+$f4: #B71C1C;
+// 运势 4 背景
+$f4-bg: #FFCDD2;
+// 玫瑰浅底
+$tint-rose: #FDF2F7;
+// 紫浅底
+$tint-violet: #F5F3FF;
+// 淡紫浅底
+$tint-lilac: #F5F0FF;
+// 紫罗兰浅底
+$tint-purple: #F3E8FF;
+// 蓝浅底
+$tint-blue: #EFF6FF;
+// 天蓝浅底
+$tint-sky: #EBF2FA;
+// 天蓝浅底·深
+$tint-sky-deep: #D6EAF8;
+// 薄荷浅底
+$tint-mint: #ECFDF5;
+// 中性浅底
+$tint-gray: #F8F9FA;
+// 青灰浅底
+$tint-cyan: #F0F6F7;
+
 .container {
   min-height: 100vh;
   background: $app-bg;
@@ -1201,7 +1264,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   align-items: center;
   margin: 20rpx 30rpx 10rpx;
   padding: 16rpx 24rpx;
-  background: linear-gradient(135deg, #F97316, #FB923C);
+  background: linear-gradient(135deg, $brand-primary, $brand-primary-light);
   border-radius: 20rpx;
   box-shadow: 0 4rpx 16rpx rgba(139,92,246,0.25);
 }
@@ -1224,7 +1287,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   display: flex;
   flex-direction: row;
   align-items: center;
-  background: linear-gradient(135deg, #F3E8FF, #FCE4EC);
+  background: linear-gradient(135deg, $tint-purple, $dim-mind-tint);
   border-radius: 20rpx;
   padding: 28rpx 24rpx;
   box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.06);
@@ -1249,13 +1312,13 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .mind-report-title {
   font-size: 30rpx;
   font-weight: bold;
-  color: #7C3AED;
+  color: $c-violet;
   display: block;
   margin-bottom: 6rpx;
 }
 .mind-report-desc {
   font-size: 22rpx;
-  color: #A855F7;
+  color: $c-violet-light;
   line-height: 1.5;
   display: block;
   margin-bottom: 10rpx;
@@ -1267,14 +1330,14 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .mind-tag {
   font-size: 20rpx;
-  color: #7C3AED;
+  color: $c-violet;
   background: rgba(255,255,255,0.6);
   padding: 4rpx 14rpx;
   border-radius: 20rpx;
 }
 .mind-report-arrow {
   font-size: 36rpx;
-  color: #FB923C;
+  color: $brand-primary-light;
   margin-left: 10rpx;
   flex-shrink: 0;
 }
@@ -1317,8 +1380,8 @@ var descList = descMap[this.dominantElement] || descMap.wood
   border-radius: 20rpx;
 }
 .mind-report-item-status.parsed {
-  color: #7C3AED;
-  background: #F3E8FF;
+  color: $c-violet;
+  background: $tint-purple;
 }
 .mind-report-item-status.pending {
   color: $app-text-muted;
@@ -1338,7 +1401,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .mind-report-empty-text {
   font-size: 24rpx;
-  color: #bbb;
+  color: $app-border;
 }
 
 /* ===== 心理能量概况 ===== */
@@ -1397,7 +1460,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   margin-bottom: 24rpx;
 }
 .test-btn {
-  background: #F97316;
+  background: $brand-primary;
   padding: 8rpx 28rpx;
   border-radius: 30rpx;
 }
@@ -1421,7 +1484,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .emi-bar-track {
   flex: 1;
   height: 20rpx;
-  background: #f0f0f0;
+  background: $app-surface-subtle;
   border-radius: 10rpx;
   overflow: hidden;
   margin: 0 16rpx;
@@ -1445,10 +1508,10 @@ var descList = descMap[this.dominantElement] || descMap.wood
   text-align: right;
   flex-shrink: 0;
 }
-.level-excellent { color: #10B981; }
-.level-good { color: #3B82F6; }
-.level-average { color: #F97316; }
-.level-low { color: #EF4444; }
+.level-excellent { color: $status-success; }
+.level-good { color: $c-info; }
+.level-average { color: $brand-primary; }
+.level-low { color: $status-danger; }
 .emi-footer {
   display: flex;
   flex-direction: row;
@@ -1456,12 +1519,12 @@ var descList = descMap[this.dominantElement] || descMap.wood
   align-items: center;
   margin-top: 20rpx;
   padding-top: 20rpx;
-  border-top: 1rpx solid #f0f0f0;
+  border-top: 1rpx solid $app-surface-subtle;
 }
 .emi-overall {
   font-size: 28rpx;
   font-weight: bold;
-  color: #FF6B35;
+  color: $c-accent;
 }
 .emi-link {
   display: flex;
@@ -1470,12 +1533,12 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .emi-link-text {
   font-size: 26rpx;
-  color: #FF6B35;
+  color: $c-accent;
   font-weight: 500;
 }
 .emi-link-arrow {
   font-size: 26rpx;
-  color: #FF6B35;
+  color: $c-accent;
   margin-left: 8rpx;
 }
 
@@ -1501,7 +1564,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   flex-direction: column;
   align-items: center;
   padding: 32rpx 0;
-  background: linear-gradient(135deg, #FF6B35, #FFD700);
+  background: linear-gradient(135deg, $c-accent, $c-gold);
   border-radius: 16rpx;
   margin: 20rpx 0;
   color: $app-surface;
@@ -1549,7 +1612,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .emi-dim-score {
   font-size: 28rpx;
   font-weight: bold;
-  color: #FF6B35;
+  color: $c-accent;
   margin-right: 12rpx;
 }
 .emi-dim-level {
@@ -1559,7 +1622,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .emi-dim-bar {
   height: 14rpx;
-  background: #f0f0f0;
+  background: $app-surface-subtle;
   border-radius: 7rpx;
   overflow: hidden;
 }
@@ -1573,22 +1636,22 @@ var descList = descMap[this.dominantElement] || descMap.wood
   justify-content: flex-end;
   align-items: center;
   padding-top: 20rpx;
-  border-top: 1rpx solid #f0f0f0;
+  border-top: 1rpx solid $app-surface-subtle;
   margin-top: 20rpx;
 }
 .emi-footer-text {
   font-size: 24rpx;
-  color: #F97316;
+  color: $brand-primary;
   font-weight: 500;
 }
 .emi-footer-icon {
   font-size: 24rpx;
   margin-left: 8rpx;
 }
-.level-excellent { color: #10B981; background: #ECFDF5; }
-.level-good { color: #3B82F6; background: #EFF6FF; }
-.level-average { color: #F97316; background: #FFF7ED; }
-.level-low { color: #EF4444; background: #FEF2F2; }
+.level-excellent { color: $status-success; background: $tint-mint; }
+.level-good { color: $c-info; background: $tint-blue; }
+.level-average { color: $brand-primary; background: $dim-wealth-tint; }
+.level-low { color: $status-danger; background: $status-danger-tint; }
 
 /* 雷达图内的空状态 */
 .placeholder-content {
@@ -1627,7 +1690,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   margin-bottom: 30rpx;
 }
 .placeholder-btn {
-  background: linear-gradient(135deg, #FF6B35, #FFD700);
+  background: linear-gradient(135deg, $c-accent, $c-gold);
   color: $app-surface;
   font-size: 28rpx;
   font-weight: bold;
@@ -1685,8 +1748,8 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .bazi-pillar-value {
   font-size: 32rpx;
   font-weight: 700;
-  color: #F97316;
-  background: #F5F0FF;
+  color: $brand-primary;
+  background: $tint-lilac;
   padding: 10rpx 14rpx;
   border-radius: 10rpx;
 }
@@ -1710,7 +1773,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .wuxing-bar-track {
   flex: 1;
   height: 20rpx;
-  background: #F0F0F0;
+  background: $app-surface-subtle;
   border-radius: 10rpx;
   overflow: hidden;
 }
@@ -1727,7 +1790,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .energy-card {
   margin-top: 20rpx;
   padding: 24rpx 20rpx;
-  background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
+  background: linear-gradient(135deg, $c-night-1 0%, $c-night-2 50%, $c-night-3 100%);
   border-radius: 20rpx;
   position: relative;
   overflow: hidden;
@@ -1771,7 +1834,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .energy-label {
   font-size: 28rpx;
   font-weight: 700;
-  background: linear-gradient(135deg, #F59E0B, $dim-mind);
+  background: linear-gradient(135deg, $dim-wealth, $dim-mind);
   -webkit-background-clip: text;
   -webkit-text-fill-color: transparent;
   background-clip: text;
@@ -1804,13 +1867,13 @@ var descList = descMap[this.dominantElement] || descMap.wood
   top: 4rpx;
   bottom: 4rpx;
   width: 4rpx;
-  background: linear-gradient(180deg, #F59E0B, $dim-mind);
+  background: linear-gradient(180deg, $dim-wealth, $dim-mind);
   border-radius: 2rpx;
 }
 
 .energy-advice {
   font-size: 24rpx;
-  color: #94A3B8;
+  color: $app-text-subtle;
   line-height: 1.7;
   display: block;
   position: relative;
@@ -1869,12 +1932,12 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .culture-dual-value {
   font-size: 28rpx;
   font-weight: 700;
-  color: #F97316;
+  color: $brand-primary;
 }
 .culture-empty {
   text-align: center;
   padding: 30rpx 0;
-  color: #bbb;
+  color: $app-border;
   font-size: 24rpx;
 }
 
@@ -1917,7 +1980,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .tip-source {
   font-size: 22rpx;
-  color: #bbb;
+  color: $app-border;
 }
 
 /* ===== 通用区块 ===== */
@@ -1988,11 +2051,11 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .meta-text {
   font-size: 22rpx;
-  color: #bbb;
+  color: $app-border;
 }
 .article-date {
   font-size: 22rpx;
-  color: #bbb;
+  color: $app-border;
   margin-left: auto;
 }
 
@@ -2024,7 +2087,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   width: 80rpx;
   height: 80rpx;
   border-radius: 40rpx;
-  background: linear-gradient(135deg, #D6EAF8, #EBF2FA);
+  background: linear-gradient(135deg, $tint-sky-deep, $tint-sky);
   display: flex;
   align-items: center;
   justify-content: center;
@@ -2053,7 +2116,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .indicator-body { margin-bottom: 8rpx; }
 .indicator-value { font-size: 40rpx; font-weight: bold; color: $dim-mind; }
 .indicator-placeholder { font-size: 26rpx; color: $app-border; }
-.indicator-range { font-size: 20rpx; color: #bbb; }
+.indicator-range { font-size: 20rpx; color: $app-border; }
 .bottom-spacer { height: 120rpx; }
 
 /* ===== 肠脑轴 ===== */
@@ -2062,7 +2125,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
   color: $app-text-secondary;
   margin-bottom: 16rpx;
   padding: 12rpx 16rpx;
-  background: #F0FFF4;
+  background: $dim-action-tint;
   border-radius: 12rpx;
   line-height: 1.6;
 }
@@ -2095,7 +2158,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .gut-indicator-bar-track {
   flex: 1;
   height: 16rpx;
-  background: #F0F0F0;
+  background: $app-surface-subtle;
   border-radius: 8rpx;
   overflow: hidden;
 }
@@ -2118,16 +2181,16 @@ var descList = descMap[this.dominantElement] || descMap.wood
   text-align: center;
 }
 .status-normal {
-  background: #D1FAE5;
-  color: #059669;
+  background: $status-success-soft;
+  color: $status-success-deep;
 }
 .status-abnormal {
-  background: #FEE2E2;
-  color: #DC2626;
+  background: $status-danger-soft;
+  color: $status-danger-deep;
 }
 .status-warning {
-  background: #FEF3C7;
-  color: #D97706;
+  background: $status-warning-soft;
+  color: $status-warning-deep;
 }
 
 /* ===== 关键信息(家庭+个人) ===== */
@@ -2159,7 +2222,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .key-info-col {
   flex: 1;
-  background: #F8F9FA;
+  background: $tint-gray;
   border-radius: 14rpx;
   padding: 16rpx;
   min-width: 0;
@@ -2223,31 +2286,31 @@ var descList = descMap[this.dominantElement] || descMap.wood
   border-radius: 10rpx;
 }
 .ki-fortune-0 {
-  color: #D32F2F;
-  background: #FFEBEE;
+  color: $f0;
+  background: $f0-bg;
 }
 .ki-fortune-1 {
-  color: #E65100;
-  background: #FFF3E0;
+  color: $f1;
+  background: $f1-bg;
 }
 .ki-fortune-2 {
-  color: #F9A825;
-  background: #FFFDE7;
+  color: $f2;
+  background: $f2-bg;
 }
 .ki-fortune-3 {
-  color: #7B1FA2;
-  background: #F3E5F5;
+  color: $f3;
+  background: $f3-bg;
 }
 .ki-fortune-4 {
-  color: #B71C1C;
-  background: #FFCDD2;
+  color: $f4;
+  background: $f4-bg;
 }
 .ki-insight {
   display: flex;
   align-items: flex-start;
   margin-top: 16rpx;
   padding: 16rpx;
-  background: #FFF8F0;
+  background: $dim-body-tint;
   border-radius: 12rpx;
 }
 .ki-insight-icon {
@@ -2257,7 +2320,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .ki-insight-text {
   font-size: 22rpx;
-  color: #8B6914;
+  color: $c-insight-ink;
   line-height: 1.5;
 }
 .ki-footer {
@@ -2265,9 +2328,9 @@ var descList = descMap[this.dominantElement] || descMap.wood
   text-align: center;
   padding: 12rpx;
   font-size: 24rpx;
-  color: #F97316;
+  color: $brand-primary;
   font-weight: 500;
-  background: #F5F3FF;
+  background: $tint-violet;
   border-radius: 12rpx;
 }
 .ki-footer:active {
@@ -2298,12 +2361,12 @@ var descList = descMap[this.dominantElement] || descMap.wood
   border-radius: 8rpx;
 }
 .dan-status.confirmed {
-  background: #D1FAE5;
-  color: #065F46;
+  background: $status-success-soft;
+  color: $status-success-strong;
 }
 .dan-status.pending {
-  background: #FEF3C7;
-  color: #92400E;
+  background: $status-warning-soft;
+  color: $status-warning-strong;
 }
 .dan-report-desc {
   font-size: 28rpx;
@@ -2317,7 +2380,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .dan-view-link {
   font-size: 26rpx;
-  color: #6366F1;
+  color: $dim-wisdom;
 }
 .section-header {
   display: flex;
@@ -2332,7 +2395,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .section-more {
   font-size: 26rpx;
-  color: #6366F1;
+  color: $dim-wisdom;
   padding: 8rpx 16rpx;
 }
 
@@ -2340,13 +2403,13 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .brand-strap {
   margin: 16rpx 30rpx 0;
   padding: 20rpx 28rpx;
-  background: linear-gradient(135deg, #FFF0F5, rgba(255,107,157,0.12));
+  background: linear-gradient(135deg, $dim-mind-tint, rgba(255,107,157,0.12));
   border-radius: 16rpx;
   border-left: 8rpx solid $dim-mind;
 }
 .brand-strap-text {
   font-size: 26rpx;
-  color: #9D174D;
+  color: $c-mind-ink;
   font-weight: 500;
 }
 
@@ -2354,7 +2417,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .monthly-guidance {
   margin: 16rpx 30rpx 0;
   padding: 20rpx 28rpx;
-  background: linear-gradient(135deg, #FFF0F5, rgba(255,107,157,0.08));
+  background: linear-gradient(135deg, $dim-mind-tint, rgba(255,107,157,0.08));
   border-radius: 16rpx;
   border-left: 8rpx solid $dim-mind;
   display: flex;
@@ -2364,7 +2427,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .guidance-icon { font-size: 32rpx; }
 .guidance-text {
   font-size: 26rpx;
-  color: #9D174D;
+  color: $c-mind-ink;
   font-weight: 500;
 }
 
@@ -2373,7 +2436,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 .radar-group-label {
   font-size: 28rpx;
   font-weight: bold;
-  color: #9D174D;
+  color: $c-mind-ink;
   margin-bottom: 16rpx;
   padding-left: 10rpx;
 }
@@ -2436,7 +2499,7 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .portrait-dim-bar-track {
   height: 10rpx;
-  background: #F0F6F7;
+  background: $tint-cyan;
   border-radius: 5rpx;
   overflow: hidden;
   margin-bottom: 4rpx;
@@ -2454,14 +2517,14 @@ var descList = descMap[this.dominantElement] || descMap.wood
 }
 .portrait-tip {
   padding: 16rpx 20rpx;
-  background: linear-gradient(135deg, #FFF0F5, #FDF2F7);
+  background: linear-gradient(135deg, $dim-mind-tint, $tint-rose);
   border-radius: 12rpx;
   border-left: 8rpx solid $dim-mind;
   margin-top: 16rpx;
 }
 .portrait-tip-text {
   font-size: 22rpx;
-  color: #C2410C;
+  color: $brand-primary-deep;
   line-height: 1.5;
 }
 </style>

+ 26 - 26
cfc-frontend/pages/wealth/index.vue

@@ -849,8 +849,8 @@ export default {
   align-items: center;
 }
 .stage-card.active {
-  background: #FFF7ED;
-  border: 2rpx solid #FBBF24;
+  background: $dim-wealth-tint;
+  border: 2rpx solid $status-warning;
 }
 .stage-icon {
   font-size: 44rpx;
@@ -874,13 +874,13 @@ export default {
 .stream-water {
   height: 20rpx;
   border-radius: 10rpx;
-  background: #FEF3C7;
+  background: $status-warning-soft;
   overflow: hidden;
 }
 .stream-water-fill {
   height: 100%;
   border-radius: 10rpx;
-  background: linear-gradient(90deg, $dim-wealth, #FBBF24);
+  background: linear-gradient(90deg, $dim-wealth, $status-warning);
   transition: width 0.8s ease;
 }
 .stream-percent {
@@ -894,13 +894,13 @@ export default {
   display: block;
   text-align: center;
   font-size: 24rpx;
-  color: #92400E;
+  color: $status-warning-strong;
   margin-top: 12rpx;
 }
 
 /* 财富数据主卡 */
 .disc-card {
-  background: linear-gradient(135deg, #FFF7ED, #FEF3C7);
+  background: linear-gradient(135deg, $dim-wealth-tint, $status-warning-soft);
   border-radius: 20rpx;
   padding: 30rpx;
   margin-bottom: 16rpx;
@@ -909,7 +909,7 @@ export default {
 }
 .disc-label {
   font-size: 26rpx;
-  color: #92400E;
+  color: $status-warning-strong;
 }
 .disc-value {
   font-size: 56rpx;
@@ -919,7 +919,7 @@ export default {
 }
 .disc-sub {
   font-size: 24rpx;
-  color: #B45309;
+  color: $status-warning-strong;
   margin-top: 8rpx;
 }
 .disc-sub-row {
@@ -1006,7 +1006,7 @@ export default {
 .trend-bar {
   flex: 1;
   margin: 0 6rpx;
-  background: linear-gradient(180deg, #FBBF24, $dim-wealth);
+  background: linear-gradient(180deg, $status-warning, $dim-wealth);
   border-radius: 6rpx 6rpx 0 0;
 }
 .child-trend-days {
@@ -1040,7 +1040,7 @@ export default {
   width: 88rpx;
   height: 88rpx;
   border-radius: 24rpx;
-  background: #FFF7ED;
+  background: $dim-wealth-tint;
   display: flex;
   align-items: center;
   justify-content: center;
@@ -1055,7 +1055,7 @@ export default {
 }
 
 .logout-item {
-  color: #EF4444;
+  color: $status-danger;
 }
 
 /* 未登录 */
@@ -1067,13 +1067,13 @@ export default {
 .brand-strap {
   margin: 16rpx 30rpx 0;
   padding: 20rpx 28rpx;
-  background: linear-gradient(135deg, #FFFBEB, rgba(245,158,11,0.12));
+  background: linear-gradient(135deg, $dim-wealth-tint, rgba(245,158,11,0.12));
   border-radius: 16rpx;
   border-left: 8rpx solid $dim-wealth;
 }
 .brand-strap-text {
   font-size: 26rpx;
-  color: #92400E;
+  color: $status-warning-strong;
   font-weight: 500;
 }
 
@@ -1152,8 +1152,8 @@ export default {
   padding: 4rpx 12rpx;
   border-radius: 8rpx;
 }
-.insurance-item-status.status-active { background: #DCFCE7; color: #16A34A; }
-.insurance-item-status.status-expired { background: #FEF2F2; color: #DC2626; }
+.insurance-item-status.status-active { background: $status-success-soft; color: $status-success-text; }
+.insurance-item-status.status-expired { background: $status-danger-tint; color: $status-danger-deep; }
 .insurance-item-status.status-cancelled { background: $app-surface-subtle; color: $app-text-muted; }
 .insurance-item-row {
   display: flex;
@@ -1183,7 +1183,7 @@ export default {
   display: flex;
   align-items: center;
   padding: 12rpx 16rpx;
-  background: #FFFBEB;
+  background: $dim-wealth-tint;
   border-radius: 12rpx;
   margin-bottom: 8rpx;
 }
@@ -1204,16 +1204,16 @@ export default {
   font-weight: 500;
 }
 .insight-item-tag.tag-strong {
-  background: #D1FAE5;
-  color: #059669;
+  background: $status-success-soft;
+  color: $status-success-deep;
 }
 .insight-item-tag.tag-improve {
-  background: #FEF3C7;
-  color: #D97706;
+  background: $status-warning-soft;
+  color: $status-warning-deep;
 }
 .insight-tip {
   padding: 12rpx 16rpx;
-  background: #FFFBEB;
+  background: $dim-wealth-tint;
   border-radius: 12rpx;
 }
 .insight-tip-text {
@@ -1265,7 +1265,7 @@ export default {
   justify-content: center;
   margin-right: 10rpx;
   font-size: 20rpx;
-  background: linear-gradient(135deg, #FFF7ED, #FFF3E8);
+  background: linear-gradient(135deg, $dim-wealth-tint, $dim-body-tint);
 }
 .portrait-dim-name {
   font-size: 24rpx;
@@ -1280,7 +1280,7 @@ export default {
 }
 .portrait-dim-bar-track {
   height: 10rpx;
-  background: #FFF7ED;
+  background: $dim-wealth-tint;
   border-radius: 5rpx;
   overflow: hidden;
   margin-bottom: 4rpx;
@@ -1298,21 +1298,21 @@ export default {
 }
 .portrait-tip {
   padding: 16rpx 20rpx;
-  background: linear-gradient(135deg, #FFF7ED, #FFF3E8);
+  background: linear-gradient(135deg, $dim-wealth-tint, $dim-body-tint);
   border-radius: 12rpx;
   border-left: 8rpx solid $dim-wealth;
   margin-top: 16rpx;
 }
 .portrait-tip-text {
   font-size: 22rpx;
-  color: #C2410C;
+  color: $brand-primary-deep;
   line-height: 1.5;
 }
 
 /* 月度引导语 */
 .monthly-guidance {
   margin: 0 30rpx 20rpx;
-  background: linear-gradient(135deg, #FFFBEB, rgba(245,158,11,0.1));
+  background: linear-gradient(135deg, $dim-wealth-tint, rgba(245,158,11,0.1));
   border-radius: 16rpx;
   padding: 20rpx 24rpx;
   display: flex;

+ 49 - 30
cfc-frontend/pages/wisdom-detail/index.vue

@@ -740,6 +740,25 @@ export default {
 </script>
 
 <style scoped lang="scss">
+
+// 页面级局部调色板:仅本页专有色阶,跨页共性一律走 uni.scss 全局令牌
+// 智·深阶(渐变尾)
+$c-wisdom-deep: #4F46E5;
+// 智·亮阶(渐变尾)
+$c-wisdom-light: #818CF8;
+// 智·极深文字
+$c-wisdom-ink: #3730A3;
+// 浅蓝底 A
+$c-tint-a: #F0F4FF;
+// 浅蓝底 B
+$c-tint-b: #F8FAFF;
+// 浅蓝底 C
+$c-tint-c: #EEF2FF;
+// 浅蓝底 D
+$c-tint-d: #E8F1FE;
+// 强文字(深色块内)
+$c-ink-strong: #1D1D1F;
+
 .wisdom-container {
   min-height: 100vh;
   background: $app-bg;
@@ -813,7 +832,7 @@ export default {
 .section-sub {
   flex: 1 1 100%;
   font-size: 22rpx;
-  color: #94A3B8;
+  color: $app-text-subtle;
   line-height: 1.4;
   margin-top: 6rpx;
   display: block;
@@ -856,7 +875,7 @@ export default {
 
 /* 主按钮 */
 .primary-btn {
-  background: linear-gradient(135deg, $dim-wisdom, #4F46E5);
+  background: linear-gradient(135deg, $dim-wisdom, $c-wisdom-deep);
   color: $app-surface;
   font-size: 26rpx;
   font-weight: bold;
@@ -882,7 +901,7 @@ export default {
 .indicator-body { margin-bottom: 8rpx; }
 .indicator-value { font-size: 40rpx; font-weight: bold; color: $dim-wisdom; }
 .indicator-placeholder { font-size: 26rpx; color: $app-border; }
-.indicator-range { font-size: 20rpx; color: #bbb; }
+.indicator-range { font-size: 20rpx; color: $app-border; }
 .bottom-spacer { height: 120rpx; }
 
 /* DAN 报告卡片 */
@@ -909,12 +928,12 @@ export default {
   border-radius: 8rpx;
 }
 .dan-status.confirmed {
-  background: #D1FAE5;
-  color: #065F46;
+  background: $status-success-soft;
+  color: $status-success-strong;
 }
 .dan-status.pending {
-  background: #FEF3C7;
-  color: #92400E;
+  background: $status-warning-soft;
+  color: $status-warning-strong;
 }
 .dan-report-desc {
   font-size: 28rpx;
@@ -943,7 +962,7 @@ export default {
 .avg-badge {
   flex: 1 1 100%;
   font-size: 20rpx;
-  color: #94A3B8;
+  color: $app-text-subtle;
   margin-top: 6rpx;
   display: block;
 }
@@ -952,14 +971,14 @@ export default {
 .brand-strap {
   margin: 16rpx 30rpx 0;
   padding: 24rpx 28rpx;
-  background: linear-gradient(135deg, #F0F0FF, rgba(99,102,241,0.16));
+  background: linear-gradient(135deg, $dim-wisdom-tint, rgba(99,102,241,0.16));
   border-radius: 16rpx;
   border-left: 8rpx solid $dim-wisdom;
   box-shadow: 0 2rpx 12rpx rgba(99,102,241,0.12);
 }
 .brand-strap-text {
   font-size: 26rpx;
-  color: #3730A3;
+  color: $c-wisdom-ink;
   font-weight: bold;
   line-height: 1.5;
 }
@@ -968,7 +987,7 @@ export default {
 .monthly-guidance {
   margin: 16rpx 30rpx 0;
   padding: 20rpx 28rpx;
-  background: linear-gradient(135deg, #F0F0FF, rgba(99,102,241,0.08));
+  background: linear-gradient(135deg, $dim-wisdom-tint, rgba(99,102,241,0.08));
   border-radius: 16rpx;
   border-left: 8rpx solid $dim-wisdom;
   display: flex;
@@ -978,7 +997,7 @@ export default {
 .guidance-icon { font-size: 32rpx; }
 .guidance-text {
   font-size: 26rpx;
-  color: #3730A3;
+  color: $c-wisdom-ink;
   font-weight: 500;
 }
 
@@ -1018,7 +1037,7 @@ export default {
 .gut-indicator-bar-track {
   flex: 1;
   height: 16rpx;
-  background: #F0F0F0;
+  background: $app-surface-subtle;
   border-radius: 8rpx;
   overflow: hidden;
 }
@@ -1041,16 +1060,16 @@ export default {
   text-align: center;
 }
 .status-normal {
-  background: #D1FAE5;
-  color: #059669;
+  background: $status-success-soft;
+  color: $status-success-deep;
 }
 .status-abnormal {
-  background: #FEE2E2;
-  color: #DC2626;
+  background: $status-danger-soft;
+  color: $status-danger-deep;
 }
 .status-warning {
-  background: #FEF3C7;
-  color: #D97706;
+  background: $status-warning-soft;
+  color: $status-warning-deep;
 }
 .gut-empty {
   display: flex;
@@ -1068,7 +1087,7 @@ export default {
   margin-bottom: 24rpx;
 }
 .gut-upload-btn {
-  background: linear-gradient(135deg, $dim-wisdom, #818CF8);
+  background: linear-gradient(135deg, $dim-wisdom, $c-wisdom-light);
   color: $app-surface;
   font-size: 26rpx;
   font-weight: 600;
@@ -1094,7 +1113,7 @@ export default {
   display: flex;
   align-items: center;
   padding: 12rpx 16rpx;
-  background: #F8FAFF;
+  background: $c-tint-b;
   border-radius: 12rpx;
   margin-bottom: 8rpx;
 }
@@ -1115,16 +1134,16 @@ export default {
   font-weight: 500;
 }
 .insight-item-tag.tag-strong {
-  background: #D1FAE5;
-  color: #059669;
+  background: $status-success-soft;
+  color: $status-success-deep;
 }
 .insight-item-tag.tag-improve {
-  background: #FEF3C7;
-  color: #D97706;
+  background: $status-warning-soft;
+  color: $status-warning-deep;
 }
 .insight-tip {
   padding: 12rpx 16rpx;
-  background: #EEF2FF;
+  background: $c-tint-c;
   border-radius: 12rpx;
 }
 .insight-tip-text {
@@ -1143,7 +1162,7 @@ export default {
   margin-bottom: 20rpx;
 }
 .insight-btn {
-  background: linear-gradient(135deg, $dim-wisdom, #818CF8);
+  background: linear-gradient(135deg, $dim-wisdom, $c-wisdom-light);
   color: $app-surface;
   font-size: 26rpx;
   font-weight: 600;
@@ -1212,7 +1231,7 @@ export default {
 }
 .portrait-dim-bar-track {
   height: 10rpx;
-  background: #F0F4FF;
+  background: $c-tint-a;
   border-radius: 5rpx;
   overflow: hidden;
   margin-bottom: 4rpx;
@@ -1230,14 +1249,14 @@ export default {
 }
 .portrait-tip {
   padding: 16rpx 20rpx;
-  background: linear-gradient(135deg, #F0F4FF, #E8F1FE);
+  background: linear-gradient(135deg, $c-tint-a, $c-tint-d);
   border-radius: 12rpx;
   border-left: 8rpx solid $dim-wisdom;
   margin-top: 16rpx;
 }
 .portrait-tip-text {
   font-size: 22rpx;
-  color: #1D1D1F;
+  color: $c-ink-strong;
   line-height: 1.5;
 }
 </style>

+ 61 - 13
cfc-frontend/uni.scss

@@ -22,18 +22,18 @@
 // 1. 品牌色彩 (Brand Colors)
 // ============================================================
 
-/* 主色调 - 柔和天蓝 (Logo蓝色) */
+// 主色调 - 柔和天蓝 (Logo蓝色)
 $uni-primary: #5B9BD5;          // Logo中蓝 - 主品牌色
 $uni-primary-light: #8FC5E8;    // 浅蓝
 $uni-primary-dark: #3A7CC4;     // 深蓝
 $uni-primary-pale: #D6EAF8;     // 极浅蓝 (Logo背景色)
 
-/* 辅助暖色 - 珊瑚粉 (家庭温暖) */
+// 辅助暖色 - 珊瑚粉 (家庭温暖)
 $uni-warm: #F08A7A;             // 心形暖色 - 保留"关爱"感
 $uni-warm-light: #F4B0A5;
 $uni-warm-dark: #E06A58;
 
-/* 语义色 (Semantic) */
+// 语义色 (Semantic)
 $uni-success: #4CAF50;
 $uni-success-light: #81C784;
 $uni-warning: #FFB74D;
@@ -42,7 +42,7 @@ $uni-error: #EF5350;
 $uni-error-light: #E57373;
 $uni-info: #5B9BD5;             // 复用了品牌蓝
 
-/* 中性色 (Neutral) — 冷调中性,匹配蓝色系 */
+// 中性色 (Neutral) — 冷调中性,匹配蓝色系
 $uni-bg-color: #F5F9FC;        // 极浅蓝灰背景
 $uni-bg-color-grey: #EDF2F7;   // 浅灰蓝
 $uni-bg-color-dark: #E2E8F0;   // 灰蓝
@@ -59,7 +59,7 @@ $uni-text-color-inverse: #FFFFFF;
 // 2. 字体系统 (Typography)
 // ============================================================
 
-/* 字体栈 - 小程序不支持自定义字体 */
+// 字体栈 - 小程序不支持自定义字体
 $uni-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
   'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
   'Helvetica Neue', Helvetica, Arial, system-ui, sans-serif;
@@ -67,7 +67,7 @@ $uni-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI',
 $uni-font-family-display: $uni-font-family;
 $uni-font-family-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
 
-/* 字号 */
+// 字号
 $uni-font-size-xs: 20rpx;
 $uni-font-size-sm: 24rpx;
 $uni-font-size-base: 28rpx;
@@ -76,7 +76,7 @@ $uni-font-size-xl: 36rpx;
 $uni-font-size-2xl: 44rpx;
 $uni-font-size-3xl: 52rpx;
 
-/* 字重 */
+// 字重
 $uni-font-weight-normal: 400;
 $uni-font-weight-medium: 500;
 $uni-font-weight-bold: 600;
@@ -348,12 +348,12 @@ $uni-transition-slow: 0.3s ease;
 // 本段补齐「真实在用」的语义令牌;页面改用这些名字,避免逐个硬编码。
 // 注意:mp-weixin 对 CSS var(--x) 运行时解析不稳定,故统一用 SCSS 变量(编译期内联,零运行时风险)。
 
-/* 品牌主色 —— 与 pages.json tabBar.selectedColor 一致 */
+// 品牌主色 —— 与 pages.json tabBar.selectedColor 一致
 $brand-primary: #F97316;
 $brand-primary-dark: #EA580C;
 $brand-primary-soft: rgba(249, 115, 22, 0.12);
 
-/* 五维身份色:页面 PageBanner / 分段左条 / CTA / 价值卡浅底统一取用 */
+// 五维身份色:页面 PageBanner / 分段左条 / CTA / 价值卡浅底统一取用
 $dim-body:   #FF8C42;
 $dim-mind:   #FF6B9D;
 $dim-wisdom: #6366F1;
@@ -366,7 +366,7 @@ $dim-wisdom-soft: rgba(99, 102, 241, 0.15);
 $dim-action-soft: rgba(16, 185, 129, 0.15);
 $dim-wealth-soft: rgba(245, 158, 11, 0.15);
 
-/* 语义角色(与应用真实观感一致) */
+// 语义角色(与应用真实观感一致)
 $app-bg:             #F5F7FA;
 $app-surface:        #FFFFFF;
 $app-surface-subtle: #F7F8FA;
@@ -376,17 +376,17 @@ $app-text-muted:     #8A94A3;
 $app-border-subtle:  #E7EBF0;
 $app-border:         #CBD5E1;
 
-/* 状态:按压/禁用用透明度与语言表达,不新增多套颜色 */
+// 状态:按压/禁用用透明度与语言表达,不新增多套颜色
 $press-opacity:    0.85;
 $disabled-opacity: 0.45;
 
-/* 动效令牌:只声明稳定属性,禁止 transition: all */
+// 动效令牌:只声明稳定属性,禁止 transition: all
 $ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
 $dur-press:      0.12s;
 $dur-state:      0.2s;
 $dur-structural: 0.26s;
 
-/* 可复用 mixin */
+// 可复用 mixin
 @mixin dim-card($radius: $uni-radius-md) {
   background: $app-surface;
   border-radius: $radius;
@@ -402,3 +402,51 @@ $dur-structural: 0.26s;
   min-height: $size;
   min-width: $size;
 }
+
+
+// ============================================================
+// 13. 状态色阶 / 品牌亮阶 / 维度浅底
+// ============================================================
+// 状态色只用于传达状态,禁止当装饰使用;浅底为不透明 tint,用于卡片与分区背景。
+
+// 状态色阶
+$status-success:        #10B981;
+$status-success-soft:   #D1FAE5;
+$status-success-strong: #065F46;
+$status-warning:        #FBBF24;
+$status-warning-soft:   #FEF3C7;
+$status-warning-strong: #92400E;
+$status-danger:         #EF4444;
+$status-danger-soft:    #FEE2E2;
+$status-danger-strong:  #B91C1C;
+
+// 品牌橙亮阶(渐变/高亮用)
+$brand-primary-light:   #FB923C;
+
+// 维度浅底(不透明 tint)
+$dim-body-tint:   #FFF8F0;
+$dim-mind-tint:   #FFF0F5;
+$dim-wisdom-tint: #F0F0FF;
+$dim-action-tint: #F0FFF4;
+$dim-wealth-tint: #FFFBEB;
+
+// 边框与文字的次级阶
+$app-border-strong: #D1D5DB;
+$app-text-subtle:   #94A3B8;
+
+
+// ============================================================
+// 14. 状态深阶 / 品牌深阶(收尾:跨页共性)
+// ============================================================
+// -deep 为色板 600 档,用于状态文字与强调;-tint 为极浅底。
+// 仅收录在 2 个及以上页面中复用的色值,单页专有色阶由页面级局部变量承载。
+
+// 状态深阶(文字 / 强调)
+$status-danger-deep:    #DC2626;  // 危险态文字:较差 / 已过期
+$status-danger-tint:    #FEF2F2;  // 危险态极浅底
+$status-warning-deep:   #D97706;  // 警示态文字
+$status-success-deep:   #059669;  // 成功态文字
+$status-success-text:   #16A34A;  // 成功态文字(green-600)
+
+// 品牌 / 身 深阶文字
+$brand-primary-deep:    #C2410C;