fix: 修复重构本地闭环契约
This commit is contained in:
parent
cf89157fd6
commit
fd22836c23
@ -12,12 +12,12 @@
|
||||
|
||||
| Domain | Tables | Owner Batch | Notes |
|
||||
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Admin Identity | `admin_user`, `admin_role`, `admin_permission`, `admin_menu`, `admin_department`, `admin_user_role`, `admin_role_permission`, `admin_role_menu` | Batch 2 | Login, menu, role, permission, department. |
|
||||
| Platform Config | `platform_dict_group`, `platform_dict_item`, `platform_component_template`, `platform_setting` | Batch 2 | Dict and component template split from legacy Admin misc. |
|
||||
| Blog Content | `blog_post`, `blog_taxonomy`, `blog_term`, `blog_post_term`, `blog_theme_profile`, `blog_import_job` | Batch 3 | Categories and tags use relation table. |
|
||||
| Admin Identity | `admin_user`, `admin_role`, `admin_permission`, `admin_menu`, `admin_dept`, `admin_department`, `admin_user_role`, `admin_role_permission`, `admin_role_menu` | Batch 2 | Runtime login/menu/role/dept tables plus future permission and department boundary tables. |
|
||||
| Platform Config | `admin_dict`, `admin_component`, `platform_dict_group`, `platform_dict_item`, `platform_component_template`, `platform_setting` | Batch 2 | Runtime Admin dict/component compatibility plus new platform dict/component template split. |
|
||||
| Blog Content | `blog_post`, `blog_article`, `blog_taxonomy`, `blog_term`, `blog_post_term`, `blog_theme_profile`, `blog_theme_config`, `blog_import_job` | Batch 3 | `blog_article`/`blog_theme_config` keep current runtime compatibility; `blog_term` carries both runtime category/tag fields and nullable taxonomy planning fields. |
|
||||
| WordPress Mirror | `wordpress_site`, `wordpress_auth_session`, `wordpress_remote_post`, `wordpress_remote_term`, `wordpress_sync_job`, `wordpress_sync_mapping` | Batch 3 | Remote state separate from local Blog content. |
|
||||
| Asset | `asset_bucket`, `asset_object`, `asset_reference`, `asset_access_grant` | Batch 3 | MinIO object ownership and access grant. |
|
||||
| System Event | `system_notice`, `system_event`, `system_event_dedupe`, `system_event_delivery` | Batch 2 | MySQL stores actionable events; Loki remains log query source. |
|
||||
| System Event | `admin_notice`, `system_notice`, `system_event`, `system_event_dedupe`, `system_event_delivery` | Batch 2 | Admin notices and MySQL actionable events; Loki remains log query source. |
|
||||
| Runtime Evidence | `runtime_evidence_index` | Batch 1 | Safe index only, no large logs or secrets. |
|
||||
| QQBot Core | `qqbot_account`, `qqbot_account_ability`, `qqbot_connection_session`, `qqbot_capability_binding`, `qqbot_permission_policy`, `qqbot_allowlist`, `qqbot_blocklist`, `qqbot_command`, `qqbot_command_alias`, `qqbot_command_log`, `qqbot_config`, `qqbot_rule`, `qqbot_conversation`, `qqbot_message`, `qqbot_send_task`, `qqbot_send_log`, `qqbot_dedupe_event`, `qqbot_dedupe`, `qqbot_account_napcat`, `qqbot_napcat_container` | Batch 4 | Account, connection, permission, command, message, send queue, and transitional registered-entity compatibility tables until Batches 5-7 replace plugin/NapCat internals. |
|
||||
| NapCat Runtime | `napcat_container`, `napcat_device_identity`, `napcat_account_binding`, `napcat_login_session`, `napcat_login_challenge`, `napcat_runtime_cleanup` | Batch 7 | Device identity and login challenge state. |
|
||||
|
||||
@ -15,16 +15,27 @@ $schema = Join-Path $root "sql\refactor-v3\00-full-schema.sql"
|
||||
$seed = Join-Path $root "sql\refactor-v3\01-seed-core.sql"
|
||||
$verify = Join-Path $root "sql\refactor-v3\99-verify.sql"
|
||||
|
||||
function Invoke-Mysql {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string[]]$Arguments
|
||||
)
|
||||
|
||||
mysql --default-character-set=utf8mb4 @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "mysql failed with exit code $LASTEXITCODE"
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-MysqlSource {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path
|
||||
)
|
||||
|
||||
$sourcePath = (Resolve-Path -LiteralPath $Path).Path.Replace("\", "/")
|
||||
mysql -h $HostName -P $Port -u $User $Database --execute="source $sourcePath"
|
||||
Invoke-Mysql -Arguments @("-h", $HostName, "-P", "$Port", "-u", $User, $Database, "--execute=source $sourcePath")
|
||||
}
|
||||
|
||||
mysql -h $HostName -P $Port -u $User -e "DROP DATABASE IF EXISTS ``$Database``; CREATE DATABASE ``$Database`` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
|
||||
Invoke-Mysql -Arguments @("-h", $HostName, "-P", "$Port", "-u", $User, "-e", "DROP DATABASE IF EXISTS ``$Database``; CREATE DATABASE ``$Database`` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;")
|
||||
Invoke-MysqlSource -Path $schema
|
||||
Invoke-MysqlSource -Path $seed
|
||||
Invoke-MysqlSource -Path $verify
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
param(
|
||||
[string]$BaseUrl = "http://127.0.0.1:5320"
|
||||
[string]$BaseUrl = "http://127.0.0.1:48085"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
@ -1,22 +1,147 @@
|
||||
CREATE TABLE IF NOT EXISTS admin_user (
|
||||
CREATE TABLE IF NOT EXISTS admin_menu (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
username VARCHAR(64) NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
nickname VARCHAR(64) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_admin_user_username (username)
|
||||
pid BIGINT NOT NULL DEFAULT 0,
|
||||
name VARCHAR(120) NOT NULL,
|
||||
path VARCHAR(255) NULL,
|
||||
component VARCHAR(255) NULL,
|
||||
redirect VARCHAR(255) NULL,
|
||||
auth_code VARCHAR(120) NULL,
|
||||
type VARCHAR(32) NOT NULL DEFAULT 'menu',
|
||||
meta LONGTEXT NULL,
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
sort INT NOT NULL DEFAULT 0,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
UNIQUE KEY uk_admin_menu_name (name),
|
||||
KEY idx_admin_menu_pid (pid),
|
||||
KEY idx_admin_menu_path (path),
|
||||
KEY idx_admin_menu_auth_code (auth_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_role (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
role_key VARCHAR(64) NOT NULL,
|
||||
role_name VARCHAR(64) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_admin_role_key (role_key)
|
||||
role_code VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
UNIQUE KEY uk_admin_role_code (role_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_user (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
real_name VARCHAR(255) NOT NULL,
|
||||
avatar VARCHAR(1024) NOT NULL DEFAULT '',
|
||||
dept_id BIGINT NULL,
|
||||
home_path VARCHAR(255) NOT NULL DEFAULT '',
|
||||
timezone VARCHAR(255) NOT NULL DEFAULT 'Asia/Shanghai',
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
UNIQUE KEY uk_admin_user_username (username),
|
||||
KEY idx_admin_user_dept_id (dept_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_dept (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
pid BIGINT NOT NULL DEFAULT 0,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
remark VARCHAR(255) NOT NULL DEFAULT '',
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
KEY idx_admin_dept_pid (pid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_dict (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
dict_code VARCHAR(255) NOT NULL,
|
||||
label VARCHAR(255) NOT NULL,
|
||||
value VARCHAR(255) NOT NULL,
|
||||
children_code VARCHAR(255) NULL,
|
||||
sort INT NOT NULL DEFAULT 0,
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
UNIQUE KEY uk_admin_dict_code_value (dict_code, value),
|
||||
KEY idx_admin_dict_code (dict_code),
|
||||
KEY idx_admin_dict_children_code (children_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_component (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||||
type INT NOT NULL,
|
||||
component_type INT NOT NULL,
|
||||
image MEDIUMTEXT NOT NULL,
|
||||
template MEDIUMTEXT NOT NULL,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
KEY idx_admin_component_type (type),
|
||||
KEY idx_admin_component_component_type (component_type),
|
||||
KEY idx_admin_component_deleted (is_deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_notice (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
content LONGTEXT NOT NULL,
|
||||
summary TEXT NULL,
|
||||
level INT NOT NULL DEFAULT 1,
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'info',
|
||||
source VARCHAR(64) NOT NULL DEFAULT 'system',
|
||||
event_type VARCHAR(120) NOT NULL DEFAULT 'system.event',
|
||||
dedupe_key VARCHAR(255) NULL,
|
||||
occurrence_count INT NOT NULL DEFAULT 1,
|
||||
notify_role_code VARCHAR(64) NOT NULL DEFAULT 'super',
|
||||
metadata JSON NULL,
|
||||
is_top TINYINT NOT NULL DEFAULT 0,
|
||||
notify_users TEXT NULL,
|
||||
created_by BIGINT NULL,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
active_dedupe_key VARCHAR(255) GENERATED ALWAYS AS (CASE WHEN is_deleted = 0 AND dedupe_key IS NOT NULL THEN dedupe_key ELSE NULL END) VIRTUAL,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
first_seen_at DATETIME NULL,
|
||||
last_seen_at DATETIME NULL,
|
||||
UNIQUE KEY uk_admin_notice_active_dedupe_key (active_dedupe_key),
|
||||
KEY idx_admin_notice_status (status),
|
||||
KEY idx_admin_notice_severity (severity),
|
||||
KEY idx_admin_notice_source_event (source, event_type),
|
||||
KEY idx_admin_notice_dedupe_key (dedupe_key),
|
||||
KEY idx_admin_notice_notify_role (notify_role_code),
|
||||
KEY idx_admin_notice_is_top (is_top),
|
||||
KEY idx_admin_notice_is_deleted (is_deleted),
|
||||
KEY idx_admin_notice_create_time (create_time),
|
||||
KEY idx_admin_notice_last_seen (last_seen_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_user_role (
|
||||
user_id BIGINT NOT NULL,
|
||||
role_id BIGINT NOT NULL,
|
||||
PRIMARY KEY (user_id, role_id),
|
||||
KEY idx_admin_user_role_role_id (role_id),
|
||||
CONSTRAINT fk_admin_user_role_user FOREIGN KEY (user_id) REFERENCES admin_user (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_admin_user_role_role FOREIGN KEY (role_id) REFERENCES admin_role (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_role_menu (
|
||||
role_id BIGINT NOT NULL,
|
||||
menu_id BIGINT NOT NULL,
|
||||
PRIMARY KEY (role_id, menu_id),
|
||||
KEY idx_admin_role_menu_menu_id (menu_id),
|
||||
CONSTRAINT fk_admin_role_menu_role FOREIGN KEY (role_id) REFERENCES admin_role (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_admin_role_menu_menu FOREIGN KEY (menu_id) REFERENCES admin_menu (id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_permission (
|
||||
@ -29,21 +154,6 @@ CREATE TABLE IF NOT EXISTS admin_permission (
|
||||
UNIQUE KEY uk_admin_permission_key (permission_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_menu (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
parent_id BIGINT NULL,
|
||||
menu_key VARCHAR(128) NOT NULL,
|
||||
title VARCHAR(128) NOT NULL,
|
||||
path VARCHAR(255) NOT NULL,
|
||||
component VARCHAR(255) NULL,
|
||||
sort_no INT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_admin_menu_key (menu_key),
|
||||
KEY idx_admin_menu_parent (parent_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_department (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
parent_id BIGINT NULL,
|
||||
@ -55,15 +165,6 @@ CREATE TABLE IF NOT EXISTS admin_department (
|
||||
KEY idx_admin_department_parent (parent_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_user_role (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
role_id BIGINT NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_admin_user_role (user_id, role_id),
|
||||
KEY idx_admin_user_role_role (role_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_role_permission (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
role_id BIGINT NOT NULL,
|
||||
@ -73,15 +174,6 @@ CREATE TABLE IF NOT EXISTS admin_role_permission (
|
||||
KEY idx_admin_role_permission_permission (permission_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS admin_role_menu (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
role_id BIGINT NOT NULL,
|
||||
menu_id BIGINT NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_admin_role_menu (role_id, menu_id),
|
||||
KEY idx_admin_role_menu_menu (menu_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS platform_dict_group (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
group_key VARCHAR(128) NOT NULL,
|
||||
@ -142,6 +234,30 @@ CREATE TABLE IF NOT EXISTS blog_post (
|
||||
KEY idx_blog_post_status (status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_article (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) NOT NULL DEFAULT '',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'draft',
|
||||
excerpt TEXT NULL,
|
||||
content_markdown MEDIUMTEXT NULL,
|
||||
content_html MEDIUMTEXT NULL,
|
||||
cover TEXT NULL,
|
||||
author_name VARCHAR(255) NOT NULL DEFAULT 'KwiTsukasa',
|
||||
category_items TEXT NULL,
|
||||
tag_items TEXT NULL,
|
||||
views INT NOT NULL DEFAULT 0,
|
||||
comments INT NOT NULL DEFAULT 0,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
publish_time DATETIME NULL,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
KEY idx_blog_article_slug (slug),
|
||||
KEY idx_blog_article_status (status),
|
||||
KEY idx_blog_article_publish_time (publish_time),
|
||||
KEY idx_blog_article_is_deleted (is_deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_taxonomy (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
taxonomy_key VARCHAR(64) NOT NULL,
|
||||
@ -153,13 +269,20 @@ CREATE TABLE IF NOT EXISTS blog_taxonomy (
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_term (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
taxonomy_id BIGINT NOT NULL,
|
||||
taxonomy_id BIGINT NULL,
|
||||
kind VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
slug VARCHAR(255) NOT NULL,
|
||||
term_name VARCHAR(128) NOT NULL,
|
||||
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uk_blog_term_slug (taxonomy_id, slug),
|
||||
KEY idx_blog_term_taxonomy (taxonomy_id)
|
||||
term_name VARCHAR(128) NULL,
|
||||
description TEXT NULL,
|
||||
parent_id VARCHAR(64) NULL,
|
||||
is_deleted TINYINT NOT NULL DEFAULT 0,
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||
KEY idx_blog_term_taxonomy (taxonomy_id),
|
||||
KEY idx_blog_term_kind_slug (kind, slug),
|
||||
KEY idx_blog_term_parent_id (parent_id),
|
||||
KEY idx_blog_term_is_deleted (is_deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_post_term (
|
||||
@ -182,6 +305,14 @@ CREATE TABLE IF NOT EXISTS blog_theme_profile (
|
||||
UNIQUE KEY uk_blog_theme_profile_key (profile_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_theme_config (
|
||||
id VARCHAR(64) NOT NULL PRIMARY KEY,
|
||||
config LONGTEXT NOT NULL,
|
||||
source VARCHAR(255) NOT NULL DEFAULT 'local',
|
||||
create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
update_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS blog_import_job (
|
||||
id BIGINT NOT NULL PRIMARY KEY,
|
||||
source_key VARCHAR(64) NOT NULL,
|
||||
|
||||
@ -1,67 +1,214 @@
|
||||
INSERT INTO admin_role (
|
||||
id,
|
||||
role_code,
|
||||
name,
|
||||
remark,
|
||||
status
|
||||
) VALUES (
|
||||
2041700000000010001,
|
||||
'super',
|
||||
'超级管理员',
|
||||
'拥有所有后台权限',
|
||||
1
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
remark = VALUES(remark),
|
||||
status = VALUES(status),
|
||||
is_deleted = 0;
|
||||
|
||||
INSERT INTO admin_dept (
|
||||
id,
|
||||
pid,
|
||||
name,
|
||||
status,
|
||||
remark
|
||||
) VALUES (
|
||||
2041700000000200001,
|
||||
0,
|
||||
'KT 总部',
|
||||
1,
|
||||
'根部门'
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
pid = VALUES(pid),
|
||||
name = VALUES(name),
|
||||
status = VALUES(status),
|
||||
remark = VALUES(remark),
|
||||
is_deleted = 0;
|
||||
|
||||
INSERT INTO admin_user (
|
||||
id,
|
||||
username,
|
||||
password_hash,
|
||||
nickname,
|
||||
password,
|
||||
real_name,
|
||||
avatar,
|
||||
dept_id,
|
||||
home_path,
|
||||
timezone,
|
||||
status
|
||||
) VALUES (
|
||||
1000000000000000001,
|
||||
2041700000000000002,
|
||||
'admin',
|
||||
'!disabled-refactor-v3-password-hash!',
|
||||
'Administrator',
|
||||
'password_unset'
|
||||
'123456',
|
||||
'Admin',
|
||||
'',
|
||||
2041700000000200001,
|
||||
'/workspace',
|
||||
'Asia/Shanghai',
|
||||
1
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
nickname = VALUES(nickname),
|
||||
status = VALUES(status);
|
||||
|
||||
INSERT INTO admin_role (
|
||||
id,
|
||||
role_key,
|
||||
role_name,
|
||||
status
|
||||
) VALUES (
|
||||
1000000000000000002,
|
||||
'super_admin',
|
||||
'Super Administrator',
|
||||
'enabled'
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
role_name = VALUES(role_name),
|
||||
status = VALUES(status);
|
||||
|
||||
INSERT INTO admin_user_role (
|
||||
id,
|
||||
user_id,
|
||||
role_id
|
||||
) VALUES (
|
||||
1000000000000000003,
|
||||
1000000000000000001,
|
||||
1000000000000000002
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
role_id = VALUES(role_id);
|
||||
password = VALUES(password),
|
||||
real_name = VALUES(real_name),
|
||||
avatar = VALUES(avatar),
|
||||
dept_id = VALUES(dept_id),
|
||||
home_path = VALUES(home_path),
|
||||
timezone = VALUES(timezone),
|
||||
status = VALUES(status),
|
||||
is_deleted = 0;
|
||||
|
||||
INSERT INTO admin_menu (
|
||||
id,
|
||||
parent_id,
|
||||
menu_key,
|
||||
title,
|
||||
pid,
|
||||
name,
|
||||
path,
|
||||
component,
|
||||
sort_no,
|
||||
status
|
||||
) VALUES (
|
||||
1000000000000000004,
|
||||
NULL,
|
||||
'dashboard',
|
||||
'Dashboard',
|
||||
'/dashboard',
|
||||
'dashboard/workspace/index',
|
||||
10,
|
||||
'enabled'
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
title = VALUES(title),
|
||||
redirect,
|
||||
auth_code,
|
||||
type,
|
||||
meta,
|
||||
status,
|
||||
sort
|
||||
) VALUES
|
||||
(
|
||||
2041700000000100001,
|
||||
0,
|
||||
'Dashboard',
|
||||
'/dashboard',
|
||||
NULL,
|
||||
'/workspace',
|
||||
NULL,
|
||||
'catalog',
|
||||
'{"order":-1,"title":"page.dashboard.title"}',
|
||||
1,
|
||||
0
|
||||
),
|
||||
(
|
||||
2041700000000100102,
|
||||
2041700000000100001,
|
||||
'Workspace',
|
||||
'/workspace',
|
||||
'/dashboard/workspace/index',
|
||||
NULL,
|
||||
NULL,
|
||||
'menu',
|
||||
'{"icon":"carbon:workspace","title":"page.dashboard.workspace"}',
|
||||
1,
|
||||
0
|
||||
),
|
||||
(
|
||||
2041700000000100400,
|
||||
0,
|
||||
'QqBot',
|
||||
'/qqbot',
|
||||
NULL,
|
||||
'/qqbot/dashboard',
|
||||
NULL,
|
||||
'catalog',
|
||||
'{"icon":"lucide:bot","order":110,"title":"QQBot 管理"}',
|
||||
1,
|
||||
110
|
||||
),
|
||||
(
|
||||
2041700000000100402,
|
||||
2041700000000100400,
|
||||
'QqBotAccount',
|
||||
'/qqbot/account',
|
||||
'/qqbot/account/list',
|
||||
NULL,
|
||||
'QqBot:Account:List',
|
||||
'menu',
|
||||
'{"icon":"lucide:radio-receiver","title":"账号连接"}',
|
||||
1,
|
||||
1
|
||||
),
|
||||
(
|
||||
2041700000000100408,
|
||||
2041700000000100400,
|
||||
'QqBotCommand',
|
||||
'/qqbot/command',
|
||||
'/qqbot/command/list',
|
||||
NULL,
|
||||
'QqBot:Command:List',
|
||||
'menu',
|
||||
'{"icon":"lucide:square-terminal","title":"在线命令"}',
|
||||
1,
|
||||
3
|
||||
),
|
||||
(
|
||||
2041700000000100409,
|
||||
2041700000000100400,
|
||||
'QqBotPlugin',
|
||||
'/qqbot/plugin',
|
||||
'/qqbot/plugin/list',
|
||||
NULL,
|
||||
'QqBot:Plugin:List',
|
||||
'menu',
|
||||
'{"icon":"lucide:plug","title":"插件能力"}',
|
||||
1,
|
||||
4
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
pid = VALUES(pid),
|
||||
path = VALUES(path),
|
||||
component = VALUES(component),
|
||||
status = VALUES(status);
|
||||
redirect = VALUES(redirect),
|
||||
auth_code = VALUES(auth_code),
|
||||
type = VALUES(type),
|
||||
meta = VALUES(meta),
|
||||
status = VALUES(status),
|
||||
sort = VALUES(sort),
|
||||
is_deleted = 0;
|
||||
|
||||
INSERT INTO admin_dict (
|
||||
id,
|
||||
dict_code,
|
||||
label,
|
||||
value,
|
||||
children_code,
|
||||
sort,
|
||||
status
|
||||
) VALUES
|
||||
(
|
||||
2041700000000300001,
|
||||
'COMPONENT_TYPE',
|
||||
'图表',
|
||||
'1',
|
||||
'CHART',
|
||||
1,
|
||||
1
|
||||
),
|
||||
(
|
||||
2041700000000300101,
|
||||
'CHART',
|
||||
'未分类',
|
||||
'-1',
|
||||
NULL,
|
||||
0,
|
||||
1
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
label = VALUES(label),
|
||||
children_code = VALUES(children_code),
|
||||
sort = VALUES(sort),
|
||||
status = VALUES(status),
|
||||
is_deleted = 0;
|
||||
|
||||
INSERT IGNORE INTO admin_user_role (user_id, role_id)
|
||||
VALUES (2041700000000000002, 2041700000000010001);
|
||||
|
||||
INSERT IGNORE INTO admin_role_menu (role_id, menu_id)
|
||||
SELECT 2041700000000010001, id
|
||||
FROM admin_menu
|
||||
WHERE is_deleted = 0;
|
||||
|
||||
INSERT INTO platform_setting (
|
||||
id,
|
||||
@ -121,6 +268,9 @@ INSERT INTO qqbot_command (
|
||||
id,
|
||||
operation_key,
|
||||
command_key,
|
||||
code,
|
||||
name,
|
||||
aliases,
|
||||
plugin_key,
|
||||
enabled,
|
||||
cooldown_seconds
|
||||
@ -128,11 +278,17 @@ INSERT INTO qqbot_command (
|
||||
1000000000000000201,
|
||||
'bangdream.song.search',
|
||||
'bangdream_song',
|
||||
'bd',
|
||||
'BangDream 查歌',
|
||||
'["查曲","bd","bangdream","bandori","邦邦","邦邦查歌"]',
|
||||
'bangdream',
|
||||
1,
|
||||
2
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
operation_key = VALUES(operation_key),
|
||||
code = VALUES(code),
|
||||
name = VALUES(name),
|
||||
aliases = VALUES(aliases),
|
||||
plugin_key = VALUES(plugin_key),
|
||||
enabled = VALUES(enabled),
|
||||
cooldown_seconds = VALUES(cooldown_seconds);
|
||||
|
||||
@ -2,6 +2,7 @@ SELECT 'admin_user' AS table_name, COUNT(*) AS row_count FROM admin_user;
|
||||
SELECT 'admin_role' AS table_name, COUNT(*) AS row_count FROM admin_role;
|
||||
SELECT 'admin_menu' AS table_name, COUNT(*) AS row_count FROM admin_menu;
|
||||
SELECT 'platform_setting' AS table_name, COUNT(*) AS row_count FROM platform_setting;
|
||||
SELECT 'admin_dict' AS table_name, COUNT(*) AS row_count FROM admin_dict;
|
||||
SELECT 'qqbot_command' AS table_name, COUNT(*) AS row_count FROM qqbot_command;
|
||||
SELECT 'qqbot_plugin' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin;
|
||||
SELECT 'napcat_device_identity' AS table_name, COUNT(*) AS row_count FROM napcat_device_identity;
|
||||
@ -9,7 +10,9 @@ SELECT 'napcat_device_identity' AS table_name, COUNT(*) AS row_count FROM napcat
|
||||
SELECT 'seed_admin_user' AS check_name, COUNT(*) AS matched_rows
|
||||
FROM admin_user
|
||||
WHERE username = 'admin'
|
||||
AND status = 'password_unset';
|
||||
AND password <> ''
|
||||
AND status = 1
|
||||
AND is_deleted = 0;
|
||||
|
||||
SELECT 'seed_platform_schema_version' AS check_name, COUNT(*) AS matched_rows
|
||||
FROM platform_setting
|
||||
@ -40,6 +43,12 @@ WHERE table_schema = DATABASE()
|
||||
AND table_name = 'platform_setting'
|
||||
AND index_name = 'uk_platform_setting_key';
|
||||
|
||||
SELECT 'index_admin_dict_code_value' AS check_name, COUNT(*) AS matched_rows
|
||||
FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'admin_dict'
|
||||
AND index_name = 'uk_admin_dict_code_value';
|
||||
|
||||
SELECT 'index_qqbot_command_key' AS check_name, COUNT(*) AS matched_rows
|
||||
FROM information_schema.statistics
|
||||
WHERE table_schema = DATABASE()
|
||||
|
||||
@ -44,7 +44,10 @@ import { RuntimeModule } from './runtime';
|
||||
password: configService.get('DB_PASSWORD'),
|
||||
database: configService.get('DB_DATABASE'),
|
||||
synchronize: configService.get<string>('DB_SYNC') === 'true',
|
||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||
entities: [
|
||||
__dirname + '/**/*.entity{.ts,.js}',
|
||||
__dirname + '/**/*.entities{.ts,.js}',
|
||||
],
|
||||
subscribers: [__dirname + '/**/*.subscriber{.ts,.js}'],
|
||||
};
|
||||
},
|
||||
|
||||
@ -105,6 +105,15 @@ describe('QQBot plugin platform API contract', () => {
|
||||
expect(source).toContain('QqbotPluginPlatformModule');
|
||||
});
|
||||
|
||||
it('loads plural entity files into the TypeORM datasource', () => {
|
||||
const source = readFileSync(
|
||||
join(__dirname, '../../../../src/app.module.ts'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
expect(source).toContain('*.entities{.ts,.js}');
|
||||
});
|
||||
|
||||
it('exposes plugin-platform management routes', () => {
|
||||
expect(routeKey).toBeDefined();
|
||||
expect(
|
||||
|
||||
@ -53,4 +53,78 @@ describe('refactor v3 schema skeleton', () => {
|
||||
expect(verify).toContain('qqbot_plugin');
|
||||
expect(verify).toContain('napcat_device_identity');
|
||||
});
|
||||
|
||||
it('declares bootstrap tables required before the API can finish startup', () => {
|
||||
const sql = readFileSync(
|
||||
join(root, 'sql/refactor-v3/00-full-schema.sql'),
|
||||
'utf8',
|
||||
);
|
||||
const verify = readFileSync(
|
||||
join(root, 'sql/refactor-v3/99-verify.sql'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
expect(sql).toContain('CREATE TABLE IF NOT EXISTS admin_dict');
|
||||
expect(verify).toContain('admin_dict');
|
||||
});
|
||||
|
||||
it('declares blog tables compatible with current runtime entities', () => {
|
||||
const sql = readFileSync(
|
||||
join(root, 'sql/refactor-v3/00-full-schema.sql'),
|
||||
'utf8',
|
||||
);
|
||||
const blogTermColumns = sql.match(
|
||||
/CREATE TABLE IF NOT EXISTS blog_term \(([\s\S]*?)\) ENGINE=/,
|
||||
)?.[1];
|
||||
|
||||
expect(sql).toContain('CREATE TABLE IF NOT EXISTS blog_article');
|
||||
expect(sql).toContain('CREATE TABLE IF NOT EXISTS blog_theme_config');
|
||||
expect(sql).toContain('content_markdown');
|
||||
expect(sql).toContain('content_html');
|
||||
expect(sql).toContain('category_items');
|
||||
expect(sql).toContain('tag_items');
|
||||
expect(sql).toContain('author_name');
|
||||
expect(sql).toContain('publish_time');
|
||||
expect(sql).toContain('is_deleted');
|
||||
expect(blogTermColumns).toContain('kind');
|
||||
expect(blogTermColumns).toContain('name');
|
||||
expect(blogTermColumns).toContain('description');
|
||||
expect(blogTermColumns).toContain('parent_id');
|
||||
});
|
||||
|
||||
it('seeds qqbot command rows with required command code and aliases', () => {
|
||||
const seed = readFileSync(
|
||||
join(root, 'sql/refactor-v3/01-seed-core.sql'),
|
||||
'utf8',
|
||||
);
|
||||
const commandColumns = seed.match(
|
||||
/INSERT INTO qqbot_command \(([\s\S]*?)\) VALUES/,
|
||||
)?.[1];
|
||||
|
||||
expect(commandColumns).toContain('code');
|
||||
expect(commandColumns).toContain('aliases');
|
||||
expect(seed).toContain('["查曲","bd","bangdream","bandori","邦邦","邦邦查歌"]');
|
||||
});
|
||||
|
||||
it('runs dry-run SQL sources with utf8mb4 and fails on native mysql errors', () => {
|
||||
const dryRunScript = readFileSync(
|
||||
join(root, 'scripts/refactor-v3/db-dry-run.ps1'),
|
||||
'utf8',
|
||||
);
|
||||
|
||||
expect(dryRunScript).toContain('--default-character-set=utf8mb4');
|
||||
expect(dryRunScript).toContain('$LASTEXITCODE');
|
||||
expect(dryRunScript).toContain('throw');
|
||||
});
|
||||
|
||||
it('uses the Nest listen port as the local smoke default base URL', () => {
|
||||
const localSmokeScript = readFileSync(
|
||||
join(root, 'scripts/refactor-v3/local-smoke.ps1'),
|
||||
'utf8',
|
||||
);
|
||||
const main = readFileSync(join(root, 'src/main.ts'), 'utf8');
|
||||
|
||||
expect(main).toContain('app.listen(48085)');
|
||||
expect(localSmokeScript).toContain('http://127.0.0.1:48085');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user