Files
YMhut-box-C-/server/unified-management/internal/db/schema.go
T
QWQLwToo 2513eb2903
build-winui / winui (push) Has been cancelled
继续更新 update 门户站点界面和功能
2026-06-26 20:17:48 +08:00

297 lines
10 KiB
Go

package db
import (
"database/sql"
"fmt"
)
const CurrentSchemaVersion = "2026-06-compat-baseline"
func (s *Store) migrate(conn *sql.DB, d dialect) error {
statements := []string{}
if d.name == "sqlite" {
statements = append(statements,
"PRAGMA busy_timeout = 5000",
"PRAGMA journal_mode = WAL",
"PRAGMA foreign_keys = ON",
)
}
statements = append(statements, schemaStatements(d)...)
for _, statement := range statements {
if _, err := conn.Exec(d.rebind(statement)); err != nil {
return err
}
}
return s.recordSchemaVersion(conn, d)
}
func schemaStatements(d dialect) []string {
return []string{
`CREATE TABLE IF NOT EXISTS schema_migrations (
version VARCHAR(64) NOT NULL PRIMARY KEY,
applied_at TEXT NOT NULL,
description VARCHAR(255) NOT NULL DEFAULT ''
)`,
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS admin_users (
id %s,
username TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
password_changed INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS sessions (
id %s,
session_id TEXT NOT NULL UNIQUE,
username TEXT NOT NULL,
csrf TEXT NOT NULL,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_packages (
id %s,
product TEXT NOT NULL,
version TEXT NOT NULL,
platform TEXT NOT NULL,
arch TEXT NOT NULL,
file_name TEXT NOT NULL UNIQUE,
url TEXT NOT NULL,
sha256 TEXT NOT NULL,
size_bytes BIGINT NOT NULL DEFAULT 0,
enabled INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_notices (
id %s,
version TEXT NOT NULL UNIQUE,
build TEXT NOT NULL DEFAULT '',
channel TEXT NOT NULL DEFAULT 'stable',
title TEXT NOT NULL DEFAULT '',
message TEXT NOT NULL DEFAULT '',
release_notes TEXT NOT NULL DEFAULT '',
message_md TEXT NOT NULL DEFAULT '',
release_notes_md TEXT NOT NULL DEFAULT '',
download_url TEXT NOT NULL DEFAULT '',
notice_file TEXT NOT NULL DEFAULT '',
raw_json TEXT NOT NULL,
published_at TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS release_notice_revisions (
id %s,
version TEXT NOT NULL,
raw_json TEXT NOT NULL,
note TEXT NOT NULL DEFAULT '',
created_by TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_tickets (
code TEXT PRIMARY KEY,
title TEXT NOT NULL,
type TEXT NOT NULL,
severity TEXT NOT NULL,
category TEXT NOT NULL DEFAULT '',
priority TEXT NOT NULL DEFAULT '',
contact TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL,
status_detail TEXT NOT NULL DEFAULT '',
public_reply TEXT NOT NULL DEFAULT '',
note TEXT NOT NULL DEFAULT '',
assignee TEXT NOT NULL DEFAULT '',
handled_by TEXT NOT NULL DEFAULT '',
due_at TEXT NOT NULL DEFAULT '',
resolved_at TEXT NOT NULL DEFAULT '',
archived_at TEXT NOT NULL DEFAULT '',
sla_level TEXT NOT NULL DEFAULT '',
source_channel TEXT NOT NULL DEFAULT '',
risk_score INTEGER NOT NULL DEFAULT 0,
resolution TEXT NOT NULL DEFAULT '',
attachment TEXT NOT NULL DEFAULT '',
package_path TEXT NOT NULL DEFAULT '',
encrypted_package_path TEXT NOT NULL DEFAULT '',
package_sha256 TEXT NOT NULL DEFAULT '',
plain_package_sha256 TEXT NOT NULL DEFAULT '',
summary_text TEXT NOT NULL DEFAULT '',
included_files TEXT NOT NULL DEFAULT '',
mail_sent INTEGER NOT NULL DEFAULT 0,
remote_addr TEXT NOT NULL DEFAULT '',
tags TEXT NOT NULL DEFAULT '[]',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
last_activity_at TEXT NOT NULL
)`),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_comments (
id %s,
feedback_code TEXT NOT NULL,
author TEXT NOT NULL DEFAULT '',
body TEXT NOT NULL,
internal INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_attachments (
id %s,
feedback_code TEXT NOT NULL,
kind TEXT NOT NULL,
path TEXT NOT NULL,
file_name TEXT NOT NULL,
sha256 TEXT NOT NULL DEFAULT '',
size_bytes BIGINT NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS feedback_events (
id %s,
feedback_code TEXT NOT NULL,
event_type TEXT NOT NULL,
actor TEXT NOT NULL DEFAULT '',
from_value TEXT NOT NULL DEFAULT '',
to_value TEXT NOT NULL DEFAULT '',
message TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
)`, d.idType()),
`CREATE TABLE IF NOT EXISTS feedback_tags (
feedback_code TEXT NOT NULL,
tag TEXT NOT NULL,
created_at TEXT NOT NULL,
PRIMARY KEY (feedback_code, tag)
)`,
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS mail_records (
id %s,
feedback_code TEXT NOT NULL DEFAULT '',
kind TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT '',
to_address TEXT NOT NULL DEFAULT '',
subject TEXT NOT NULL DEFAULT '',
plain_body TEXT NOT NULL DEFAULT '',
html_body TEXT NOT NULL DEFAULT '',
attachment_path TEXT NOT NULL DEFAULT '',
attachment_name TEXT NOT NULL DEFAULT '',
error_message TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
sent_at TEXT NOT NULL DEFAULT ''
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS source_categories (
id %s,
category_id TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1,
ui_config TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS source_endpoints (
id %s,
category_id TEXT NOT NULL,
category_name TEXT NOT NULL,
source_id TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
method TEXT NOT NULL DEFAULT 'GET',
api_url TEXT NOT NULL DEFAULT '',
url_template TEXT NOT NULL DEFAULT '',
thumbnail_url TEXT NOT NULL DEFAULT '',
proxy_mode TEXT NOT NULL DEFAULT 'client_direct',
timeout_ms INTEGER NOT NULL DEFAULT 8000,
retry_count INTEGER NOT NULL DEFAULT 1,
cache_seconds INTEGER NOT NULL DEFAULT 300,
check_interval_sec INTEGER NOT NULL DEFAULT 300,
enabled INTEGER NOT NULL DEFAULT 1,
client_visible INTEGER NOT NULL DEFAULT 1,
supported_formats TEXT NOT NULL DEFAULT '[]',
last_status TEXT NOT NULL DEFAULT 'unknown',
last_latency_ms INTEGER NOT NULL DEFAULT 0,
last_checked_at TEXT NOT NULL DEFAULT '',
last_error TEXT NOT NULL DEFAULT '',
consecutive_failure INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS endpoint_health_checks (
id %s,
source_db_id BIGINT NOT NULL,
status TEXT NOT NULL,
latency_ms INTEGER NOT NULL DEFAULT 0,
error TEXT NOT NULL DEFAULT '',
checked_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS endpoint_call_logs (
id %s,
source_id TEXT NOT NULL,
status TEXT NOT NULL,
latency_ms INTEGER NOT NULL DEFAULT 0,
error TEXT NOT NULL DEFAULT '',
client TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS database_sync_jobs (
id %s,
direction TEXT NOT NULL,
status TEXT NOT NULL,
message TEXT NOT NULL DEFAULT '',
tables_json TEXT NOT NULL DEFAULT '{}',
started_at TEXT NOT NULL,
finished_at TEXT NOT NULL DEFAULT ''
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS legacy_sync_jobs (
id %s,
status TEXT NOT NULL,
summary TEXT NOT NULL DEFAULT '',
stats_json TEXT NOT NULL DEFAULT '{}',
started_at TEXT NOT NULL,
finished_at TEXT NOT NULL DEFAULT ''
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS audit_logs (
id %s,
actor TEXT NOT NULL DEFAULT '',
type TEXT NOT NULL,
target TEXT NOT NULL DEFAULT '',
message TEXT NOT NULL DEFAULT '',
ip TEXT NOT NULL DEFAULT '',
user_agent TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS legacy_json_revisions (
id %s,
name TEXT NOT NULL,
raw TEXT NOT NULL,
note TEXT NOT NULL DEFAULT '',
created_by TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
)`, d.idType()),
fmt.Sprintf(`CREATE TABLE IF NOT EXISTS webhook_deliveries (
id %s,
webhook_name TEXT NOT NULL DEFAULT '',
event TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT '',
attempts INTEGER NOT NULL DEFAULT 0,
response_code INTEGER NOT NULL DEFAULT 0,
error_message TEXT NOT NULL DEFAULT '',
payload_sha256 TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
finished_at TEXT NOT NULL DEFAULT ''
)`, d.idType()),
`CREATE INDEX IF NOT EXISTS idx_feedback_tickets_activity ON feedback_tickets(last_activity_at)`,
`CREATE INDEX IF NOT EXISTS idx_feedback_comments_code ON feedback_comments(feedback_code)`,
`CREATE INDEX IF NOT EXISTS idx_feedback_attachments_code ON feedback_attachments(feedback_code)`,
`CREATE INDEX IF NOT EXISTS idx_feedback_events_code ON feedback_events(feedback_code)`,
`CREATE INDEX IF NOT EXISTS idx_mail_records_code ON mail_records(feedback_code)`,
`CREATE INDEX IF NOT EXISTS idx_endpoint_call_logs_source ON endpoint_call_logs(source_id)`,
`CREATE INDEX IF NOT EXISTS idx_audit_logs_created ON audit_logs(created_at)`,
`CREATE INDEX IF NOT EXISTS idx_legacy_json_revisions_name ON legacy_json_revisions(name, id)`,
`CREATE INDEX IF NOT EXISTS idx_release_notices_version ON release_notices(version)`,
`CREATE INDEX IF NOT EXISTS idx_release_notice_revisions_version ON release_notice_revisions(version, id)`,
}
}
func (s *Store) recordSchemaVersion(conn *sql.DB, d dialect) error {
columns := []string{"version", "applied_at", "description"}
_, err := conn.Exec(d.rebind(d.upsert("schema_migrations", columns, []string{"version"})),
CurrentSchemaVersion,
Now(),
"unified-management layered monolith baseline",
)
return err
}