feat(analytics): add SEO/GEO page dashboard and retire Rybbit SSO
Expose Umami memind-pages discoveryChannel data in adm with a public-page style table, proxy it via admin-api, and remove Rybbit configuration paths. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+17
-12
@@ -5,6 +5,7 @@ import { spawn } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import express from 'express';
|
||||
import { listUsagePaged, listLedgerPaged, getUsageStats, getUsageSummary } from './pagination.mjs';
|
||||
import { fetchMemindDiscoveryPages } from './umami-analytics.mjs';
|
||||
|
||||
const projectRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
|
||||
@@ -236,19 +237,23 @@ export function createAdminApp(services) {
|
||||
res.json({ url: `${baseUrl}/auth/memind?ticket=${encoded}.${signature}` });
|
||||
});
|
||||
|
||||
adminApi.get('/analytics/seo-geo-pages', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const config = loadMindSpaceConfig ? await loadMindSpaceConfig(pool) : null;
|
||||
const result = await fetchMemindDiscoveryPages(req.query, {
|
||||
env: process.env,
|
||||
analyticsConfig: config?.analytics ?? {},
|
||||
});
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
res.status(503).json({
|
||||
message: error instanceof Error ? error.message : '无法加载 SEO/GEO 页面统计',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
adminApi.get('/analytics/rybbit-sso', requireAdmin, async (_req, res) => {
|
||||
const sharedSecret = process.env.MEMIND_RYBBIT_SSO_SECRET?.trim();
|
||||
if (!sharedSecret) return res.status(503).json({ message: '未配置 Rybbit 单点登录密钥' });
|
||||
const email = process.env.RYBBIT_SSO_EMAIL?.trim().toLowerCase();
|
||||
if (!email) return res.status(503).json({ message: '未配置 Rybbit 单点登录账号' });
|
||||
const baseUrl = String(process.env.RYBBIT_URL || 'https://rybbit.tkmind.cn').replace(/\/$/, '');
|
||||
const encoded = Buffer.from(JSON.stringify({
|
||||
email,
|
||||
exp: Math.floor(Date.now() / 1000) + 60,
|
||||
nonce: crypto.randomUUID(),
|
||||
})).toString('base64url');
|
||||
const signature = crypto.createHmac('sha256', sharedSecret).update(encoded).digest('base64url');
|
||||
res.json({ url: `${baseUrl}/api/auth/memind?ticket=${encoded}.${signature}` });
|
||||
return res.status(410).json({ message: 'Rybbit 已退役,请使用 Umami 与 SEO/GEO 流量看板' });
|
||||
});
|
||||
|
||||
adminApi.get('/users', requireAdmin, async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user