-- 1.软件应用表:管理所有接入自动更新系统的软件 CREATE TABLE IF NOT EXISTS apps ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自增主键ID app_id TEXT NOT NULL UNIQUE, -- 软件唯一标识(客户端用来区分不同软件) app_name TEXT NOT NULL -- 软件展示名称 ); -- 2.软件版本表:存储每个软件各个渠道下的所有版本号 CREATE TABLE IF NOT EXISTS versions ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 版本自增主键version_id,关联文件表 app_id TEXT NOT NULL, -- 关联apps表的软件唯一标识 channel TEXT DEFAULT 'stable', -- 更新渠道:stable正式稳定版 / beta测试版 version TEXT NOT NULL, -- 版本号,如1.0.0、1.0.2 latest INTEGER DEFAULT 0, -- 是否为当前渠道最新版本:1=是最新,0=历史旧版 client_protocol INTEGER NOT NULL DEFAULT 1, -- 该版本客户端支持的更新/策略协议版本 create_time TEXT DEFAULT (datetime('now')), -- 新增:版本创建时间 UNIQUE(app_id, channel, version) -- 联合唯一约束:同一个软件+渠道不能重复存在相同版本 ); -- 3.版本关联文件表:记录每个版本需要更新的全部文件信息(exe、dll、资源文件) CREATE TABLE IF NOT EXISTS version_files ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 文件记录自增ID version_id INTEGER NOT NULL, -- 关联versions表的版本主键id path TEXT NOT NULL, -- 文件在MinIO存储桶内的完整路径 sha256 TEXT NOT NULL, -- 文件哈希值,客户端下载后做完整性/防篡改校验 size INTEGER -- 文件字节大小,用于计算下载进度、校验磁盘空间 ); -- 4.升级日志记录表:存储所有客户端上报的升级结果,用于后台统计排查问题 CREATE TABLE IF NOT EXISTS upgrade_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 日志自增主键 device_id TEXT, -- 用户设备唯一标识,区分不同电脑客户端 from_ver TEXT, -- 升级前本地旧版本号 to_ver TEXT, -- 升级目标新版本号 result TEXT, -- 升级结果:success成功 / fail失败 create_time TEXT -- 升级上报时间 ); --5.日志数据表 CREATE TABLE IF NOT EXISTS update_report ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_id TEXT NOT NULL, app_id TEXT NOT NULL, from_version TEXT NOT NULL, to_version TEXT NOT NULL, result TEXT NOT NULL, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 6. 每个应用/渠道的运行与升级策略;每次保存必须递增 policy_seq CREATE TABLE IF NOT EXISTS version_policies ( id INTEGER PRIMARY KEY AUTOINCREMENT, app_id TEXT NOT NULL, channel TEXT NOT NULL DEFAULT 'stable', policy_seq INTEGER NOT NULL DEFAULT 1, force_update INTEGER NOT NULL DEFAULT 0, allow_rollback INTEGER NOT NULL DEFAULT 0, offline_allowed INTEGER NOT NULL DEFAULT 1, valid_until TEXT NOT NULL, min_supported_version TEXT NOT NULL DEFAULT '', disabled_versions TEXT NOT NULL DEFAULT '[]', git_tags_enabled INTEGER NOT NULL DEFAULT 0, message TEXT NOT NULL DEFAULT '', created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), UNIQUE(app_id, channel) ); -- 7. RSA 签发的客户端设备身份 CREATE TABLE IF NOT EXISTS devices ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_id TEXT NOT NULL UNIQUE, app_id TEXT NOT NULL, installation_id TEXT NOT NULL, machine_hash TEXT NOT NULL DEFAULT '', credential_seq INTEGER NOT NULL DEFAULT 1, disabled INTEGER NOT NULL DEFAULT 0, disabled_reason TEXT NOT NULL DEFAULT '', first_seen_at TEXT DEFAULT (datetime('now')), last_seen_at TEXT DEFAULT (datetime('now')), last_ip TEXT NOT NULL DEFAULT '', UNIQUE(app_id, installation_id) ); -- 8. 软件授权及其设备占用关系 CREATE TABLE IF NOT EXISTS licenses ( id INTEGER PRIMARY KEY AUTOINCREMENT, license_id TEXT NOT NULL UNIQUE, license_key_hash TEXT NOT NULL UNIQUE, license_key_cipher TEXT NOT NULL DEFAULT '', customer_name TEXT NOT NULL, app_id TEXT NOT NULL, channel_code TEXT NOT NULL DEFAULT 'stable', max_devices INTEGER NOT NULL DEFAULT 1, valid_until TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')) ); CREATE TABLE IF NOT EXISTS license_devices ( license_id TEXT NOT NULL, device_id TEXT NOT NULL UNIQUE, bound_at TEXT DEFAULT (datetime('now')), PRIMARY KEY(license_id,device_id) ); -- 9. 每个应用独立维护的动态发布渠道 CREATE TABLE IF NOT EXISTS channels ( id INTEGER PRIMARY KEY AUTOINCREMENT, app_id TEXT NOT NULL, channel_code TEXT NOT NULL, display_name TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, sort_order INTEGER NOT NULL DEFAULT 100, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), UNIQUE(app_id, channel_code) ); -- 10. 文件下载授权与客户端完成结果 CREATE TABLE IF NOT EXISTS download_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_id TEXT NOT NULL, license_id TEXT NOT NULL, app_id TEXT NOT NULL, version TEXT NOT NULL, channel_code TEXT NOT NULL, file_path TEXT NOT NULL, file_size INTEGER NOT NULL DEFAULT 0, result TEXT NOT NULL, ip TEXT NOT NULL DEFAULT '', user_agent TEXT NOT NULL DEFAULT '', created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_download_logs_created ON download_logs(created_at); CREATE INDEX IF NOT EXISTS idx_download_logs_device ON download_logs(device_id,created_at); -- 11. 管理后台写操作审计 CREATE TABLE IF NOT EXISTS admin_audit_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, actor_hash TEXT NOT NULL, actor_username TEXT NOT NULL DEFAULT '', actor_roles TEXT NOT NULL DEFAULT '', auth_type TEXT NOT NULL DEFAULT '', action TEXT NOT NULL, method TEXT NOT NULL, path TEXT NOT NULL, target TEXT NOT NULL DEFAULT '', result TEXT NOT NULL, status_code INTEGER NOT NULL, ip TEXT NOT NULL DEFAULT '', user_agent TEXT NOT NULL DEFAULT '', created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_admin_audit_created ON admin_audit_logs(created_at); -- 11.1 管理后台用户、角色与刷新令牌 CREATE TABLE IF NOT EXISTS admin_users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, display_name TEXT NOT NULL DEFAULT '', roles TEXT NOT NULL DEFAULT '["super_admin"]', status TEXT NOT NULL DEFAULT 'active', created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), last_login_at TEXT ); CREATE INDEX IF NOT EXISTS idx_admin_users_status ON admin_users(status); CREATE TABLE IF NOT EXISTS admin_refresh_tokens ( id INTEGER PRIMARY KEY AUTOINCREMENT, token_id TEXT NOT NULL UNIQUE, username TEXT NOT NULL, token_hash TEXT NOT NULL, expires_at TEXT NOT NULL, revoked_at TEXT, created_at TEXT DEFAULT (datetime('now')), user_agent TEXT NOT NULL DEFAULT '', ip TEXT NOT NULL DEFAULT '' ); CREATE INDEX IF NOT EXISTS idx_admin_refresh_tokens_username ON admin_refresh_tokens(username,expires_at); -- 12. SimCAE 崩溃报告原始数据索引 CREATE TABLE IF NOT EXISTS crash_reports ( id INTEGER PRIMARY KEY AUTOINCREMENT, report_id TEXT NOT NULL UNIQUE, client_report_id TEXT NOT NULL UNIQUE, content_hash TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'stored', symbolication_status TEXT NOT NULL DEFAULT 'not_started', product TEXT NOT NULL, app_version TEXT NOT NULL, git_commit TEXT NOT NULL, build_type TEXT NOT NULL, channel TEXT NOT NULL, exception_code TEXT NOT NULL DEFAULT '', crash_time_utc TEXT NOT NULL, received_at_utc TEXT NOT NULL, remote_address TEXT NOT NULL DEFAULT '', content_length INTEGER NOT NULL DEFAULT 0, metadata_sha256 TEXT NOT NULL, metadata_size INTEGER NOT NULL DEFAULT 0, minidump_sha256 TEXT NOT NULL, minidump_size INTEGER NOT NULL DEFAULT 0, attachments_sha256 TEXT NOT NULL DEFAULT '', attachments_size INTEGER NOT NULL DEFAULT 0, storage_path TEXT NOT NULL, metadata_json TEXT NOT NULL, server_json TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_crash_reports_build ON crash_reports(product,app_version,git_commit); CREATE INDEX IF NOT EXISTS idx_crash_reports_exception ON crash_reports(exception_code); CREATE INDEX IF NOT EXISTS idx_crash_reports_received ON crash_reports(received_at_utc); -- 13. SimCAE 符号包上传索引 CREATE TABLE IF NOT EXISTS crash_symbol_uploads ( id INTEGER PRIMARY KEY AUTOINCREMENT, symbol_upload_id TEXT NOT NULL UNIQUE, identity_hash TEXT NOT NULL UNIQUE, status TEXT NOT NULL DEFAULT 'stored', product TEXT NOT NULL, app_version TEXT NOT NULL, git_commit TEXT NOT NULL, build_type TEXT NOT NULL, platform TEXT NOT NULL, toolchain TEXT NOT NULL, created_at_utc TEXT NOT NULL, received_at_utc TEXT NOT NULL, metadata_sha256 TEXT NOT NULL, metadata_size INTEGER NOT NULL DEFAULT 0, symbols_sha256 TEXT NOT NULL, symbols_size INTEGER NOT NULL DEFAULT 0, storage_path TEXT NOT NULL, metadata_json TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_crash_symbols_build ON crash_symbol_uploads(product,app_version,git_commit,build_type,platform); CREATE INDEX IF NOT EXISTS idx_crash_symbols_received ON crash_symbol_uploads(received_at_utc); -- 14. 崩溃原始文件访问审计 CREATE TABLE IF NOT EXISTS crash_file_access_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, report_id TEXT NOT NULL, file_name TEXT NOT NULL, actor_hash TEXT NOT NULL, ip TEXT NOT NULL DEFAULT '', user_agent TEXT NOT NULL DEFAULT '', created_at TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_crash_file_access_report ON crash_file_access_logs(report_id,created_at);