-- WmailHub D1 初始schema -- Console 运行时也会在本地模式下自动执行等价初始化(幂等) CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL ); -- 节点(转发平面) CREATE TABLE IF NOT EXISTS nodes ( id TEXT PRIMARY KEY, name TEXT NOT NULL, cloudflare_account_id TEXT, credential_id TEXT, status TEXT NOT NULL DEFAULT 'pending_oauth', -- pending_oauth | provisioning | offline | online | revoked version TEXT, last_seen_at TEXT, ingress_url TEXT, ingress_secret_enc TEXT, enrollment_token TEXT, enrollment_expires_at TEXT, provision_steps TEXT, -- JSON: 各安装步骤状态 created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); -- 节点凭据:secret_hash 为摘要,secret_enc 为 AES-GCM 密文(HMAC 验签需要原文,加密存储防拖库泄露) CREATE TABLE IF NOT EXISTS node_credentials ( id TEXT PRIMARY KEY, node_id TEXT NOT NULL, secret_hash TEXT NOT NULL, secret_enc TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', -- active | revoked created_at TEXT NOT NULL, revoked_at TEXT ); CREATE INDEX IF NOT EXISTS idx_node_credentials_node ON node_credentials(node_id); CREATE TABLE IF NOT EXISTS domains ( id TEXT PRIMARY KEY, cloudflare_account_id TEXT NOT NULL, node_id TEXT, name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', -- pending | active | error worker_id TEXT, zone_id TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, UNIQUE(cloudflare_account_id, name) ); CREATE TABLE IF NOT EXISTS mailboxes ( id TEXT PRIMARY KEY, domain_id TEXT NOT NULL, address TEXT NOT NULL UNIQUE, status TEXT NOT NULL DEFAULT 'active', -- active | disabled retention_seconds INTEGER, -- NULL = 使用全局默认 86400 is_catch_all INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_mailboxes_domain ON mailboxes(domain_id); CREATE TABLE IF NOT EXISTS emails ( id TEXT PRIMARY KEY, node_id TEXT, mailbox_id TEXT, message_id TEXT, from_address TEXT, to_addresses TEXT, -- JSON array cc_addresses TEXT, -- JSON array subject TEXT, text_body TEXT, html_body TEXT, raw_storage_key TEXT, size INTEGER NOT NULL DEFAULT 0, received_at TEXT NOT NULL, expires_at TEXT NOT NULL, created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_emails_expires ON emails(expires_at); CREATE INDEX IF NOT EXISTS idx_emails_mailbox ON emails(mailbox_id); CREATE INDEX IF NOT EXISTS idx_emails_received ON emails(received_at DESC); CREATE INDEX IF NOT EXISTS idx_emails_message_id ON emails(message_id); CREATE TABLE IF NOT EXISTS email_attachments ( id TEXT PRIMARY KEY, email_id TEXT NOT NULL, filename TEXT, content_type TEXT, size INTEGER NOT NULL DEFAULT 0, storage_key TEXT, content_id TEXT ); CREATE INDEX IF NOT EXISTS idx_attachments_email ON email_attachments(email_id); CREATE TABLE IF NOT EXISTS webhooks ( id TEXT PRIMARY KEY, name TEXT NOT NULL, endpoint TEXT NOT NULL, secret TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS webhook_deliveries ( id TEXT PRIMARY KEY, webhook_id TEXT NOT NULL, email_id TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', -- pending | success | failed | exhausted attempt_count INTEGER NOT NULL DEFAULT 0, next_retry_at TEXT, last_error TEXT, delivered_at TEXT, created_at TEXT NOT NULL ); CREATE INDEX IF NOT EXISTS idx_deliveries_retry ON webhook_deliveries(status, next_retry_at); CREATE INDEX IF NOT EXISTS idx_deliveries_webhook ON webhook_deliveries(webhook_id); CREATE TABLE IF NOT EXISTS oauth_connections ( id TEXT PRIMARY KEY, provider TEXT NOT NULL, account_id TEXT, encrypted_access_token TEXT NOT NULL, refresh_token TEXT, expires_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); -- OAuth CSRF state(node_id 记录本次授权为哪个节点安装) CREATE TABLE IF NOT EXISTS oauth_states ( state TEXT PRIMARY KEY, node_id TEXT, created_at TEXT NOT NULL, expires_at TEXT NOT NULL ); -- Node 请求 nonce 防重放(唯一约束即拒绝重复) CREATE TABLE IF NOT EXISTS nonces ( nonce TEXT PRIMARY KEY, node_id TEXT NOT NULL, expires_at TEXT NOT NULL ); -- Console API / MCP 凭据(wmh_ 开头,总长 32;库中只存 SHA-256) CREATE TABLE IF NOT EXISTS api_credentials ( id TEXT PRIMARY KEY, kind TEXT NOT NULL, -- api | mcp name TEXT, key_hash TEXT NOT NULL UNIQUE, key_last4 TEXT NOT NULL, created_at TEXT NOT NULL, revoked_at TEXT, last_used_at TEXT ); -- 本地 sim 模式:模拟 Cloudflare API 已创建的资源,供 UI 展示安装结果 CREATE TABLE IF NOT EXISTS cf_sim_resources ( id TEXT PRIMARY KEY, kind TEXT NOT NULL, -- email_worker | routing_rule | zone | account ref_id TEXT, payload TEXT, created_at TEXT NOT NULL );