schema.sql 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. -- ============================================
  2. -- TG Live Game D1 Database Schema
  3. -- Database: tg_live_game
  4. -- Engine: Cloudflare D1 (SQLite)
  5. -- ============================================
  6. -- 摄像头管理表
  7. CREATE TABLE IF NOT EXISTS cameras (
  8. id TEXT PRIMARY KEY,
  9. name TEXT NOT NULL,
  10. type TEXT CHECK(type IN ('mac', 'ip', 'rtsp', 'screen')),
  11. protocol TEXT CHECK(protocol IN ('rtmps', 'srt', 'whip')),
  12. rtsp_url TEXT,
  13. location TEXT,
  14. status TEXT DEFAULT 'offline' CHECK(status IN ('online', 'offline', 'error')),
  15. live_input_id TEXT, -- Cloudflare Stream Live Input ID
  16. meta TEXT, -- JSON 扩展字段
  17. created_at INTEGER DEFAULT (strftime('%s', 'now')),
  18. updated_at INTEGER DEFAULT (strftime('%s', 'now'))
  19. );
  20. CREATE INDEX IF NOT EXISTS idx_cameras_status ON cameras(status);
  21. CREATE INDEX IF NOT EXISTS idx_cameras_type ON cameras(type);
  22. CREATE INDEX IF NOT EXISTS idx_cameras_live_input ON cameras(live_input_id);
  23. -- 直播会话表
  24. CREATE TABLE IF NOT EXISTS live_sessions (
  25. id TEXT PRIMARY KEY,
  26. camera_id TEXT NOT NULL REFERENCES cameras(id) ON DELETE CASCADE,
  27. live_input_id TEXT NOT NULL, -- Cloudflare Stream Live Input ID
  28. started_at INTEGER NOT NULL,
  29. ended_at INTEGER,
  30. duration INTEGER, -- 秒
  31. status TEXT DEFAULT 'live' CHECK(status IN ('live', 'ended', 'error')),
  32. viewer_count INTEGER DEFAULT 0,
  33. peak_viewers INTEGER DEFAULT 0,
  34. recording_id TEXT, -- 录像视频 ID
  35. meta TEXT, -- JSON 扩展字段
  36. created_at INTEGER DEFAULT (strftime('%s', 'now'))
  37. );
  38. CREATE INDEX IF NOT EXISTS idx_sessions_camera ON live_sessions(camera_id);
  39. CREATE INDEX IF NOT EXISTS idx_sessions_status ON live_sessions(status);
  40. CREATE INDEX IF NOT EXISTS idx_sessions_started ON live_sessions(started_at);
  41. -- 视频元数据表 (扩展 Cloudflare Stream 视频)
  42. CREATE TABLE IF NOT EXISTS videos (
  43. id TEXT PRIMARY KEY,
  44. cf_uid TEXT UNIQUE NOT NULL, -- Cloudflare Stream Video UID
  45. camera_id TEXT REFERENCES cameras(id) ON DELETE SET NULL,
  46. session_id TEXT REFERENCES live_sessions(id) ON DELETE SET NULL,
  47. title TEXT,
  48. description TEXT,
  49. tags TEXT, -- JSON array
  50. thumbnail TEXT,
  51. duration INTEGER, -- 秒
  52. size INTEGER, -- 字节
  53. status TEXT DEFAULT 'processing' CHECK(status IN ('ready', 'processing', 'error')),
  54. is_public INTEGER DEFAULT 0,
  55. view_count INTEGER DEFAULT 0,
  56. created_at INTEGER DEFAULT (strftime('%s', 'now')),
  57. updated_at INTEGER DEFAULT (strftime('%s', 'now'))
  58. );
  59. CREATE INDEX IF NOT EXISTS idx_videos_cf_uid ON videos(cf_uid);
  60. CREATE INDEX IF NOT EXISTS idx_videos_camera ON videos(camera_id);
  61. CREATE INDEX IF NOT EXISTS idx_videos_session ON videos(session_id);
  62. CREATE INDEX IF NOT EXISTS idx_videos_status ON videos(status);
  63. -- 用户表
  64. CREATE TABLE IF NOT EXISTS users (
  65. id TEXT PRIMARY KEY,
  66. username TEXT UNIQUE NOT NULL,
  67. email TEXT UNIQUE,
  68. password_hash TEXT,
  69. role TEXT DEFAULT 'viewer' CHECK(role IN ('admin', 'operator', 'viewer')),
  70. status TEXT DEFAULT 'active' CHECK(status IN ('active', 'disabled')),
  71. last_login INTEGER,
  72. created_at INTEGER DEFAULT (strftime('%s', 'now')),
  73. updated_at INTEGER DEFAULT (strftime('%s', 'now'))
  74. );
  75. CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
  76. CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
  77. CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
  78. -- 用户权限表
  79. CREATE TABLE IF NOT EXISTS user_permissions (
  80. id TEXT PRIMARY KEY,
  81. user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  82. camera_id TEXT NOT NULL REFERENCES cameras(id) ON DELETE CASCADE,
  83. permission TEXT NOT NULL CHECK(permission IN ('view', 'control', 'manage')),
  84. granted_at INTEGER DEFAULT (strftime('%s', 'now')),
  85. granted_by TEXT REFERENCES users(id) ON DELETE SET NULL,
  86. UNIQUE(user_id, camera_id)
  87. );
  88. CREATE INDEX IF NOT EXISTS idx_perms_user ON user_permissions(user_id);
  89. CREATE INDEX IF NOT EXISTS idx_perms_camera ON user_permissions(camera_id);
  90. -- 观看统计表
  91. CREATE TABLE IF NOT EXISTS view_stats (
  92. id TEXT PRIMARY KEY,
  93. video_id TEXT REFERENCES videos(id) ON DELETE CASCADE,
  94. session_id TEXT REFERENCES live_sessions(id) ON DELETE CASCADE,
  95. user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
  96. ip_address TEXT,
  97. user_agent TEXT,
  98. watch_duration INTEGER, -- 秒
  99. started_at INTEGER NOT NULL,
  100. ended_at INTEGER,
  101. country TEXT,
  102. city TEXT,
  103. created_at INTEGER DEFAULT (strftime('%s', 'now'))
  104. );
  105. CREATE INDEX IF NOT EXISTS idx_stats_video ON view_stats(video_id);
  106. CREATE INDEX IF NOT EXISTS idx_stats_session ON view_stats(session_id);
  107. CREATE INDEX IF NOT EXISTS idx_stats_started ON view_stats(started_at);
  108. -- 操作日志表
  109. CREATE TABLE IF NOT EXISTS audit_logs (
  110. id TEXT PRIMARY KEY,
  111. user_id TEXT REFERENCES users(id) ON DELETE SET NULL,
  112. action TEXT NOT NULL CHECK(action IN ('create', 'update', 'delete', 'login', 'logout')),
  113. resource TEXT NOT NULL, -- 'camera', 'video', 'user', 'session'
  114. resource_id TEXT,
  115. details TEXT, -- JSON
  116. ip_address TEXT,
  117. created_at INTEGER DEFAULT (strftime('%s', 'now'))
  118. );
  119. CREATE INDEX IF NOT EXISTS idx_audit_user ON audit_logs(user_id);
  120. CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_logs(action);
  121. CREATE INDEX IF NOT EXISTS idx_audit_resource ON audit_logs(resource);
  122. CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_logs(created_at);
  123. -- ============================================
  124. -- 初始化数据
  125. -- ============================================
  126. -- 创建默认管理员用户 (密码需要后续更新)
  127. INSERT OR IGNORE INTO users (id, username, email, role, status)
  128. VALUES ('admin-001', 'admin', 'admin@tg-live.local', 'admin', 'active');