Files
memind_adm/server/bootstrap.mjs
T
john 731d93843d feat(admin): add Memory V2 personal controls and Skill Runtime page
Wire admin UI and API routes to restored Memind personal memory and skill
runtime modules, including candidate review and runtime status display.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 14:00:20 +08:00

169 lines
6.6 KiB
JavaScript

import path from 'node:path';
import { createDbPool, isDatabaseConfigured } from './db.mjs';
import { projectRoot } from './load-env.mjs';
import { importMemind, resolveMemindLib } from './lib-path.mjs';
import { createSystemTestAccountService, ensureSystemTestAccountSchema } from './system-test-accounts.mjs';
export async function bootstrapAdminServices() {
if (!isDatabaseConfigured()) {
throw new Error('数据库未配置');
}
const memindLib = resolveMemindLib();
const h5Root =
process.env.MEMIND_LIB_ROOT?.trim() ??
path.join(projectRoot, '../Memind');
const pool = createDbPool();
const { loadCreateLlmProviderService } = await import('./llm-provider-loader.mjs');
const createLlmProviderService = await loadCreateLlmProviderService();
const { createWechatAdminService } = await importMemind('wechat-admin.mjs');
const { createWechatMpService, loadWechatMpConfig } = await importMemind('wechat-mp.mjs');
const { createPlazaPostService, formatPostRow } = await importMemind('plaza-posts.mjs');
const { createPlazaInteractionService } = await importMemind('plaza-interactions.mjs');
const { createPlazaOpsService } = await importMemind('plaza-ops.mjs');
const { createNoopPlazaRedis } = await importMemind('plaza-redis.mjs');
const { ensureAlgorithmConfig, loadAlgorithmConfig } = await importMemind('plaza-algorithm.mjs');
const {
ensureMindSpaceConfig,
loadMindSpaceConfig,
updateMindSpaceConfig,
} = await importMemind('mindspace-config.mjs');
const { createMemoryV2AdminConfigService } = await importMemind('memory-v2-admin-config.mjs');
const { createPersonalMemoryCandidateStore } = await importMemind('memory-v2-personal-store.mjs');
const { createSkillRuntimeAdminConfigService } = await importMemind('skill-runtime-admin-config.mjs');
const { createAssetGatewayConfigService } = await importMemind('asset-gateway.mjs');
const { ensureAssetGatewaySchema } = await importMemind('db.mjs');
const { createWechatScheduleLlmConfigService } = await importMemind('wechat-schedule-llm-config.mjs');
const { createAdminSystemTestService } = await importMemind('admin-system-tests.mjs');
const { createOpsApi } = await importMemind('admin-routes.mjs');
const { createWordFilterService, ensureWordFilterSchema } = await importMemind('word-filter.mjs');
const {
USER_COOKIE,
clearUserSessionCookie,
createUserAuth,
resolveCookieDomainForRequest,
userLoginCookies,
} = await importMemind('user-auth.mjs');
const {
ensurePlanCatalogSchema,
createPlanCatalogService,
createSubscriptionService,
} = await importMemind('billing-subscription.mjs');
const usersRoot =
process.env.H5_USERS_ROOT?.trim() ?? path.join(projectRoot, 'data', 'users');
const apiTarget = process.env.TKMIND_API_TARGET ?? 'https://127.0.0.1:18006';
const apiSecret = process.env.TKMIND_SERVER__SECRET_KEY ?? 'local-dev-secret';
const plazaRedis = createNoopPlazaRedis();
await ensureAlgorithmConfig(pool);
const algorithmConfig = await loadAlgorithmConfig(pool);
await ensureMindSpaceConfig(pool, { env: process.env, seedDefault: false });
const mindSpaceConfig = await loadMindSpaceConfig(pool, { env: process.env });
const plazaInteractions = createPlazaInteractionService(pool, { formatPostRow, plazaRedis });
let plazaOps = null;
const plazaPosts = createPlazaPostService(pool, {
loadViewerReactions: (viewerId, postIds) =>
plazaInteractions.loadViewerReactions(viewerId, postIds),
plazaRedis,
algorithmConfig,
onPostPublished: () => {},
loadFeaturedPosts: async (viewerId) => {
if (!plazaOps) return { homepage_banner: [], trending: [], category_top: {} };
return plazaOps.loadActiveFeaturedPosts(viewerId);
},
});
plazaOps = createPlazaOpsService(pool, {
formatPostRow,
reviewPost: (...args) => plazaPosts.reviewPost(...args),
invalidateFeedCaches: () => plazaRedis?.invalidateFeedCaches?.(),
});
const userAuth = createUserAuth(pool, {
usersRoot,
h5Root,
defaultSignupBalanceCents: Number(process.env.H5_SIGNUP_BALANCE_CENTS ?? 500),
});
const llmProviderService = createLlmProviderService(pool, {
apiTarget,
apiSecret,
});
await ensureAssetGatewaySchema(pool);
const assetGatewayConfigService = createAssetGatewayConfigService(pool, { llmProviderService });
const memoryV2ConfigService = createMemoryV2AdminConfigService(pool, {
env: process.env,
});
const personalMemoryCandidateStore = createPersonalMemoryCandidateStore(pool);
const skillRuntimeConfigService = createSkillRuntimeAdminConfigService(pool, {
env: process.env,
h5Root,
});
const wechatScheduleLlmConfigService = createWechatScheduleLlmConfigService(pool, {
env: process.env,
});
const adminSystemTestService = createAdminSystemTestService({
pool,
userAuth,
portalBaseUrl: `http://127.0.0.1:${process.env.H5_PORT ?? 8081}`,
});
const wechatMpConfig = loadWechatMpConfig();
const wechatMpService = createWechatMpService({
config: wechatMpConfig,
userAuth,
apiFetch: async () => {
throw new Error('admin api does not proxy WeChat chat sessions');
},
});
const wechatAdmin = createWechatAdminService(pool, {
config: wechatMpConfig,
scheduleEnabled: process.env.H5_SCHEDULE_ENABLED === '1',
reminderWorkerEnabled: process.env.H5_REMINDER_WORKER_ENABLED === '1',
sendWechatTextToUser: wechatMpService?.enabled
? (userId, text) => wechatMpService.sendTextToUser(userId, text)
: null,
});
await ensureWordFilterSchema(pool);
const wordFilterService = createWordFilterService(pool);
await ensurePlanCatalogSchema(pool);
const planCatalogService = createPlanCatalogService(pool);
const subscriptionService = createSubscriptionService(pool, {
getPlanAsync: (planType) => planCatalogService.getPlan(planType),
});
await ensureSystemTestAccountSchema(pool);
const systemTestAccountService = createSystemTestAccountService(pool);
console.log(`Admin DB connected (${process.env.MYSQL_DATABASE ?? 'via DATABASE_URL'})`);
console.log(`Users root: ${usersRoot}`);
console.log(`Memind lib: ${memindLib}`);
return {
pool,
userAuth,
llmProviderService,
assetGatewayConfigService,
plazaOps,
createOpsApi,
wechatAdmin,
mindSpaceConfig,
loadMindSpaceConfig,
updateMindSpaceConfig,
memoryV2ConfigService,
personalMemoryCandidateStore,
skillRuntimeConfigService,
wechatScheduleLlmConfigService,
adminSystemTestService,
systemTestAccountService,
wordFilterService,
planCatalogService,
subscriptionService,
USER_COOKIE,
userLoginCookies,
clearUserSessionCookie,
resolveCookieDomainForRequest,
};
}