Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .cursor/environment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "Cloud Mail",
"install": "corepack enable && corepack prepare pnpm@10.33.3 --activate && cd mail-worker && pnpm install && cd ../mail-vue && pnpm install && pnpm run build && cd ../mail-worker && npx wrangler d1 execute email --local --config wrangler-dev.toml --file db/local-init.sql",
"terminals": [
{
"name": "mail-worker (Hono API + SPA, :8787)",
"command": "cd mail-worker && npx wrangler dev --config wrangler-dev.toml --port 8787 --ip 0.0.0.0"
},
{
"name": "mail-vue (Vite dev server, :3001)",
"command": "cd mail-vue && pnpm run dev"
}
],
"ports": [8787, 3001]
}
313 changes: 313 additions & 0 deletions mail-worker/db/local-init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
-- =====================================================
-- Cloud-Mail 本地开发数据库初始化脚本 (local dev only)
-- 用途: 为 wrangler dev 的本地 D1 (miniflare) 建立完整 schema + 最小种子数据
-- 依据: mail-worker/src/entity/*.js (Drizzle ORM 实体定义为 schema 单一事实来源)
-- 说明: 仓库内 migrations/ 仅覆盖 share 相关表, 缺少 perm/role_perm/reg_key/
-- star/attachments/verify_record 等基础表与 setting/role 种子数据,
-- 导致全新本地库无法完成注册/登录。本脚本补齐全部表并可重复执行 (幂等)。
-- =====================================================

-- ---------- 用户表 ----------
CREATE TABLE IF NOT EXISTS user (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL,
type INTEGER DEFAULT 1 NOT NULL,
password TEXT NOT NULL,
salt TEXT NOT NULL,
status INTEGER DEFAULT 0 NOT NULL,
create_time TEXT DEFAULT CURRENT_TIMESTAMP,
active_time TEXT,
create_ip TEXT,
active_ip TEXT,
os TEXT,
browser TEXT,
device TEXT,
sort TEXT DEFAULT 0,
send_count TEXT DEFAULT 0,
reg_key_id INTEGER DEFAULT 0 NOT NULL,
is_del INTEGER DEFAULT 0 NOT NULL
);

-- ---------- 账户表 ----------
CREATE TABLE IF NOT EXISTS account (
account_id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL,
name TEXT DEFAULT '' NOT NULL,
status INTEGER DEFAULT 0 NOT NULL,
latest_email_time TEXT,
create_time TEXT DEFAULT CURRENT_TIMESTAMP,
user_id INTEGER NOT NULL,
is_del INTEGER DEFAULT 0 NOT NULL
);

-- ---------- 邮件表 ----------
CREATE TABLE IF NOT EXISTS email (
email_id INTEGER PRIMARY KEY AUTOINCREMENT,
send_email TEXT,
name TEXT,
account_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
subject TEXT,
text TEXT,
content TEXT,
cc TEXT DEFAULT '[]',
bcc TEXT DEFAULT '[]',
recipient TEXT,
to_email TEXT DEFAULT '' NOT NULL,
to_name TEXT DEFAULT '' NOT NULL,
in_reply_to TEXT DEFAULT '',
relation TEXT DEFAULT '',
message_id TEXT DEFAULT '',
type INTEGER DEFAULT 0 NOT NULL,
status INTEGER DEFAULT 0 NOT NULL,
resend_email_id TEXT,
message TEXT,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
is_del INTEGER DEFAULT 0 NOT NULL,
is_read INTEGER DEFAULT 0 NOT NULL,
read_count INTEGER DEFAULT 0 NOT NULL
);

-- ---------- 附件表 ----------
CREATE TABLE IF NOT EXISTS attachments (
att_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
email_id INTEGER NOT NULL,
account_id INTEGER NOT NULL,
key TEXT NOT NULL,
filename TEXT,
mime_type TEXT,
size INTEGER,
status TEXT DEFAULT 0 NOT NULL,
type INTEGER DEFAULT 0 NOT NULL,
disposition TEXT,
related TEXT,
content_id TEXT,
encoding TEXT,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);

-- ---------- 星标表 ----------
CREATE TABLE IF NOT EXISTS star (
star_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
email_id INTEGER NOT NULL,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);

-- ---------- 角色表 ----------
CREATE TABLE IF NOT EXISTS role (
role_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
key TEXT NOT NULL,
description TEXT,
ban_email TEXT DEFAULT '' NOT NULL,
ban_email_type INTEGER DEFAULT 0 NOT NULL,
avail_domain TEXT DEFAULT '',
sort INTEGER,
is_default INTEGER DEFAULT 0,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
user_id INTEGER,
send_count INTEGER,
send_type TEXT DEFAULT 'count',
account_count INTEGER
);

-- ---------- 权限表 ----------
CREATE TABLE IF NOT EXISTS perm (
perm_id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
perm_key TEXT,
pid INTEGER DEFAULT 0 NOT NULL,
type INTEGER DEFAULT 2 NOT NULL,
sort INTEGER
);

-- ---------- 角色-权限关联表 ----------
CREATE TABLE IF NOT EXISTS role_perm (
id INTEGER PRIMARY KEY AUTOINCREMENT,
role_id INTEGER,
perm_id INTEGER
);

-- ---------- 注册卡密表 ----------
CREATE TABLE IF NOT EXISTS reg_key (
rege_key_id INTEGER PRIMARY KEY AUTOINCREMENT,
code TEXT DEFAULT '' NOT NULL,
count INTEGER DEFAULT 0 NOT NULL,
role_id INTEGER DEFAULT 0 NOT NULL,
user_id INTEGER DEFAULT 0 NOT NULL,
expire_time TEXT,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);

-- ---------- 人机验证记录表 ----------
CREATE TABLE IF NOT EXISTS verify_record (
vr_id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT DEFAULT '' NOT NULL,
count INTEGER DEFAULT 1 NOT NULL,
type INTEGER DEFAULT 0 NOT NULL,
update_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);

-- ---------- 系统设置表 (单行配置) ----------
CREATE TABLE IF NOT EXISTS setting (
register INTEGER DEFAULT 0 NOT NULL,
receive INTEGER DEFAULT 0 NOT NULL,
title TEXT DEFAULT '' NOT NULL,
many_email INTEGER DEFAULT 1 NOT NULL,
add_email INTEGER DEFAULT 0 NOT NULL,
auto_refresh_time INTEGER DEFAULT 0 NOT NULL,
add_email_verify INTEGER DEFAULT 1 NOT NULL,
register_verify INTEGER DEFAULT 1 NOT NULL,
reg_verify_count INTEGER DEFAULT 1 NOT NULL,
add_verify_count INTEGER DEFAULT 1 NOT NULL,
send INTEGER DEFAULT 1 NOT NULL,
r2_domain TEXT,
secret_key TEXT,
site_key TEXT,
reg_key INTEGER DEFAULT 1 NOT NULL,
background TEXT,
tg_bot_token TEXT DEFAULT '' NOT NULL,
tg_chat_id TEXT DEFAULT '' NOT NULL,
tg_bot_status INTEGER DEFAULT 1 NOT NULL,
forward_email TEXT DEFAULT '' NOT NULL,
forward_status INTEGER DEFAULT 1 NOT NULL,
rule_email TEXT DEFAULT '' NOT NULL,
rule_type INTEGER DEFAULT 0 NOT NULL,
login_opacity REAL DEFAULT 0.88,
resend_tokens TEXT DEFAULT '{}' NOT NULL,
notice_title TEXT DEFAULT '' NOT NULL,
notice_content TEXT DEFAULT '' NOT NULL,
notice_type TEXT DEFAULT '' NOT NULL,
notice_duration INTEGER DEFAULT 0 NOT NULL,
notice_position TEXT DEFAULT '' NOT NULL,
notice_offset INTEGER DEFAULT 0 NOT NULL,
notice_width INTEGER DEFAULT 400 NOT NULL,
notice INTEGER DEFAULT 0 NOT NULL,
global_announcement_content TEXT,
global_announcement_version INTEGER,
global_announcement_enabled INTEGER DEFAULT 0 NOT NULL,
global_announcement_title TEXT DEFAULT '' NOT NULL,
global_announcement_display_mode TEXT DEFAULT 'always' NOT NULL,
global_announcement_images TEXT DEFAULT '[]' NOT NULL,
global_announcement_override_share_announcement INTEGER DEFAULT 0 NOT NULL,
global_announcement_auto_apply_new_share INTEGER DEFAULT 1 NOT NULL,
no_recipient INTEGER DEFAULT 1 NOT NULL,
login_domain INTEGER DEFAULT 0 NOT NULL,
bucket TEXT DEFAULT '' NOT NULL,
region TEXT DEFAULT '' NOT NULL,
endpoint TEXT DEFAULT '' NOT NULL,
s3_access_key TEXT DEFAULT '' NOT NULL,
s3_secret_key TEXT DEFAULT '' NOT NULL,
share_whitelist TEXT DEFAULT '' NOT NULL
);

-- ---------- 分享表 ----------
CREATE TABLE IF NOT EXISTS share (
share_id INTEGER PRIMARY KEY AUTOINCREMENT,
share_token TEXT NOT NULL UNIQUE,
target_email TEXT NOT NULL,
share_name TEXT NOT NULL,
keyword_filter TEXT DEFAULT '',
expire_time TEXT NOT NULL,
create_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
user_id INTEGER NOT NULL,
is_active INTEGER DEFAULT 1 NOT NULL,
rate_limit_per_second INTEGER DEFAULT 5 NOT NULL,
auto_recovery_seconds INTEGER DEFAULT 60 NOT NULL,
status TEXT DEFAULT 'active',
otp_count_daily INTEGER DEFAULT 0,
otp_limit_daily INTEGER DEFAULT 100,
last_reset_date TEXT,
remark TEXT DEFAULT '',
share_type INTEGER DEFAULT 1 NOT NULL,
authorized_emails TEXT DEFAULT '[]' NOT NULL,
verification_code_limit INTEGER DEFAULT 100 NOT NULL,
verification_code_limit_enabled INTEGER DEFAULT 1 NOT NULL,
otp_limit_enabled INTEGER DEFAULT 1 NOT NULL,
share_domain TEXT,
latest_email_count INTEGER,
auto_refresh_enabled INTEGER DEFAULT 0 NOT NULL,
auto_refresh_interval INTEGER DEFAULT 30 NOT NULL,
filter_mode INTEGER DEFAULT 1 NOT NULL,
template_id TEXT,
show_full_email INTEGER DEFAULT 1 NOT NULL,
cooldown_enabled INTEGER DEFAULT 1 NOT NULL,
cooldown_seconds INTEGER DEFAULT 10 NOT NULL,
enable_captcha INTEGER DEFAULT 0 NOT NULL,
announcement_content TEXT,
announcement_version INTEGER,
use_global_announcement INTEGER DEFAULT 1 NOT NULL
);

-- ---------- 分享访问日志表 ----------
CREATE TABLE IF NOT EXISTS share_access_log (
log_id INTEGER PRIMARY KEY AUTOINCREMENT,
share_id INTEGER NOT NULL,
share_token TEXT NOT NULL,
access_ip TEXT NOT NULL,
user_agent TEXT DEFAULT '',
access_email TEXT NOT NULL,
extracted_codes TEXT DEFAULT '[]',
access_result TEXT NOT NULL,
error_message TEXT DEFAULT '',
access_time TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
response_time INTEGER DEFAULT 0,
email_count INTEGER DEFAULT 0,
email_ids TEXT DEFAULT '[]'
);

-- ---------- 邮件模板表 ----------
CREATE TABLE IF NOT EXISTS email_templates (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
sender_pattern TEXT,
subject_pattern TEXT,
body_pattern TEXT,
extraction_regex TEXT NOT NULL,
code_format TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
user_id INTEGER NOT NULL,
is_active INTEGER DEFAULT 1 NOT NULL,
description TEXT,
example_email TEXT,
example_code TEXT
);

-- ---------- 公告已读表 ----------
CREATE TABLE IF NOT EXISTS announcement_read (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
announcement_version INTEGER NOT NULL,
read_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
UNIQUE(user_id, announcement_version)
);

-- ---------- 索引 ----------
CREATE INDEX IF NOT EXISTS idx_user_email ON user(email);
CREATE INDEX IF NOT EXISTS idx_account_email ON account(email);
CREATE INDEX IF NOT EXISTS idx_account_user_id ON account(user_id);
CREATE INDEX IF NOT EXISTS idx_email_user_id ON email(user_id);
CREATE INDEX IF NOT EXISTS idx_email_account_id ON email(account_id);
CREATE INDEX IF NOT EXISTS idx_star_user_id ON star(user_id);
CREATE INDEX IF NOT EXISTS idx_att_email_id ON attachments(email_id);
CREATE INDEX IF NOT EXISTS idx_share_user_id ON share(user_id);
CREATE INDEX IF NOT EXISTS idx_share_token ON share(share_token);
CREATE INDEX IF NOT EXISTS idx_share_access_log_share_id ON share_access_log(share_id);
CREATE INDEX IF NOT EXISTS idx_share_access_log_token ON share_access_log(share_token);

-- =====================================================
-- 最小种子数据 (仅当表为空时插入, 保证幂等)
-- =====================================================

-- 默认角色: 普通用户 (is_default=1, avail_domain 为空 => 允许全部域名)
INSERT INTO role (name, key, description, ban_email, ban_email_type, avail_domain, sort, is_default, send_count, send_type, account_count)
SELECT '普通用户', 'user', '默认注册角色', '', 0, '', 1, 1, 100, 'day', 5
WHERE NOT EXISTS (SELECT 1 FROM role);

-- 系统设置单行: register=0(开放注册), register_verify=1(关闭人机验证), reg_key=1(关闭卡密)
INSERT INTO setting (register)
SELECT 0
WHERE NOT EXISTS (SELECT 1 FROM setting);
Loading