Files
blog/blog-admin/schema.sql
T
zqlit a74b3c7127
Deploy to Production / pre-check (push) Successful in 58s
Deploy to Production / build (push) Successful in 4m3s
Deploy to Production / deploy-edgeone (push) Successful in 3m48s
Deploy to Production / finalize (push) Successful in 26s
Deploy to Production / notify-failure (push) Skipped
归档 artalk-cf 评论后端 + rss-robot 到 blog-admin(含技术选型/模块分布 README)
2026-10-04 08:45:40 +08:00

140 lines
6.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ===========================================================================
-- artalk-cf —— D1 / SQLite schema
-- 执行:npx wrangler d1 execute artalk-cf --remote --file=./schema.sql
-- 设计与 Artalk v2 的 gorm 模型对应,但时间统一存 unix 毫秒(INTEGER),
-- 输出时再按 Asia/Shanghai 格式化成 "YYYY-MM-DD HH:mm:ss"。
-- ===========================================================================
CREATE TABLE IF NOT EXISTS sites (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
urls TEXT NOT NULL DEFAULT '', -- 逗号分隔
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS pages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT NOT NULL, -- Artalk 的 page_key,如 /20210911.html
site_name TEXT NOT NULL,
title TEXT NOT NULL DEFAULT '',
admin_only INTEGER NOT NULL DEFAULT 0,
pv INTEGER NOT NULL DEFAULT 0,
vote_up INTEGER NOT NULL DEFAULT 0,
vote_down INTEGER NOT NULL DEFAULT 0,
accessible_url TEXT NOT NULL DEFAULT '',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_pages_key_site ON pages (key, site_name);
CREATE INDEX IF NOT EXISTS idx_pages_site ON pages (site_name);
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
link TEXT NOT NULL DEFAULT '',
password TEXT NOT NULL DEFAULT '', -- 空 = 无密码;支持 (pbkdf2) / (md5) / 明文(兼容)
badge_name TEXT NOT NULL DEFAULT '',
badge_color TEXT NOT NULL DEFAULT '',
title_name TEXT NOT NULL DEFAULT '', -- 头衔徽章(金色,优先级仅次于系统徽章)
last_ip TEXT NOT NULL DEFAULT '',
last_ua TEXT NOT NULL DEFAULT '',
is_admin INTEGER NOT NULL DEFAULT 0,
receive_email INTEGER NOT NULL DEFAULT 1,
is_in_conf INTEGER NOT NULL DEFAULT 0,
token_valid_from INTEGER NOT NULL DEFAULT 0, -- 早于此刻签发的 token 失效(改密码后踢下线)
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_name_email ON users (name, email);
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL,
page_key TEXT NOT NULL,
site_name TEXT NOT NULL,
user_id INTEGER NOT NULL,
rid INTEGER NOT NULL DEFAULT 0, -- 直接父节点 id(0 = 顶层)
root_id INTEGER NOT NULL DEFAULT 0, -- 顶层祖先 id(顶层为 0)
is_collapsed INTEGER NOT NULL DEFAULT 0,
is_pending INTEGER NOT NULL DEFAULT 0,
is_pinned INTEGER NOT NULL DEFAULT 0,
is_verified INTEGER NOT NULL DEFAULT 0,
vote_up INTEGER NOT NULL DEFAULT 0,
vote_down INTEGER NOT NULL DEFAULT 0,
ua TEXT NOT NULL DEFAULT '',
ip TEXT NOT NULL DEFAULT '',
ip_region TEXT NOT NULL DEFAULT '',
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
deleted_at INTEGER NOT NULL DEFAULT 0 -- 软删除,0 = 未删除
);
CREATE INDEX IF NOT EXISTS idx_comments_page ON comments (page_key, site_name, deleted_at);
CREATE INDEX IF NOT EXISTS idx_comments_root ON comments (root_id, deleted_at);
CREATE INDEX IF NOT EXISTS idx_comments_user ON comments (user_id, deleted_at);
CREATE INDEX IF NOT EXISTS idx_comments_created ON comments (created_at);
-- 列表/计数覆盖索引:原来列表要 ORDER BY is_pinned DESC, created_at DESC,
-- 没有匹配索引 → SQLite 每次全表扫 ~1000 行(实测列表 940 行/次、计数 1500-2000 行/次,
-- 是 D1 免费额度被打爆的主因)。带上这些列后只读命中行。
CREATE INDEX IF NOT EXISTS idx_comments_page_list
ON comments (site_name, page_key, deleted_at, is_pending, is_pinned DESC, created_at DESC, id DESC);
-- 子评论拉取(root_id IN (...))专用:让 SQLite 按 root_id seek,而不是扫整页
CREATE INDEX IF NOT EXISTS idx_comments_children
ON comments (root_id, deleted_at, is_pending, created_at, id);
CREATE INDEX IF NOT EXISTS idx_comments_site_list
ON comments (site_name, deleted_at, is_pending, created_at DESC, id DESC);
CREATE TABLE IF NOT EXISTS votes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
target_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
type TEXT NOT NULL, -- 'comment' | 'page'
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_votes_unique ON votes (target_id, user_id, type);
CREATE TABLE IF NOT EXISTS notifies (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
comment_id INTEGER NOT NULL,
is_read INTEGER NOT NULL DEFAULT 0,
is_emailed INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_notifies_user ON notifies (user_id, is_read);
-- 键值配置:frontend_conf / admin_users / moderator / captcha / ip_region / ...
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at INTEGER NOT NULL
);
-- 简单限流:按 IP + 动作统计,60 秒窗口
CREATE TABLE IF NOT EXISTS rate_limits (
bucket TEXT PRIMARY KEY, -- 如 "comment:1.2.3.4"
count INTEGER NOT NULL DEFAULT 0,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_rate_expires ON rate_limits (expires_at);
-- 验证码通过状态(按 IP 记,跨域请求带不上 cookie,所以放服务端)
CREATE TABLE IF NOT EXISTS captcha_passes (
ip TEXT PRIMARY KEY,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_captcha_expires ON captcha_passes (expires_at);
-- 验证码题目:answer 只存哈希,防止有人直接读库
CREATE TABLE IF NOT EXISTS captcha_challenges (
id TEXT PRIMARY KEY,
answer_hash TEXT NOT NULL,
ip TEXT NOT NULL,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_captcha_ch_expires ON captcha_challenges (expires_at);