refactor: Business logic and dependencies updates

- 核心服务代码更新 (db, server, auth, proxy)
- Agent 相关模块更新 (mindspace, experience)
- 前端组件和 hooks 更新
- 数据库 schema 更新
- 依赖版本更新
This commit is contained in:
john
2026-06-27 08:25:02 +08:00
parent f1220a7905
commit 25f8223253
20 changed files with 1458 additions and 116 deletions
+46 -3
View File
@@ -13,13 +13,27 @@ export function isDatabaseConfigured() {
);
}
// Pool size must scale with peak concurrent agent sessions: each session does
// several queries per turn (session node lookup + policy + provider + reconcile).
// The historical default of 10 starved at ~30 concurrent sessions. Tune via
// MYSQL_POOL_SIZE per portal instance × expected concurrency.
function resolvePoolOptions() {
const connectionLimit = Math.max(1, Number(process.env.MYSQL_POOL_SIZE ?? 50));
// queueLimit caps how many requests wait for a free connection before failing
// fast, instead of piling up unboundedly under a connection-starvation storm.
const queueLimit = Math.max(0, Number(process.env.MYSQL_POOL_QUEUE_LIMIT ?? 0));
return { waitForConnections: true, connectionLimit, queueLimit };
}
export function createDbPool() {
if (!isDatabaseConfigured()) {
throw new Error('MySQL 未配置,请设置 DATABASE_URL 或 MYSQL_* 环境变量');
}
const poolOptions = resolvePoolOptions();
if (process.env.DATABASE_URL) {
return mysql.createPool(process.env.DATABASE_URL);
return mysql.createPool({ uri: process.env.DATABASE_URL, ...poolOptions });
}
return mysql.createPool({
@@ -28,8 +42,7 @@ export function createDbPool() {
user: process.env.MYSQL_USER ?? 'boot',
password: process.env.MYSQL_PASSWORD ?? '',
database: process.env.MYSQL_DATABASE ?? 'tkmind',
waitForConnections: true,
connectionLimit: 10,
...poolOptions,
});
}
@@ -199,6 +212,26 @@ export async function migrateSchema(pool) {
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`);
// Shared experience store (etat C). Keep in sync with schema.sql.
await pool.query(`
CREATE TABLE IF NOT EXISTS h5_experience (
id CHAR(36) PRIMARY KEY,
scope VARCHAR(64) NOT NULL DEFAULT 'global',
kind VARCHAR(32) NOT NULL DEFAULT 'lesson',
title VARCHAR(255) NOT NULL,
body MEDIUMTEXT NOT NULL,
tags_json JSON NULL,
source_session_id VARCHAR(128) NULL,
source_user_id CHAR(36) NULL,
use_count BIGINT NOT NULL DEFAULT 0,
embedding JSON NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_h5_experience_scope_updated (scope, updated_at),
FULLTEXT KEY ftx_h5_experience (title, body)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
`);
const publishColumns = [
['plaza_view_count', 'BIGINT NOT NULL DEFAULT 0'],
['plaza_like_count', 'BIGINT NOT NULL DEFAULT 0'],
@@ -239,6 +272,16 @@ export async function migrateSchema(pool) {
);
}
// goosed_target stores the resolved upstream URL a session is pinned to, so
// routing survives reordering or resizing the goosed target list. The legacy
// integer goosed_node is kept as a fallback for rows written before this column
// existed (and for older bundles that still read it).
if (!(await columnExists(pool, 'h5_user_sessions', 'goosed_target'))) {
await pool.query(
`ALTER TABLE h5_user_sessions ADD COLUMN goosed_target VARCHAR(255) NULL AFTER goosed_node`,
);
}
const oauthStateColumns = [
['intent', "VARCHAR(16) NOT NULL DEFAULT 'login' AFTER utm_campaign"],
['bind_user_id', 'CHAR(36) NULL AFTER intent'],