mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 15:06:36 +08:00
refactor(architecture): eliminate internal package and complete cordis single-owner model and repository migration
- Physically purged all legacy internal/ packages, centralized pkg/model/ and pkg/repository/ - Migrated domain models and database repositories into self-contained owner plugins (user, auth, message_gateway, admin, upload, risk_control) - Decoupled cross-plugin interactions via pure core/contracts and typed EventBus - Ensured 100% test coverage pass, zero data races (-race clean), and 0 lint issues in make code-check
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id BIGINT PRIMARY KEY,
|
||||
username VARCHAR(64) UNIQUE,
|
||||
password VARCHAR(255),
|
||||
nickname VARCHAR(255),
|
||||
email VARCHAR(255),
|
||||
avatar_url VARCHAR(255),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
is_admin BOOLEAN DEFAULT FALSE,
|
||||
bio VARCHAR(500),
|
||||
phone VARCHAR(32),
|
||||
gender VARCHAR(16),
|
||||
website VARCHAR(255),
|
||||
location VARCHAR(255),
|
||||
last_login_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users (is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_last_login_at ON users (last_login_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_created_at ON users (created_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS auth_sources (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(80) NOT NULL UNIQUE,
|
||||
type VARCHAR(20) NOT NULL,
|
||||
display_name VARCHAR(100),
|
||||
is_active BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
client_id VARCHAR(255),
|
||||
client_secret VARCHAR(1024),
|
||||
openid_discovery_url VARCHAR(1024),
|
||||
scopes VARCHAR(255),
|
||||
icon_url VARCHAR(1024),
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_auth_sources_is_active ON auth_sources (is_active);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS external_accounts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
auth_source_id BIGINT,
|
||||
user_id BIGINT NOT NULL,
|
||||
external_id VARCHAR(255) NOT NULL,
|
||||
external_username VARCHAR(255),
|
||||
email VARCHAR(255),
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_external_accounts_auth_source_id ON external_accounts (auth_source_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_external_accounts_user_id ON external_accounts (user_id);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_external_accounts_source_external ON external_accounts (auth_source_id, external_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS system_configs (
|
||||
key VARCHAR(64) PRIMARY KEY,
|
||||
value TEXT NOT NULL,
|
||||
type VARCHAR(32) NOT NULL DEFAULT 'system',
|
||||
visibility INTEGER NOT NULL DEFAULT 0,
|
||||
description VARCHAR(255),
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS uploads (
|
||||
id BIGINT PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
file_name VARCHAR(255) NOT NULL,
|
||||
file_path VARCHAR(500) NOT NULL,
|
||||
file_size BIGINT NOT NULL,
|
||||
mime_type VARCHAR(100) NOT NULL,
|
||||
extension VARCHAR(50) NOT NULL,
|
||||
hash VARCHAR(64),
|
||||
storage_driver VARCHAR(50) NOT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL,
|
||||
metadata JSON,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_user_id ON uploads (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_file_path ON uploads (file_path);
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_hash ON uploads (hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_type ON uploads (type);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS access_tokens (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id BIGINT NOT NULL,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
token_hash VARCHAR(64) NOT NULL UNIQUE,
|
||||
masked_token VARCHAR(64) NOT NULL,
|
||||
last_used_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_access_tokens_user_id ON access_tokens (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS task_executions (
|
||||
id BIGINT PRIMARY KEY,
|
||||
task_id VARCHAR(128) NOT NULL UNIQUE,
|
||||
task_type VARCHAR(64) NOT NULL,
|
||||
task_name VARCHAR(128),
|
||||
status VARCHAR(32) NOT NULL,
|
||||
retryable BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
max_retry INTEGER NOT NULL DEFAULT 0,
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
log TEXT,
|
||||
error_message TEXT,
|
||||
result TEXT,
|
||||
started_at DATETIME,
|
||||
finished_at DATETIME,
|
||||
duration BIGINT,
|
||||
payload TEXT,
|
||||
triggered_by VARCHAR(32) NOT NULL DEFAULT 'system',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_task_type ON task_executions (task_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_status ON task_executions (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_started_at ON task_executions (started_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_created_at ON task_executions (created_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS templates (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key VARCHAR(80) NOT NULL UNIQUE,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(20) NOT NULL DEFAULT 'email',
|
||||
subject VARCHAR(255),
|
||||
content TEXT NOT NULL,
|
||||
description VARCHAR(255),
|
||||
is_system BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_is_system ON templates (is_system);
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_created_at ON templates (created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_updated_at ON templates (updated_at);
|
||||
|
||||
INSERT INTO system_configs (key, value, type, visibility, description, created_at, updated_at) VALUES
|
||||
('cap_login_enabled', 'false', 'system', 1, '是否启用登录人机验证(true/false)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_auto_solve', 'true', 'system', 1, '打开页面后是否自动开始计算,关闭则需用户手动点击触发', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_challenge_count', '1', 'system', 0, '客户端需求解的 PoW 难题总数,默认 1,推荐 1~5', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_challenge_size', '32', 'system', 0, '人机验证盐值长度', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_challenge_difficulty', '4', 'system', 0, '人机验证 PoW 难度(目标前缀长度)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_challenge_ttl_seconds', '600', 'system', 0, '人机验证难题有效时间(秒)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('cap_token_ttl_seconds', '1200', 'system', 0, '人机验证兑换凭证有效时间(秒)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('server_address', '', 'system', 0, '服务器地址(用于跨域源控制,不设定则允许任意源)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('smtp_host', '', 'system', 0, 'SMTP 服务器地址(例如 smtp.example.com)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('smtp_port', '587', 'system', 0, 'SMTP 端口(例如 587 或 465)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('smtp_username', '', 'system', 0, 'SMTP 账户(如 sender@example.com)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('smtp_password', '', 'system', 0, 'SMTP 访问凭证(授权码/密码)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('upload_allowed_extensions', 'jpg,png,webp', 'system', 1, '允许上传的图片扩展名(逗号分隔)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('site_name', 'Wavelet', 'system', 1, '系统平台的展示名称', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('password_login_enabled', 'true', 'system', 1, '是否允许使用账号密码登录', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('registration_enabled', 'true', 'system', 1, '控制普通用户是否可以自主注册(true/false)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('password_register_enabled', 'true', 'system', 1, '是否允许通过密码创建本地账号', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('oidc_login_enabled', 'true', 'system', 1, '是否允许使用第三方 OIDC 认证源登录', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('max_api_keys_per_user', '5', 'business', 1, '限制每个普通用户可以创建的 API Key 最大数量', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('email_login_verification_enabled', 'false', 'system', 1, '是否开启邮箱登录验证(true/false)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('email_register_verification_enabled', 'false', 'system', 1, '是否开启邮箱注册验证(true/false)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('menu_display_config', '{}', 'system', 1, '目录显示配置(JSON 字符串,格式为 {url: enabled})', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('search_engine_indexing_enabled', 'false', 'system', 1, '是否允许搜索引擎爬取/检索该站点(true/false)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('update_upstream_repository', 'Rain-kl/Wavelet', 'system', 0, 'GitHub Actions Release 上游仓库(owner/repo 或 GitHub 仓库地址)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('storage_config', '{"driver":"local","local":{"root":"."},"s3":{"region":"us-east-1"},"r2":{"region":"auto"},"minio":{"region":"us-east-1","path_style":true},"oss":{},"webdav":{}}', 'system', 0, '文件存储驱动及连接配置(JSON)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
INSERT INTO users (id, username, password, nickname, avatar_url, is_active, is_admin, last_login_at, created_at, updated_at)
|
||||
VALUES (1, 'admin', '12345678', 'Administrator', '', TRUE, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (username) DO NOTHING;
|
||||
|
||||
INSERT INTO templates (key, name, type, subject, content, description, is_system, created_at, updated_at) VALUES
|
||||
('login_email', '登录验证码邮件', 'email', 'Wavelet 登录验证码', '<h3>Wavelet 登录验证</h3><p>您的登录验证码为:<strong>{{.Code}}</strong>,5分钟内有效,请勿将验证码泄露给他人。</p>', '用户密码登录时发送的验证码邮件模板,支持变量:{{.Code}}', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('register_email', '注册验证码邮件', 'email', 'Wavelet 注册验证码', '<h3>Wavelet 注册验证</h3><p>您的注册验证码为:<strong>{{.Code}}</strong>,5分钟内有效,请勿泄露给他人。</p>', '用户注册时发送的验证码邮件模板,支持变量:{{.Code}}', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS templates;
|
||||
DROP TABLE IF EXISTS task_executions;
|
||||
DROP TABLE IF EXISTS access_tokens;
|
||||
DROP TABLE IF EXISTS uploads;
|
||||
DROP TABLE IF EXISTS system_configs;
|
||||
DROP TABLE IF EXISTS external_accounts;
|
||||
DROP TABLE IF EXISTS auth_sources;
|
||||
DROP TABLE IF EXISTS users;
|
||||
@@ -0,0 +1,20 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS schedules (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
task_type VARCHAR(64) NOT NULL,
|
||||
cron VARCHAR(64) NOT NULL,
|
||||
payload TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_schedules_is_active ON schedules (is_active);
|
||||
|
||||
-- Seed initial cleanup task
|
||||
INSERT INTO schedules (id, name, task_type, cron, payload, is_active, created_at, updated_at)
|
||||
VALUES (1, '清理未使用上传', 'cleanup_unused_uploads', '0 */2 * * *', '{}', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS schedules;
|
||||
@@ -0,0 +1,5 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE access_tokens ADD COLUMN is_admin BOOLEAN NOT NULL DEFAULT 0;
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE access_tokens DROP COLUMN is_admin;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE access_tokens DROP COLUMN last_used_at;
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
ALTER TABLE access_tokens ADD COLUMN last_used_at DATETIME;
|
||||
-- +goose StatementEnd
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
-- 1. Rename existing schedules table
|
||||
ALTER TABLE schedules RENAME TO schedules_old;
|
||||
|
||||
-- 2. Create new schedules table with AUTOINCREMENT
|
||||
CREATE TABLE schedules (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
task_type VARCHAR(64) NOT NULL,
|
||||
cron VARCHAR(64) NOT NULL,
|
||||
payload TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 3. Copy existing data
|
||||
INSERT INTO schedules (id, name, task_type, cron, payload, is_active, created_at, updated_at)
|
||||
SELECT id, name, task_type, cron, payload, is_active, created_at, updated_at FROM schedules_old;
|
||||
|
||||
-- 4. Drop the old table
|
||||
DROP TABLE schedules_old;
|
||||
|
||||
-- 5. Recreate index
|
||||
CREATE INDEX IF NOT EXISTS idx_schedules_is_active ON schedules (is_active);
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
-- Re-creating table with AUTOINCREMENT cannot be undone simply without recreating table again.
|
||||
-- +goose StatementEnd
|
||||
@@ -0,0 +1,123 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE users RENAME TO w_users;
|
||||
ALTER TABLE auth_sources RENAME TO w_auth_sources;
|
||||
ALTER TABLE external_accounts RENAME TO w_external_accounts;
|
||||
ALTER TABLE system_configs RENAME TO w_system_configs;
|
||||
ALTER TABLE uploads RENAME TO w_uploads;
|
||||
ALTER TABLE access_tokens RENAME TO w_access_tokens;
|
||||
ALTER TABLE task_executions RENAME TO w_task_executions;
|
||||
ALTER TABLE templates RENAME TO w_templates;
|
||||
ALTER TABLE schedules RENAME TO w_schedules;
|
||||
|
||||
-- Drop and Recreate SQLite indexes
|
||||
DROP INDEX IF EXISTS idx_users_email;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_users_email ON w_users (email);
|
||||
DROP INDEX IF EXISTS idx_users_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_users_is_active ON w_users (is_active);
|
||||
DROP INDEX IF EXISTS idx_users_last_login_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_users_last_login_at ON w_users (last_login_at);
|
||||
DROP INDEX IF EXISTS idx_users_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_users_created_at ON w_users (created_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_auth_sources_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_auth_sources_is_active ON w_auth_sources (is_active);
|
||||
|
||||
DROP INDEX IF EXISTS idx_external_accounts_auth_source_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_external_accounts_auth_source_id ON w_external_accounts (auth_source_id);
|
||||
DROP INDEX IF EXISTS idx_external_accounts_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_external_accounts_user_id ON w_external_accounts (user_id);
|
||||
DROP INDEX IF EXISTS idx_external_accounts_source_external;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_w_external_accounts_source_external ON w_external_accounts (auth_source_id, external_id);
|
||||
|
||||
DROP INDEX IF EXISTS idx_uploads_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_user_id ON w_uploads (user_id);
|
||||
DROP INDEX IF EXISTS idx_uploads_file_path;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_file_path ON w_uploads (file_path);
|
||||
DROP INDEX IF EXISTS idx_uploads_hash;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_hash ON w_uploads (hash);
|
||||
DROP INDEX IF EXISTS idx_uploads_type;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_type ON w_uploads (type);
|
||||
|
||||
DROP INDEX IF EXISTS idx_access_tokens_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_access_tokens_user_id ON w_access_tokens (user_id);
|
||||
|
||||
DROP INDEX IF EXISTS idx_task_executions_task_type;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_task_executions_task_type ON w_task_executions (task_type);
|
||||
DROP INDEX IF EXISTS idx_task_executions_status;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_task_executions_status ON w_task_executions (status);
|
||||
DROP INDEX IF EXISTS idx_task_executions_started_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_task_executions_started_at ON w_task_executions (started_at);
|
||||
DROP INDEX IF EXISTS idx_task_executions_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_task_executions_created_at ON w_task_executions (created_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_templates_is_system;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_templates_is_system ON w_templates (is_system);
|
||||
DROP INDEX IF EXISTS idx_templates_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_templates_created_at ON w_templates (created_at);
|
||||
DROP INDEX IF EXISTS idx_templates_updated_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_templates_updated_at ON w_templates (updated_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_schedules_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_w_schedules_is_active ON w_schedules (is_active);
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE w_schedules RENAME TO schedules;
|
||||
ALTER TABLE w_templates RENAME TO templates;
|
||||
ALTER TABLE w_task_executions RENAME TO task_executions;
|
||||
ALTER TABLE w_access_tokens RENAME TO access_tokens;
|
||||
ALTER TABLE w_uploads RENAME TO uploads;
|
||||
ALTER TABLE w_system_configs RENAME TO system_configs;
|
||||
ALTER TABLE w_external_accounts RENAME TO external_accounts;
|
||||
ALTER TABLE w_auth_sources RENAME TO auth_sources;
|
||||
ALTER TABLE w_users RENAME TO users;
|
||||
|
||||
-- Revert indexes
|
||||
DROP INDEX IF EXISTS idx_w_users_email;
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users (email);
|
||||
DROP INDEX IF EXISTS idx_w_users_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_users_is_active ON users (is_active);
|
||||
DROP INDEX IF EXISTS idx_w_users_last_login_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_users_last_login_at ON users (last_login_at);
|
||||
DROP INDEX IF EXISTS idx_w_users_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_users_created_at ON users (created_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_auth_sources_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_auth_sources_is_active ON auth_sources (is_active);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_external_accounts_auth_source_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_external_accounts_auth_source_id ON external_accounts (auth_source_id);
|
||||
DROP INDEX IF EXISTS idx_w_external_accounts_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_external_accounts_user_id ON external_accounts (user_id);
|
||||
DROP INDEX IF EXISTS idx_w_external_accounts_source_external;
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_external_accounts_source_external ON external_accounts (auth_source_id, external_id);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_uploads_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_user_id ON uploads (user_id);
|
||||
DROP INDEX IF EXISTS idx_w_uploads_file_path;
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_file_path ON uploads (file_path);
|
||||
DROP INDEX IF EXISTS idx_w_uploads_hash;
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_hash ON uploads (hash);
|
||||
DROP INDEX IF EXISTS idx_w_uploads_type;
|
||||
CREATE INDEX IF NOT EXISTS idx_uploads_type ON uploads (type);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_access_tokens_user_id;
|
||||
CREATE INDEX IF NOT EXISTS idx_access_tokens_user_id ON access_tokens (user_id);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_task_executions_task_type;
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_task_type ON task_executions (task_type);
|
||||
DROP INDEX IF EXISTS idx_w_task_executions_status;
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_status ON task_executions (status);
|
||||
DROP INDEX IF EXISTS idx_w_task_executions_started_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_started_at ON task_executions (started_at);
|
||||
DROP INDEX IF EXISTS idx_w_task_executions_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_task_executions_created_at ON task_executions (created_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_templates_is_system;
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_is_system ON templates (is_system);
|
||||
DROP INDEX IF EXISTS idx_w_templates_created_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_created_at ON templates (created_at);
|
||||
DROP INDEX IF EXISTS idx_w_templates_updated_at;
|
||||
CREATE INDEX IF NOT EXISTS idx_templates_updated_at ON templates (updated_at);
|
||||
|
||||
DROP INDEX IF EXISTS idx_w_schedules_is_active;
|
||||
CREATE INDEX IF NOT EXISTS idx_schedules_is_active ON schedules (is_active);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES ('file_access_whitelist', '["avatar"]', 'system', 1, '免登录访问的文件业务类型白名单 (JSON 数组格式)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key = 'file_access_whitelist';
|
||||
@@ -0,0 +1,10 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES
|
||||
('disk_cache_max_size_mb', '100', 'system', 0, '磁盘缓存最大空间大小 (MB)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('disk_cache_ttl_minutes', '60', 'system', 0, '磁盘缓存默认有效期 (分钟)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('disk_cache_lru_enabled', 'true', 'system', 0, '是否启用 LRU 淘汰机制', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key IN ('disk_cache_max_size_mb', 'disk_cache_ttl_minutes', 'disk_cache_lru_enabled');
|
||||
@@ -0,0 +1,8 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES
|
||||
('login_session_ttl_hours', '0', 'system', 0, '登录会话过期时间 (小时,0表示浏览器关闭后自动退出,-1表示永不过期)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key = 'login_session_ttl_hours';
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES ('update_upstream_repository', 'Rain-kl/Wavelet', 'system', 0, 'GitHub Actions Release 上游仓库(owner/repo 或 GitHub 仓库地址)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key = 'update_upstream_repository';
|
||||
@@ -0,0 +1,6 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE w_uploads ADD COLUMN access_mode INTEGER NOT NULL DEFAULT 0;
|
||||
UPDATE w_uploads SET access_mode = 1 WHERE type = 'avatar';
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE w_uploads DROP COLUMN access_mode;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- +goose Up
|
||||
-- SQLite stores VARCHAR and TEXT with the same TEXT affinity.
|
||||
SELECT 1;
|
||||
|
||||
-- +goose Down
|
||||
SELECT 1;
|
||||
@@ -0,0 +1,15 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES (
|
||||
'storage_config',
|
||||
'{"driver":"local","local":{"root":"."},"s3":{"region":"us-east-1"},"r2":{"region":"auto"},"minio":{"region":"us-east-1","path_style":true},"oss":{},"webdav":{}}',
|
||||
'system',
|
||||
0,
|
||||
'文件存储驱动及连接配置(JSON)',
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP
|
||||
)
|
||||
ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key = 'storage_config';
|
||||
@@ -0,0 +1,34 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE w_push_events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
event_key TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
channels TEXT NOT NULL,
|
||||
targets TEXT NOT NULL,
|
||||
template TEXT NOT NULL,
|
||||
enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_w_push_events_enabled ON w_push_events(enabled);
|
||||
|
||||
CREATE TABLE w_push_histories (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
event_key TEXT NOT NULL,
|
||||
channel TEXT NOT NULL,
|
||||
target TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
level TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
error_msg TEXT,
|
||||
created_at DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_w_push_histories_event ON w_push_histories(event_key);
|
||||
CREATE INDEX idx_w_push_histories_created ON w_push_histories(created_at);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS w_push_histories;
|
||||
DROP TABLE IF EXISTS w_push_events;
|
||||
@@ -0,0 +1,7 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_users (id, username, password, nickname, avatar_url, is_active, is_admin, last_login_at, created_at, updated_at)
|
||||
VALUES (999, 'system', '*', '系统', '', TRUE, FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (username) DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_users WHERE username = 'system';
|
||||
@@ -0,0 +1,19 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE w_push_channels (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
type TEXT NOT NULL DEFAULT 'custom',
|
||||
token TEXT,
|
||||
url TEXT NOT NULL,
|
||||
other TEXT NOT NULL,
|
||||
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at DATETIME NOT NULL,
|
||||
updated_at DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_w_push_channels_name ON w_push_channels(name);
|
||||
CREATE INDEX idx_w_push_channels_enabled ON w_push_channels(enabled);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS w_push_channels;
|
||||
@@ -0,0 +1,11 @@
|
||||
-- +goose Up
|
||||
UPDATE w_schedules
|
||||
SET name = '系统定期垃圾清理',
|
||||
task_type = 'system_cleanup'
|
||||
WHERE id = 1;
|
||||
|
||||
-- +goose Down
|
||||
UPDATE w_schedules
|
||||
SET name = '清理未使用上传',
|
||||
task_type = 'cleanup_unused_uploads'
|
||||
WHERE id = 1;
|
||||
@@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE w_push_events ADD COLUMN task_type VARCHAR(100) NOT NULL DEFAULT '';
|
||||
CREATE INDEX idx_w_push_events_task_type ON w_push_events(task_type);
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX IF EXISTS idx_w_push_events_task_type;
|
||||
-- SQLite does not support DROP COLUMN in older versions easily, but standard ALTER TABLE DROP COLUMN works in SQLite 3.35.0+.
|
||||
-- We can write standard DROP COLUMN.
|
||||
ALTER TABLE w_push_events DROP COLUMN task_type;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- +goose Up
|
||||
DELETE FROM w_system_configs WHERE key = 'push_config';
|
||||
DELETE FROM w_push_events WHERE event_key = 'admin_login';
|
||||
DELETE FROM w_system_configs WHERE key = 'push_global_token';
|
||||
|
||||
-- +goose Down
|
||||
@@ -0,0 +1,9 @@
|
||||
-- +goose Up
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_status_created_at ON w_uploads (status, created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_storage_driver_status ON w_uploads (storage_driver, status);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_hash_file_size_status ON w_uploads (hash, file_size, status);
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX IF EXISTS idx_w_uploads_hash_file_size_status;
|
||||
DROP INDEX IF EXISTS idx_w_uploads_storage_driver_status;
|
||||
DROP INDEX IF EXISTS idx_w_uploads_status_created_at;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS w_upload_stats (
|
||||
dimension VARCHAR(32) NOT NULL,
|
||||
stat_key VARCHAR(64) NOT NULL DEFAULT '',
|
||||
file_count BIGINT NOT NULL DEFAULT 0,
|
||||
file_size BIGINT NOT NULL DEFAULT 0,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (dimension, stat_key)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS w_upload_stats;
|
||||
@@ -0,0 +1,67 @@
|
||||
-- +goose Up
|
||||
INSERT INTO w_upload_stats (dimension, stat_key, file_count, file_size)
|
||||
SELECT 'total', '', COUNT(*), COALESCE(SUM(file_size), 0)
|
||||
FROM w_uploads
|
||||
WHERE status != 'deleted'
|
||||
ON CONFLICT (dimension, stat_key) DO UPDATE SET
|
||||
file_count = excluded.file_count,
|
||||
file_size = excluded.file_size,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO w_upload_stats (dimension, stat_key, file_count, file_size)
|
||||
SELECT
|
||||
'type',
|
||||
COALESCE(NULLIF(type, ''), 'generic'),
|
||||
COUNT(*),
|
||||
COALESCE(SUM(file_size), 0)
|
||||
FROM w_uploads
|
||||
WHERE status != 'deleted'
|
||||
GROUP BY COALESCE(NULLIF(type, ''), 'generic')
|
||||
ON CONFLICT (dimension, stat_key) DO UPDATE SET
|
||||
file_count = excluded.file_count,
|
||||
file_size = excluded.file_size,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO w_upload_stats (dimension, stat_key, file_count, file_size)
|
||||
SELECT
|
||||
'category',
|
||||
CASE
|
||||
WHEN LOWER(mime_type) LIKE 'image/%'
|
||||
OR LOWER(extension) IN ('jpg', 'jpeg', 'png', 'webp', 'gif') THEN '图片'
|
||||
WHEN LOWER(mime_type) LIKE 'video/%' THEN '视频'
|
||||
WHEN LOWER(mime_type) LIKE 'audio/%' THEN '音频'
|
||||
WHEN LOWER(extension) IN ('zip', 'rar', '7z', 'tar', 'gz', 'tgz', 'bz2', 'xz')
|
||||
OR LOWER(mime_type) LIKE '%zip%'
|
||||
OR LOWER(mime_type) LIKE '%tar%'
|
||||
OR LOWER(mime_type) LIKE '%gzip%' THEN '压缩包'
|
||||
WHEN LOWER(extension) IN ('pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'md', 'csv', 'json', 'yaml', 'yml', 'xml')
|
||||
OR LOWER(mime_type) LIKE 'text/%'
|
||||
OR LOWER(mime_type) = 'application/pdf' THEN '文档'
|
||||
ELSE '其他'
|
||||
END,
|
||||
COUNT(*),
|
||||
COALESCE(SUM(file_size), 0)
|
||||
FROM w_uploads
|
||||
WHERE status != 'deleted'
|
||||
GROUP BY 2
|
||||
ON CONFLICT (dimension, stat_key) DO UPDATE SET
|
||||
file_count = excluded.file_count,
|
||||
file_size = excluded.file_size,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
INSERT INTO w_upload_stats (dimension, stat_key, file_count, file_size)
|
||||
SELECT
|
||||
'trend',
|
||||
STRFTIME('%Y-%m-%d', created_at),
|
||||
COUNT(*),
|
||||
COALESCE(SUM(file_size), 0)
|
||||
FROM w_uploads
|
||||
WHERE status != 'deleted'
|
||||
GROUP BY STRFTIME('%Y-%m-%d', created_at)
|
||||
ON CONFLICT (dimension, stat_key) DO UPDATE SET
|
||||
file_count = excluded.file_count,
|
||||
file_size = excluded.file_size,
|
||||
updated_at = CURRENT_TIMESTAMP;
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_upload_stats;
|
||||
@@ -0,0 +1,8 @@
|
||||
-- +goose Up
|
||||
DROP INDEX IF EXISTS idx_w_uploads_storage_driver_status;
|
||||
-- SQLite lacks DROP COLUMN IF EXISTS; goose runs this only after initial schema created the column.
|
||||
ALTER TABLE w_uploads DROP COLUMN storage_driver;
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE w_uploads ADD COLUMN storage_driver VARCHAR(50) NOT NULL DEFAULT 'local';
|
||||
CREATE INDEX IF NOT EXISTS idx_w_uploads_storage_driver_status ON w_uploads (storage_driver, status);
|
||||
@@ -0,0 +1,22 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS w_user_access_logs (
|
||||
id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL DEFAULT 0,
|
||||
path TEXT NOT NULL DEFAULT '',
|
||||
method TEXT NOT NULL DEFAULT '',
|
||||
ip TEXT NOT NULL DEFAULT '',
|
||||
user_agent TEXT NOT NULL DEFAULT '',
|
||||
headers TEXT NOT NULL DEFAULT '',
|
||||
status INTEGER NOT NULL DEFAULT 0,
|
||||
latency INTEGER NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id, created_at)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_w_user_access_logs_user_id ON w_user_access_logs (user_id, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_user_access_logs_created_at ON w_user_access_logs (created_at DESC);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS w_user_access_logs;
|
||||
DROP INDEX IF EXISTS idx_w_user_access_logs_user_id;
|
||||
DROP INDEX IF EXISTS idx_w_user_access_logs_created_at;
|
||||
@@ -0,0 +1,17 @@
|
||||
-- +goose Up
|
||||
INSERT OR IGNORE INTO w_system_configs (key, value, type, visibility, description, created_at, updated_at)
|
||||
VALUES
|
||||
('log_database', '', 'system', 0, '当前日志主库(postgres/sqlite/clickhouse),由切换任务写入', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('log_db_migration', '', 'system', 0, '日志库迁移冻结标记(空或 migrating)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('log_retention_days_postgres', '30', 'business', 0, 'PostgreSQL 用户访问日志保留天数', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('log_retention_days_sqlite', '30', 'business', 0, 'SQLite 用户访问日志保留天数', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
|
||||
('log_retention_days_clickhouse', '30', 'business', 0, 'ClickHouse 用户访问日志保留天数', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
|
||||
|
||||
-- +goose Down
|
||||
DELETE FROM w_system_configs WHERE key IN (
|
||||
'log_database',
|
||||
'log_db_migration',
|
||||
'log_retention_days_postgres',
|
||||
'log_retention_days_sqlite',
|
||||
'log_retention_days_clickhouse'
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS w_message_channels (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
owner_scope TEXT NOT NULL DEFAULT 'system',
|
||||
owner_id INTEGER NULL,
|
||||
enabled INTEGER NOT NULL DEFAULT 1,
|
||||
credentials TEXT NOT NULL DEFAULT '',
|
||||
extra TEXT NOT NULL DEFAULT '',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_message_channels_type ON w_message_channels (type);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS w_message_bindings (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL,
|
||||
channel_id INTEGER NOT NULL,
|
||||
platform_user_id TEXT NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_w_message_bindings_channel_platform
|
||||
ON w_message_bindings (channel_id, platform_user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_message_bindings_user ON w_message_bindings (user_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS w_message_pairing_codes (
|
||||
code TEXT PRIMARY KEY,
|
||||
channel_id INTEGER NOT NULL,
|
||||
platform_user_id TEXT NOT NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_w_message_pairing_lookup
|
||||
ON w_message_pairing_codes (channel_id, platform_user_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS w_message_pairing_codes;
|
||||
DROP TABLE IF EXISTS w_message_bindings;
|
||||
DROP TABLE IF EXISTS w_message_channels;
|
||||
Reference in New Issue
Block a user