feat(admin): Implement operational monitoring MVP and login optimization

Summary:
- Add SimpleLog table for activity tracking (admin_schema)
- Implement ActivityService with fire-and-forget pattern
- Add stats API endpoints (overview/live-feed/user-overview/cleanup)
- Complete activity logging for 7 modules (SYSTEM/AIA/PKB/ASL/DC/RVW/IIT)
- Update Admin Dashboard with DAU/DAT metrics and live feed
- Fix user module permission display logic
- Fix login redirect to /ai-qa instead of homepage
- Replace top navigation LOGO with brand image
- Fix PKB workspace layout CSS conflict (rename to .pa-chat-container)

New files:
- backend/src/common/services/activity.service.ts
- backend/src/modules/admin/controllers/statsController.ts
- backend/src/modules/admin/routes/statsRoutes.ts
- frontend-v2/src/modules/admin/api/statsApi.ts
- docs/03-.../04-operational-monitoring-mvp-plan.md
- docs/03-.../04-operational-monitoring-mvp-implementation.md

Tested: All features verified locally
This commit is contained in:
2026-01-25 22:16:16 +08:00
parent 303dd78c54
commit 01a17f1e6f
36 changed files with 2962 additions and 95 deletions

View File

@@ -7,6 +7,7 @@ import {
searchKnowledgeBase as ragSearchKnowledgeBase,
type RagSearchResult,
} from './ragService.js';
import { activityService } from '../../../common/services/activity.service.js';
/**
* 知识库服务
@@ -58,6 +59,26 @@ export async function createKnowledgeBase(
ekbKbId: result.ekbKbId,
});
// 埋点:记录知识库创建
try {
const userInfo = await prisma.user.findUnique({
where: { id: userId },
include: { tenants: true }
});
if (userInfo) {
activityService.log(
userInfo.tenant_id,
userInfo.tenants?.name || null,
userId,
userInfo.name,
'PKB',
'创建知识库',
'CREATE',
name
);
}
} catch (e) { /* 埋点失败不影响主业务 */ }
// 4. 转换BigInt为Number
return {
...knowledgeBase,

View File

@@ -14,6 +14,7 @@ import {
type SearchResult,
type IngestResult,
} from '../../../common/rag/index.js';
import { activityService } from '../../../common/services/activity.service.js';
// ==================== 类型定义 ====================
@@ -65,7 +66,29 @@ export async function searchKnowledgeBase(
// 查找对应的 EKB 知识库
const ekbKb = await findOrCreateEkbKnowledgeBase(userId, knowledgeBase.name, knowledgeBase.description);
return searchWithPgvector(ekbKb.id, query, { topK, minScore, mode });
const results = await searchWithPgvector(ekbKb.id, query, { topK, minScore, mode });
// 埋点:记录 RAG 检索
try {
const user = await prisma.user.findUnique({
where: { id: userId },
include: { tenants: true }
});
if (user) {
activityService.log(
user.tenant_id,
user.tenants?.name || null,
userId,
user.name,
'PKB',
'RAG检索',
'USE',
`kb:${knowledgeBase.name}, results:${results.length}`
);
}
} catch (e) { /* 埋点失败不影响主业务 */ }
return results;
}
/**