管理员后台设计(Admin Dashboard)
1. 核心概念
管理员后台是"第二大脑"产品的 SaaS 运营中枢,面向平台管理员、运营人员、客服人员和系统管理员。它提供用户生命周期管理、数据监控、内容审核、系统配置、订阅计费、日志审计等全栈运营能力,支持多租户隔离和分级权限控制。
2. 权限模型(RBAC)
2.1 角色定义
typescript
enum AdminRole {
SUPER_ADMIN = 'super_admin', // 超级管理员:全部权限
PLATFORM_ADMIN = 'platform_admin', // 平台管理员:用户/内容/系统管理
OPERATOR = 'operator', // 运营人员:数据/活动/用户支持
FINANCE_ADMIN = 'finance_admin', // 财务管理员:订阅/订单/退款
SUPPORT = 'support', // 客服人员:用户查询/工单处理
AUDITOR = 'auditor', // 审计人员:日志/安全/合规审查
READONLY = 'readonly' // 只读观察员:数据查看,无操作权限
}
interface Permission {
resource: string; // 资源类型
actions: ('create' | 'read' | 'update' | 'delete' | 'approve' | 'export' | 'manage')[];
scope: 'own' | 'team' | 'all' | 'tenant'; // 数据范围
}
// 角色权限矩阵
const ROLE_PERMISSIONS: Record<AdminRole, Permission[]> = {
SUPER_ADMIN: [
{ resource: '*', actions: ['create', 'read', 'update', 'delete', 'approve', 'export', 'manage'], scope: 'all' }
],
PLATFORM_ADMIN: [
{ resource: 'users', actions: ['create', 'read', 'update', 'delete', 'manage'], scope: 'all' },
{ resource: 'content', actions: ['read', 'update', 'delete', 'approve'], scope: 'all' },
{ resource: 'system', actions: ['read', 'update', 'manage'], scope: 'all' },
{ resource: 'logs', actions: ['read', 'export'], scope: 'all' },
{ resource: 'stats', actions: ['read', 'export'], scope: 'all' },
{ resource: 'announcements', actions: ['create', 'read', 'update', 'delete'], scope: 'all' }
],
OPERATOR: [
{ resource: 'users', actions: ['read', 'update'], scope: 'all' },
{ resource: 'content', actions: ['read', 'update', 'approve'], scope: 'all' },
{ resource: 'stats', actions: ['read', 'export'], scope: 'all' },
{ resource: 'announcements', actions: ['create', 'read', 'update'], scope: 'all' }
],
FINANCE_ADMIN: [
{ resource: 'subscriptions', actions: ['read', 'update', 'manage'], scope: 'all' },
{ resource: 'orders', actions: ['read', 'update', 'export'], scope: 'all' },
{ resource: 'refunds', actions: ['read', 'approve', 'export'], scope: 'all' },
{ resource: 'stats', actions: ['read', 'export'], scope: 'all' },
{ resource: 'users', actions: ['read'], scope: 'all' }
],
SUPPORT: [
{ resource: 'users', actions: ['read', 'update'], scope: 'all' },
{ resource: 'tickets', actions: ['create', 'read', 'update', 'manage'], scope: 'all' },
{ resource: 'content', actions: ['read'], scope: 'all' },
{ resource: 'logs', actions: ['read'], scope: 'all' }
],
AUDITOR: [
{ resource: 'logs', actions: ['read', 'export'], scope: 'all' },
{ resource: 'users', actions: ['read'], scope: 'all' },
{ resource: 'content', actions: ['read'], scope: 'all' },
{ resource: 'stats', actions: ['read', 'export'], scope: 'all' }
],
READONLY: [
{ resource: 'users', actions: ['read'], scope: 'all' },
{ resource: 'stats', actions: ['read'], scope: 'all' },
{ resource: 'content', actions: ['read'], scope: 'all' },
{ resource: 'logs', actions: ['read'], scope: 'all' }
]
};2.2 管理员用户模型
typescript
interface AdminUser {
id: string;
email: string; // 登录邮箱
name: string; // 显示名称
avatar?: string;
role: AdminRole;
permissions: Permission[]; // 动态权限(可覆盖角色默认)
// 状态
status: 'active' | 'inactive' | 'suspended' | 'pending';
lastLoginAt: Date;
lastLoginIp: string;
mfaEnabled: boolean; // 是否启用 MFA
// 审计
createdAt: Date;
createdBy: string; // 谁创建的
updatedAt: Date;
// 数据范围(多租户场景)
tenantId?: string; // 所属租户
managedTenants?: string[]; // 管理的租户列表(PLATFORM_ADMIN 可管理多个)
}3. 数据库 Schema(Admin 专用表)
sql
-- ==================== 管理员用户表 ====================
CREATE TABLE admin_users (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
avatar TEXT,
-- 密码(bcrypt 哈希)
password_hash TEXT NOT NULL,
-- 角色和权限
role TEXT NOT NULL CHECK(role IN ('super_admin', 'platform_admin', 'operator', 'finance_admin', 'support', 'auditor', 'readonly')),
permissions TEXT, -- JSON: Permission[] 动态覆盖
-- 状态
status TEXT DEFAULT 'pending' CHECK(status IN ('active', 'inactive', 'suspended', 'pending')),
last_login_at TIMESTAMP,
last_login_ip TEXT,
mfa_enabled BOOLEAN DEFAULT false,
mfa_secret TEXT, -- 加密存储
-- 审计
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- 多租户
tenant_id TEXT,
managed_tenants TEXT -- JSON: string[]
);
CREATE INDEX idx_admin_users_role ON admin_users(role);
CREATE INDEX idx_admin_users_status ON admin_users(status);
CREATE INDEX idx_admin_users_tenant ON admin_users(tenant_id);
-- ==================== 管理员登录日志 ====================
CREATE TABLE admin_login_logs (
id TEXT PRIMARY KEY,
admin_id TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
login_method TEXT, -- 'password' | 'mfa' | 'sso'
status TEXT CHECK(status IN ('success', 'failed', 'mfa_required')),
fail_reason TEXT, -- 失败原因
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (admin_id) REFERENCES admin_users(id)
);
CREATE INDEX idx_admin_login_logs_admin ON admin_login_logs(admin_id);
CREATE INDEX idx_admin_login_logs_time ON admin_login_logs(created_at);
-- ==================== 管理员操作日志 ====================
CREATE TABLE admin_audit_logs (
id TEXT PRIMARY KEY,
admin_id TEXT NOT NULL,
admin_name TEXT,
admin_role TEXT,
action TEXT NOT NULL, -- 'create' | 'read' | 'update' | 'delete' | 'approve' | 'export' | 'login' | 'logout'
resource_type TEXT NOT NULL, -- 'user' | 'content' | 'system' | 'subscription' | 'announcement' | 'config'
resource_id TEXT, -- 被操作资源的 ID
before_state TEXT, -- JSON: 操作前的状态
after_state TEXT, -- JSON: 操作后的状态
changes TEXT, -- JSON: 变更字段摘要
ip_address TEXT,
user_agent TEXT,
request_id TEXT, -- 关联请求 ID
-- 风险标记
risk_level TEXT DEFAULT 'low' CHECK(risk_level IN ('low', 'medium', 'high', 'critical')),
risk_reason TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (admin_id) REFERENCES admin_users(id)
);
CREATE INDEX idx_admin_audit_logs_admin ON admin_audit_logs(admin_id);
CREATE INDEX idx_admin_audit_logs_action ON admin_audit_logs(action, resource_type);
CREATE INDEX idx_admin_audit_logs_time ON admin_audit_logs(created_at);
CREATE INDEX idx_admin_audit_logs_risk ON admin_audit_logs(risk_level);
-- ==================== 系统公告 ====================
CREATE TABLE announcements (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT DEFAULT 'info' CHECK(type IN ('info', 'warning', 'critical', 'feature', 'maintenance')),
-- 目标受众
target_roles TEXT, -- JSON: AdminRole[] 或 null 表示全部
target_tenants TEXT, -- JSON: string[] 或 null 表示全部
-- 发布控制
status TEXT DEFAULT 'draft' CHECK(status IN ('draft', 'published', 'archived')),
scheduled_at TIMESTAMP, -- 计划发布时间
published_at TIMESTAMP,
expires_at TIMESTAMP, -- 过期时间
-- 统计
view_count INTEGER DEFAULT 0,
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (created_by) REFERENCES admin_users(id)
);
-- ==================== Feature Flags ====================
CREATE TABLE feature_flags (
id TEXT PRIMARY KEY,
key TEXT NOT NULL UNIQUE, -- 功能标识符
name TEXT NOT NULL, -- 显示名称
description TEXT,
-- 状态
enabled BOOLEAN DEFAULT false,
-- 目标范围
scope_type TEXT DEFAULT 'global' CHECK(scope_type IN ('global', 'tenant', 'user', 'percentage')),
scope_value TEXT, -- 具体值:租户 ID / 用户 ID / 百分比
-- 灰度控制
rollout_percentage INTEGER DEFAULT 0 CHECK(rollout_percentage BETWEEN 0 AND 100),
-- 元数据
category TEXT, -- 'core' | 'experimental' | 'beta' | 'deprecated'
depends_on TEXT, -- JSON: string[] 依赖的其他 flag
created_by TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (created_by) REFERENCES admin_users(id)
);
-- ==================== 系统配置 ====================
CREATE TABLE system_configs (
id TEXT PRIMARY KEY,
key TEXT NOT NULL UNIQUE,
value TEXT NOT NULL,
value_type TEXT DEFAULT 'string' CHECK(value_type IN ('string', 'number', 'boolean', 'json')),
description TEXT,
-- 可变性
editable BOOLEAN DEFAULT true,
requires_restart BOOLEAN DEFAULT false,
-- 作用域
scope TEXT DEFAULT 'global' CHECK(scope IN ('global', 'tenant', 'user')),
tenant_id TEXT,
-- 审计
updated_by TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (updated_by) REFERENCES admin_users(id)
);
-- ==================== 用户举报 ====================
CREATE TABLE user_reports (
id TEXT PRIMARY KEY,
reporter_id TEXT, -- 举报人(用户)
reported_id TEXT, -- 被举报对象 ID
reported_type TEXT CHECK(reported_type IN ('user', 'content', 'comment', 'message')),
reason TEXT NOT NULL, -- 举报原因
category TEXT CHECK(category IN ('spam', 'abuse', 'illegal', 'copyright', 'privacy', 'other')),
evidence TEXT, -- JSON: 证据截图/链接
-- 处理状态
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'investigating', 'resolved', 'dismissed')),
resolution TEXT, -- 处理结果
resolved_by TEXT, -- 处理人
resolved_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (resolved_by) REFERENCES admin_users(id)
);
CREATE INDEX idx_user_reports_status ON user_reports(status);
CREATE INDEX idx_user_reports_type ON user_reports(reported_type);
-- ==================== 客服工单 ====================
CREATE TABLE support_tickets (
id TEXT PRIMARY KEY,
ticket_number TEXT NOT NULL UNIQUE, -- 工单编号 TICKET-20260701-0001
user_id TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
category TEXT CHECK(category IN ('billing', 'technical', 'feature_request', 'bug', 'account', 'other')),
priority TEXT DEFAULT 'medium' CHECK(priority IN ('low', 'medium', 'high', 'critical')),
-- 状态
status TEXT DEFAULT 'open' CHECK(status IN ('open', 'in_progress', 'waiting_user', 'resolved', 'closed', 'escalated')),
-- 分配
assigned_to TEXT, -- 分配的客服
-- 时间戳
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
resolved_at TIMESTAMP,
-- 满意度
satisfaction_rating INTEGER, -- 1-5
satisfaction_comment TEXT,
FOREIGN KEY (assigned_to) REFERENCES admin_users(id)
);
CREATE INDEX idx_support_tickets_status ON support_tickets(status);
CREATE INDEX idx_support_tickets_assigned ON support_tickets(assigned_to);
CREATE INDEX idx_support_tickets_user ON support_tickets(user_id);
-- ==================== 工单回复 ====================
CREATE TABLE ticket_replies (
id TEXT PRIMARY KEY,
ticket_id TEXT NOT NULL,
author_id TEXT NOT NULL, -- 可以是用户或管理员
author_type TEXT CHECK(author_type IN ('user', 'admin')),
content TEXT NOT NULL,
is_internal BOOLEAN DEFAULT false, -- 是否内部备注(用户不可见)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id)
);
-- ==================== 租户表(多租户) ====================
CREATE TABLE tenants (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
slug TEXT NOT NULL UNIQUE, -- 唯一标识
-- 配置
config TEXT, -- JSON: 租户级配置
-- 资源配额
max_users INTEGER,
max_storage_gb INTEGER,
max_api_calls_per_month INTEGER,
-- 状态
status TEXT DEFAULT 'active' CHECK(status IN ('active', 'suspended', 'trial', 'expired')),
trial_ends_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户表扩展:增加租户关联
ALTER TABLE users ADD COLUMN tenant_id TEXT;
ALTER TABLE users ADD COLUMN is_tenant_admin BOOLEAN DEFAULT false;
CREATE INDEX idx_users_tenant ON users(tenant_id);4. Admin API 设计
4.1 认证与授权
typescript
// ==================== 管理员登录 ====================
POST /api/admin/auth/login
Request: {
email: string;
password: string;
mfaCode?: string; // 如果启用 MFA
}
Response: {
accessToken: string; // JWT,15 分钟
refreshToken: string; // 7 天
admin: {
id: string;
name: string;
email: string;
role: string;
permissions: Permission[];
};
}
// ==================== 刷新 Token ====================
POST /api/admin/auth/refresh
Request: { refreshToken: string }
Response: { accessToken: string }
// ==================== 登出 ====================
POST /api/admin/auth/logout
Headers: Authorization: Bearer {accessToken}
Response: { success: true }
// ==================== 获取当前管理员信息 ====================
GET /api/admin/auth/me
Response: {
id: string;
name: string;
email: string;
role: string;
permissions: Permission[];
lastLoginAt: Date;
mfaEnabled: boolean;
}
// ==================== 验证权限(中间件) ====================
// 使用方式:在路由前验证
// GET /api/admin/users 需要 admin:users:read 权限
// 如果没有权限,返回 4034.2 用户管理
typescript
// ==================== 用户列表 ====================
GET /api/admin/users
Query: {
page: number; // 默认 1
limit: number; // 默认 20
search?: string; // 搜索邮箱/名称
status?: 'active' | 'inactive' | 'suspended' | 'pending';
role?: 'free' | 'pro' | 'team' | 'enterprise';
tenantId?: string; // 多租户筛选
dateRange?: [string, string]; // 注册时间范围
sortBy?: 'createdAt' | 'lastLoginAt' | 'subscriptionTier' | 'storageUsed';
sortOrder?: 'asc' | 'desc';
}
Response: {
users: AdminUserView[];
pagination: { total: number; page: number; pages: number };
summary: {
totalUsers: number;
activeUsers: number;
newUsersToday: number;
newUsersThisWeek: number;
newUsersThisMonth: number;
avgStorageUsed: number;
};
}
interface AdminUserView {
id: string;
email: string;
name: string;
avatar?: string;
status: string;
role: string;
subscriptionTier: string;
subscriptionStatus: string;
subscriptionExpiresAt: Date;
storageUsed: number; // 字节
storageLimit: number;
lastLoginAt: Date;
lastLoginIp: string;
createdAt: Date;
tenantId?: string;
// 统计
stats: {
totalNotes: number;
totalClips: number;
totalCapsules: number;
totalKnowledgeUnits: number;
apiCallsThisMonth: number;
};
}
// ==================== 用户详情 ====================
GET /api/admin/users/:id
Response: {
user: AdminUserView;
loginHistory: LoginRecord[];
activityTimeline: ActivityRecord[];
subscriptionHistory: SubscriptionRecord[];
supportTickets: TicketSummary[];
}
// ==================== 更新用户状态 ====================
PATCH /api/admin/users/:id
Request: {
status?: 'active' | 'inactive' | 'suspended';
subscriptionTier?: 'free' | 'pro' | 'team' | 'enterprise';
storageLimit?: number;
notes?: string; // 管理员备注
}
Response: { user: AdminUserView }
// ==================== 批量操作用户 ====================
POST /api/admin/users/batch
Request: {
action: 'suspend' | 'activate' | 'delete' | 'upgrade' | 'downgrade' | 'export';
userIds: string[];
reason: string; // 操作原因(审计用)
data?: any; // 额外参数
}
Response: {
success: boolean;
processed: number;
failed: number;
failures: { userId: string; reason: string }[];
}
// ==================== 用户登录历史 ====================
GET /api/admin/users/:id/login-history
Query: { page: number; limit: number; startDate?: string; endDate?: string }
Response: {
records: LoginRecord[];
pagination: Pagination;
summary: {
totalLogins: number;
uniqueIps: number;
failedAttempts: number;
};
}
// ==================== 用户数据导出 ====================
POST /api/admin/users/:id/export
Request: {
format: 'json' | 'csv' | 'pdf';
dataTypes: ('profile' | 'notes' | 'clips' | 'capsules' | 'knowledge' | 'activity' | 'all')[];
dateRange?: [string, string];
}
Response: {
exportId: string;
status: 'queued' | 'processing' | 'completed' | 'failed';
downloadUrl?: string; // 完成后提供
expiresAt?: Date;
}
// SSE: GET /api/admin/users/:id/export/:exportId/progress4.3 数据统计
typescript
// ==================== 全局仪表盘数据 ====================
GET /api/admin/stats/dashboard
Response: {
// 用户指标
users: {
total: number;
active: number; // 30 天内有活跃
newToday: number;
newThisWeek: number;
newThisMonth: number;
churnRate: number; // 月流失率
retention: { // 留存率
day1: number;
day7: number;
day30: number;
day90: number;
};
byTier: Record<string, number>; // 按套餐分布
byCountry: Record<string, number>; // 按国家分布
};
// 活跃度指标
activity: {
dau: number; // 日活跃用户
mau: number; // 月活跃用户
avgSessionDuration: number; // 平均会话时长(秒)
avgSessionsPerDay: number; // 日均会话数
// 功能使用
featureUsage: {
notes: { users: number; count: number };
clips: { users: number; count: number };
capsules: { users: number; count: number };
graph: { users: number; count: number };
attention: { users: number; count: number };
llm: { users: number; tokens: number };
};
};
// 存储指标
storage: {
totalUsed: number; // 总使用字节
totalLimit: number;
avgPerUser: number;
byType: {
notes: number;
clips: number;
attachments: number;
vectors: number;
};
};
// 收入指标
revenue: {
mrr: number; // 月度经常性收入
arr: number; // 年度经常性收入
thisMonth: number;
lastMonth: number;
growthRate: number;
byTier: Record<string, number>;
byPaymentMethod: Record<string, number>;
};
// 系统健康
system: {
apiUptime: number; // API 可用率
avgResponseTime: number; // 平均响应时间
errorRate: number; // 错误率
queueDepth: number; // 任务队列深度
activeSyncs: number; // 活跃同步数
};
}
// ==================== 时间序列数据 ====================
GET /api/admin/stats/timeseries
Query: {
metric: 'dau' | 'mau' | 'new_users' | 'revenue' | 'api_calls' | 'storage' | 'retention';
period: 'hour' | 'day' | 'week' | 'month';
startDate: string;
endDate: string;
granularity?: 'hour' | 'day' | 'week' | 'month';
tenantId?: string;
}
Response: {
data: { timestamp: Date; value: number; label?: string }[];
summary: {
total: number;
avg: number;
max: number;
min: number;
change: number; // 环比变化
};
}
// ==================== 用户漏斗分析 ====================
GET /api/admin/stats/funnel
Query: {
funnelType: 'onboarding' | 'subscription' | 'feature_adoption';
dateRange: [string, string];
}
Response: {
steps: {
name: string;
users: number;
conversionRate: number; // 到下一步的转化率
dropOffRate: number; // 流失率
avgTime: number; // 平均停留时间(秒)
}[];
totalConversion: number; // 总转化率
}
// ==================== 热门内容/搜索 ====================
GET /api/admin/stats/popular
Query: {
type: 'searches' | 'clips' | 'notes' | 'tags' | 'domains' | 'llm_queries';
period: 'day' | 'week' | 'month';
limit: number;
}
Response: {
items: { name: string; count: number; trend: 'up' | 'down' | 'stable' }[];
}4.4 内容管理
typescript
// ==================== 内容审核列表 ====================
GET /api/admin/content
Query: {
page: number;
limit: number;
type?: 'note' | 'clip' | 'rss_item' | 'knowledge_unit' | 'capsule';
status?: 'active' | 'flagged' | 'under_review' | 'removed' | 'appealed';
brainSide?: 'personal' | 'network';
flagReason?: 'spam' | 'abuse' | 'illegal' | 'copyright' | 'privacy' | 'ai_generated' | 'user_reported';
dateRange?: [string, string];
search?: string;
sortBy?: 'flaggedAt' | 'createdAt' | 'reportCount';
}
Response: {
items: ContentItem[];
pagination: Pagination;
summary: {
totalFlagged: number;
pendingReview: number;
removedToday: number;
};
}
interface ContentItem {
id: string;
type: string;
brainSide: BrainSide;
title: string;
excerpt: string;
author: {
id: string;
name: string;
email: string;
status: string;
};
status: string;
flaggedAt: Date;
flagReason: string;
flagDetails: string;
reportCount: number;
// AI 检测
aiDetected: {
spamScore: number;
toxicityScore: number;
copyrightRisk: number;
isAiGenerated: boolean;
};
createdAt: Date;
}
// ==================== 内容详情审核 ====================
GET /api/admin/content/:id
Response: {
item: ContentItem;
fullContent: string;
reports: UserReport[];
auditHistory: AuditAction[];
similarContent: ContentItem[]; // AI 检测到的相似内容
}
// ==================== 审核操作 ====================
POST /api/admin/content/:id/audit
Request: {
action: 'approve' | 'remove' | 'shadowban' | 'warn_author' | 'escalate';
reason: string; // 审核原因
internalNotes?: string; // 内部备注
notifyUser?: boolean; // 是否通知用户
}
Response: {
success: boolean;
item: ContentItem;
}
// ==================== 批量审核 ====================
POST /api/admin/content/batch-audit
Request: {
contentIds: string[];
action: 'approve' | 'remove' | 'shadowban';
reason: string;
}
// ==================== 举报列表 ====================
GET /api/admin/reports
Query: {
page: number;
limit: number;
status?: 'pending' | 'investigating' | 'resolved' | 'dismissed';
category?: string;
priority?: 'low' | 'medium' | 'high' | 'critical';
assignedTo?: string; // 分配给哪个管理员
}
Response: {
reports: UserReport[];
pagination: Pagination;
summary: {
pending: number;
highPriority: number;
avgResolutionTime: number; // 平均处理时间(小时)
};
}
// ==================== 处理举报 ====================
POST /api/admin/reports/:id/resolve
Request: {
resolution: 'violation_found' | 'no_violation' | 'partial_violation' | 'needs_more_info';
action: 'remove_content' | 'warn_user' | 'suspend_user' | 'dismiss' | 'escalate';
reason: string;
notifyReporter: boolean;
}4.5 系统管理
typescript
// ==================== 系统配置列表 ====================
GET /api/admin/system/configs
Query: { category?: string; editable?: boolean }
Response: {
configs: SystemConfig[];
}
interface SystemConfig {
id: string;
key: string;
name: string;
value: string;
valueType: 'string' | 'number' | 'boolean' | 'json';
description: string;
editable: boolean;
requiresRestart: boolean;
scope: string;
category: string;
updatedBy: string;
updatedAt: Date;
}
// ==================== 更新系统配置 ====================
PUT /api/admin/system/configs/:id
Request: {
value: string;
reason: string; // 变更原因(审计)
}
Response: { config: SystemConfig }
// ==================== Feature Flags 列表 ====================
GET /api/admin/system/feature-flags
Response: {
flags: FeatureFlag[];
}
interface FeatureFlag {
id: string;
key: string;
name: string;
description: string;
enabled: boolean;
scopeType: string;
scopeValue?: string;
rolloutPercentage: number;
category: string;
dependsOn: string[];
createdBy: string;
createdAt: Date;
}
// ==================== 创建/更新 Feature Flag ====================
POST /api/admin/system/feature-flags
Request: {
key: string;
name: string;
description: string;
enabled: boolean;
scopeType: string;
scopeValue?: string;
rolloutPercentage: number;
category: string;
}
// ==================== 系统健康检查 ====================
GET /api/admin/system/health
Response: {
status: 'healthy' | 'degraded' | 'unhealthy';
checks: {
database: { status: string; latency: number };
redis: { status: string; latency: number };
chromadb: { status: string; latency: number };
ollama: { status: string; latency: number; models: string[] };
disk: { status: string; used: number; total: number };
memory: { status: string; used: number; total: number };
};
uptime: number; // 秒
version: string;
lastRestart: Date;
}
// ==================== 系统公告管理 ====================
GET /api/admin/system/announcements
Query: { status?: string; page: number; limit: number }
Response: { announcements: Announcement[]; pagination: Pagination }
POST /api/admin/system/announcements
Request: {
title: string;
content: string;
type: 'info' | 'warning' | 'critical' | 'feature' | 'maintenance';
targetRoles?: string[];
targetTenants?: string[];
scheduledAt?: string;
expiresAt?: string;
}
PATCH /api/admin/system/announcements/:id
Request: { status: 'published' | 'draft' | 'archived' }
DELETE /api/admin/system/announcements/:id4.6 订阅计费
typescript
// ==================== 订单列表 ====================
GET /api/admin/billing/orders
Query: {
page: number;
limit: number;
status?: 'pending' | 'paid' | 'failed' | 'refunded' | 'disputed';
paymentMethod?: 'stripe' | 'alipay' | 'wechat' | 'apple_pay' | 'bank_transfer';
tier?: 'free' | 'pro' | 'team' | 'enterprise';
dateRange?: [string, string];
search?: string; // 用户邮箱/订单号
}
Response: {
orders: Order[];
pagination: Pagination;
summary: {
totalRevenue: number;
totalRefunds: number;
netRevenue: number;
totalOrders: number;
avgOrderValue: number;
byPaymentMethod: Record<string, number>;
byTier: Record<string, number>;
};
}
interface Order {
id: string;
orderNumber: string; // ORD-20260701-0001
userId: string;
userName: string;
userEmail: string;
tier: string;
period: 'monthly' | 'yearly' | 'lifetime';
amount: number;
currency: string;
status: string;
paymentMethod: string;
paymentProvider: string;
transactionId: string;
paidAt: Date;
expiresAt: Date;
refundedAt: Date;
refundAmount: number;
createdAt: Date;
}
// ==================== 订单详情 ====================
GET /api/admin/billing/orders/:id
Response: {
order: Order;
invoiceUrl?: string;
refundHistory: RefundRecord[];
userSubscriptionHistory: Order[];
}
// ==================== 退款处理 ====================
POST /api/admin/billing/orders/:id/refund
Request: {
amount: number; // 退款金额(部分或全额)
reason: string;
category: 'customer_request' | 'billing_error' | 'fraud' | 'service_issue' | 'duplicate';
notifyUser: boolean;
}
Response: {
refundId: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
estimatedCompletion: Date;
}
// ==================== 订阅管理 ====================
GET /api/admin/billing/subscriptions
Query: {
page: number;
limit: number;
status?: 'active' | 'cancelled' | 'expired' | 'past_due' | 'trialing';
tier?: string;
autoRenew?: boolean;
dateRange?: [string, string];
}
Response: {
subscriptions: Subscription[];
pagination: Pagination;
summary: {
active: number;
trialing: number;
pastDue: number;
churning: number; // 即将流失(7天内到期且不自动续费)
mrr: number;
arr: number;
};
}
interface Subscription {
id: string;
userId: string;
userName: string;
userEmail: string;
tier: string;
status: string;
period: string;
currentPeriodStart: Date;
currentPeriodEnd: Date;
autoRenew: boolean;
cancelAtPeriodEnd: boolean;
paymentMethod: string;
createdAt: Date;
cancelledAt: Date;
}
// ==================== 更新订阅(手动干预) ====================
PATCH /api/admin/billing/subscriptions/:id
Request: {
tier?: string;
status?: 'active' | 'cancelled' | 'paused';
extendDays?: number; // 延长天数(补偿)
reason: string; // 操作原因
}
// ==================== 优惠券/促销码管理 ====================
GET /api/admin/billing/promotions
Query: { status?: string; page: number; limit: number }
Response: { promotions: Promotion[] }
POST /api/admin/billing/promotions
Request: {
code: string; // 优惠码
type: 'percentage' | 'fixed' | 'trial_extension';
value: number; // 折扣百分比或金额
maxUses: number; // 最大使用次数
maxUsesPerUser: number;
applicableTiers: string[];
startDate: string;
endDate: string;
description: string;
}
// ==================== 收入报告 ====================
GET /api/admin/billing/revenue-report
Query: {
period: 'daily' | 'weekly' | 'monthly' | 'yearly';
startDate: string;
endDate: string;
groupBy?: 'tier' | 'payment_method' | 'country' | 'referral';
}
Response: {
report: RevenueReport;
downloadUrl: string; // 可下载 CSV/PDF
}4.7 日志审计
typescript
// ==================== 操作日志列表 ====================
GET /api/admin/logs/audit
Query: {
page: number;
limit: number;
adminId?: string; // 按管理员筛选
action?: string; // 'create' | 'read' | 'update' | 'delete' | 'approve'
resourceType?: string; // 'user' | 'content' | 'system' | 'subscription'
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
dateRange?: [string, string];
search?: string;
}
Response: {
logs: AuditLog[];
pagination: Pagination;
summary: {
totalActions: number;
byAdmin: Record<string, number>;
byAction: Record<string, number>;
highRiskCount: number;
};
}
interface AuditLog {
id: string;
adminId: string;
adminName: string;
adminRole: string;
action: string;
resourceType: string;
resourceId: string;
beforeState: any;
afterState: any;
changes: string[];
ipAddress: string;
userAgent: string;
requestId: string;
riskLevel: string;
riskReason: string;
createdAt: Date;
}
// ==================== 安全事件列表 ====================
GET /api/admin/logs/security
Query: {
page: number;
limit: number;
severity?: 'info' | 'warning' | 'high' | 'critical';
type?: 'failed_login' | 'mfa_bypass' | 'privilege_escalation' | 'unusual_access' | 'data_export' | 'config_change';
dateRange?: [string, string];
}
Response: {
events: SecurityEvent[];
pagination: Pagination;
summary: {
totalEvents: number;
criticalCount: number;
unresolvedCount: number;
};
}
interface SecurityEvent {
id: string;
type: string;
severity: string;
description: string;
details: any;
affectedResource: string;
affectedUserId?: string;
detectedAt: Date;
resolvedAt: Date;
resolvedBy: string;
resolution: string;
// 关联
relatedLogs: string[];
relatedAlerts: string[];
}
// ==================== 日志导出 ====================
POST /api/admin/logs/export
Request: {
type: 'audit' | 'security' | 'login' | 'all';
format: 'csv' | 'json' | 'ndjson';
dateRange: [string, string];
filters: any;
}
Response: {
exportId: string;
status: string;
downloadUrl?: string;
expiresAt: Date;
}4.8 客服工单
typescript
// ==================== 工单列表 ====================
GET /api/admin/support/tickets
Query: {
page: number;
limit: number;
status?: 'open' | 'in_progress' | 'waiting_user' | 'resolved' | 'closed' | 'escalated';
priority?: 'low' | 'medium' | 'high' | 'critical';
category?: string;
assignedTo?: string; // 分配给哪个管理员
unassigned?: boolean; // 只看未分配的
search?: string;
}
Response: {
tickets: SupportTicket[];
pagination: Pagination;
summary: {
open: number;
inProgress: number;
waitingUser: number;
resolvedToday: number;
avgResolutionTime: number; // 平均解决时间(小时)
avgResponseTime: number; // 平均首次响应时间(分钟)
};
}
interface SupportTicket {
id: string;
ticketNumber: string;
userId: string;
userName: string;
userEmail: string;
title: string;
description: string;
category: string;
priority: string;
status: string;
assignedTo: {
id: string;
name: string;
};
createdAt: Date;
updatedAt: Date;
replyCount: number;
lastReplyAt: Date;
lastReplyBy: string;
satisfactionRating?: number;
}
// ==================== 工单详情 ====================
GET /api/admin/support/tickets/:id
Response: {
ticket: SupportTicket;
replies: TicketReply[];
userHistory: SupportTicket[];
relatedLogs: AdminAuditLog[];
}
// ==================== 回复工单 ====================
POST /api/admin/support/tickets/:id/replies
Request: {
content: string;
isInternal: boolean; // 是否内部备注
statusChange?: 'in_progress' | 'waiting_user' | 'resolved' | 'escalated';
assignTo?: string; // 转分配给
}
Response: { reply: TicketReply; ticket: SupportTicket }
// ==================== 工单统计 ====================
GET /api/admin/support/stats
Query: { dateRange: [string, string] }
Response: {
overview: {
totalTickets: number;
resolved: number;
resolutionRate: number;
avgResponseTime: number;
avgResolutionTime: number;
customerSatisfaction: number; // 平均满意度 1-5
};
byCategory: Record<string, number>;
byPriority: Record<string, number>;
byAgent: Record<string, { tickets: number; resolved: number; avgTime: number; satisfaction: number }>;
dailyVolume: { date: string; created: number; resolved: number }[];
}5. Admin Dashboard 前端设计
5.1 整体布局
┌─────────────────────────────────────────────────────────────────┐
│ 🛡️ Admin Dashboard [🔔] [👤 Admin] [Logout]│
│ ═══════════════════════════════════════════════════════════════ │
│ │
│ ┌────────┬──────────────────────────────────────────────────┐ │
│ │ │ 顶部面包屑 + 页面标题 │ │
│ │ Admin │ Dashboard / Users / User Detail │ │
│ │ 侧边栏 │ │ │
│ │ │ ┌──────────────────────────────────────────────┐ │ │
│ │ 📊 │ │ │ │ │
│ │ Dashboard│ │ 主内容区域 │ │ │
│ │ │ │ │ │ │
│ │ 👤 │ │ │ │ │
│ │ Users │ │ │ │ │
│ │ │ │ │ │ │
│ │ 📰 │ │ │ │ │
│ │ Content│ │ │ │ │
│ │ │ │ │ │ │
│ │ 📊 │ │ │ │ │
│ │ Stats │ │ │ │ │
│ │ │ │ │ │ │
│ │ 💰 │ │ │ │ │
│ │ Billing│ │ │ │ │
│ │ │ │ │ │ │
│ │ ⚙️ │ │ │ │ │
│ │ System│ │ │ │ │
│ │ │ │ │ │ │
│ │ 📝 │ │ │ │ │
│ │ Logs │ │ │ │ │
│ │ │ │ │ │ │
│ │ 🎧 │ │ │ │ │
│ │ Support│ │ │ │ │
│ │ │ │ │ │ │
│ └────────┘ └──────────────────────────────────────────────┘ │ │
│ │
│ [⚙️ 设置] [📖 文档] [🐛 反馈] │
│ │
└─────────────────────────────────────────────────────────────────┘5.2 侧边栏菜单(权限感知)
typescript
const ADMIN_MENU_ITEMS = [
{
id: 'dashboard',
icon: '📊',
label: '仪表盘',
path: '/admin',
requiredPermission: { resource: 'stats', action: 'read' },
badge: null
},
{
id: 'users',
icon: '👤',
label: '用户管理',
path: '/admin/users',
requiredPermission: { resource: 'users', action: 'read' },
badge: 'new_users_count', // 动态徽章
children: [
{ id: 'users-list', label: '用户列表', path: '/admin/users' },
{ id: 'users-activity', label: '活跃分析', path: '/admin/users/activity' },
{ id: 'users-segment', label: '用户分群', path: '/admin/users/segments' },
]
},
{
id: 'content',
icon: '📰',
label: '内容管理',
path: '/admin/content',
requiredPermission: { resource: 'content', action: 'read' },
badge: 'pending_reviews',
children: [
{ id: 'content-review', label: '内容审核', path: '/admin/content' },
{ id: 'content-reports', label: '举报处理', path: '/admin/content/reports' },
{ id: 'content-stats', label: '内容统计', path: '/admin/content/stats' },
]
},
{
id: 'stats',
icon: '📈',
label: '数据统计',
path: '/admin/stats',
requiredPermission: { resource: 'stats', action: 'read' },
children: [
{ id: 'stats-overview', label: '概览', path: '/admin/stats' },
{ id: 'stats-engagement', label: '活跃度', path: '/admin/stats/engagement' },
{ id: 'stats-retention', label: '留存', path: '/admin/stats/retention' },
{ id: 'stats-revenue', label: '收入', path: '/admin/stats/revenue' },
{ id: 'stats-llm', label: 'LLM 用量', path: '/admin/stats/llm' },
]
},
{
id: 'billing',
icon: '💰',
label: '订阅计费',
path: '/admin/billing',
requiredPermission: { resource: 'subscriptions', action: 'read' },
children: [
{ id: 'billing-orders', label: '订单', path: '/admin/billing/orders' },
{ id: 'billing-subscriptions', label: '订阅', path: '/admin/billing/subscriptions' },
{ id: 'billing-refunds', label: '退款', path: '/admin/billing/refunds' },
{ id: 'billing-promotions', label: '促销', path: '/admin/billing/promotions' },
{ id: 'billing-revenue', label: '收入报告', path: '/admin/billing/revenue' },
]
},
{
id: 'system',
icon: '⚙️',
label: '系统管理',
path: '/admin/system',
requiredPermission: { resource: 'system', action: 'read' },
children: [
{ id: 'system-config', label: '系统配置', path: '/admin/system/config' },
{ id: 'system-flags', label: 'Feature Flags', path: '/admin/system/flags' },
{ id: 'system-announcements', label: '公告', path: '/admin/system/announcements' },
{ id: 'system-health', label: '健康监控', path: '/admin/system/health' },
{ id: 'system-admins', label: '管理员', path: '/admin/system/admins' },
]
},
{
id: 'logs',
icon: '📝',
label: '日志审计',
path: '/admin/logs',
requiredPermission: { resource: 'logs', action: 'read' },
children: [
{ id: 'logs-audit', label: '操作日志', path: '/admin/logs/audit' },
{ id: 'logs-security', label: '安全事件', path: '/admin/logs/security' },
{ id: 'logs-login', label: '登录日志', path: '/admin/logs/login' },
]
},
{
id: 'support',
icon: '🎧',
label: '客服工单',
path: '/admin/support',
requiredPermission: { resource: 'tickets', action: 'read' },
badge: 'open_tickets',
children: [
{ id: 'support-tickets', label: '工单列表', path: '/admin/support' },
{ id: 'support-stats', label: '客服统计', path: '/admin/support/stats' },
]
}
];
// 权限过滤
function filterMenuByPermissions(menuItems: MenuItem[], permissions: Permission[]): MenuItem[] {
return menuItems.filter(item => {
const hasPermission = checkPermission(permissions, item.requiredPermission);
if (!hasPermission) return false;
if (item.children) {
item.children = filterMenuByPermissions(item.children, permissions);
}
return true;
});
}5.3 Dashboard 页面
┌─────────────────────────────────────────────────────────────────┐
│ 📊 仪表盘 │
│ ═══════════════════════════════════════════════════════════════ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐│
│ │ 👤 总用户 │ │ 📈 日活跃 │ │ 💰 月收入 │ │ 🟢 系统 ││
│ │ │ │ │ │ │ │ ││
│ │ 12,456 │ │ 3,892 │ │ ¥45,678 │ │ 健康 ││
│ │ ↑ 12% │ │ ↑ 5% │ │ ↑ 8% │ │ 99.9% ││
│ │ vs 上月 │ │ vs 昨日 │ │ vs 上月 │ │ ││
│ │ [查看详情] │ │ [查看详情] │ │ [查看详情] │ │ [查看] ││
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────┘│
│ │
│ ┌──────────────────────────────────────────────────────────────┐│
│ │ 📈 用户增长趋势(近30天) ││
│ │ [折线图:DAU + 新用户 + 活跃用户] ││
│ │ ││
│ │ 今日: DAU 3,892 | 新用户 156 | 活跃用户 67% ││
│ │ 本周: 平均 DAU 3,654 | 周留存 45% ││
│ │ 本月: 目标 4,000 DAU | 当前进度 97% ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
│ ┌──────────────────────────┐ ┌──────────────────────────────┐ │
│ │ 📊 套餐分布 │ │ 🌍 地域分布 │ │
│ │ [饼图] │ │ [地图热力图] │ │
│ │ │ │ │ │
│ │ Free: 8,234 (66%) │ │ 中国: 45% │ │
│ │ Pro: 3,456 (28%) │ │ 美国: 23% │ │
│ │ Team: 567 (4%) │ │ 日本: 8% │ │
│ │ Enterprise: 199 (2%) │ │ 其他: 24% │ │
│ │ [查看详情] │ │ [查看详情] │ │
│ └──────────────────────────┘ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────────┐│
│ │ ⚠️ 需要关注 ││
│ │ ││
│ │ • 3 个用户待审核(注册超过24小时未激活) ││
│ │ • 7 条内容举报待处理(其中 2 条高优先级) ││
│ │ • 5 个订阅即将到期(3天内)且未开启自动续费 ││
│ │ • 1 个安全事件:异常登录尝试(IP: 192.168.x.x) ││
│ │ • 系统磁盘使用率达到 85%(建议扩容) ││
│ │ ││
│ │ [处理全部] [查看详情] ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
│ ┌──────────────────────────────────────────────────────────────┐│
│ │ 📈 功能使用排行(近7天) ││
│ │ ││
│ │ 1. 笔记管理 ████████████████████████████████ 78% ││
│ │ 2. 浏览器剪藏 ██████████████████████████ 65% ││
│ │ 3. LLM 对话 ██████████████████████ 52% ││
│ │ 4. 知识图谱 ████████████████ 41% ││
│ │ 5. 时间胶囊 ████████████ 32% ││
│ │ 6. 注意力管家 █████████ 25% ││
│ │ 7. RSS 聚合 ██████ 18% ││
│ │ 8. 反脆弱库 ████ 15% ││
│ │ ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
│ ┌──────────────────────────────────────────────────────────────┐│
│ │ 💰 收入趋势(近6个月) ││
│ │ [柱状图:MRR + 新订 + 续订 + 退款] ││
│ │ ││
│ │ MRR: ¥45,678 | ARR: ¥548,136 | 目标达成率: 87% ││
│ │ 本月新订: 156 | 续订: 89% | 退款: 3 | 退款率: 0.8% ││
│ └──────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘5.4 用户管理页面
┌─────────────────────────────────────────────────────────────────┐
│ 👤 用户管理 │
│ ═══════════════════════════════════════════════════════════════ │
│ │
│ 筛选: [搜索邮箱/名称] [状态 ▼] [套餐 ▼] [注册时间 ▼] [导出] │
│ │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ [☑] 用户ID 邮箱 名称 套餐 状态 注册 操作 ││
│ │ ─────────────────────────────────────────────────────────── ││
│ │ ☑ u_001 zhang@example.com 张三 Pro ✓ 激活 2026-06 │ [查看] [编辑] ││
│ │ ☑ u_002 li@example.com 李四 Free ✓ 激活 2026-06 │ [查看] [编辑] ││
│ │ ☑ u_003 wang@example.com 王五 Team ⚠ 欠费 2026-05 │ [查看] [编辑] ││
│ │ ☑ u_004 zhao@example.com 赵六 Pro 🚫 封禁 2026-04 │ [查看] [编辑] ││
│ │ ☑ u_005 sun@example.com 孙七 Free ⏳ 待审 2026-07 │ [查看] [编辑] ││
│ │ ─────────────────────────────────────────────────────────── ││
│ │ 全选 [批量激活] [批量封禁] [批量升级] [导出选中] ││
│ │ 共 12,456 用户 | 第 1/623 页 ││
│ └────────────────────────────────────────────────────────────┘│
│ │
│ 用户详情弹窗(点击"查看"): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 👤 张三 (zhang@example.com) │ │
│ │ ───────────────────────────────────────────────────────── │ │
│ │ 状态: ✓ 激活 套餐: Pro 到期: 2027-07-01 │ │
│ │ 注册: 2026-06-15 最后登录: 2小时前 (IP: 123.45.x.x) │ │
│ │ MFA: 已启用 存储: 1.2GB / 5GB │ │
│ │ ───────────────────────────────────────────────────────── │ │
│ │ 统计: 笔记 245 | 胶囊 12 | 剪藏 89 | 知识单元 456 │ │
│ │ API 调用: 本月 12,345 次 (限额 50,000) │ │
│ │ ───────────────────────────────────────────────────────── │ │
│ │ [编辑套餐] [重置密码] [发送通知] [导出数据] [封禁账户] │ │
│ │ [查看登录历史] [查看工单] [查看操作日志] │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘5.5 内容审核页面
┌─────────────────────────────────────────────────────────────────┐
│ 📰 内容审核 │
│ ═══════════════════════════════════════════════════════════════ │
│ │
│ 筛选: [状态 ▼] [类型 ▼] [标记原因 ▼] [AI风险 ▼] [日期 ▼] [搜索] │
│ │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ [☑] 内容ID 类型 标题/摘要 用户 状态 标记 操作 ││
│ │ ─────────────────────────────────────────────────────────── ││
│ │ ☑ c_001 剪藏 "Rust 内存安全..." 张三 ⚠ 待审 用户举报 │ [审核] ││
│ │ ☑ c_002 笔记 "个人日记..." 李四 ⚠ 待审 AI检测 │ [审核] ││
│ │ ☑ c_003 剪藏 "某框架性能..." 王五 🚫 已移除 虚假 │ [审核] ││
│ │ ☑ c_004 知识 "投资建议..." 赵六 ⚠ 待审 用户举报 │ [审核] ││
│ │ ─────────────────────────────────────────────────────────── ││
│ │ 全选 [批量通过] [批量移除] [批量标记] ││
│ └────────────────────────────────────────────────────────────┘│
│ │
│ 审核弹窗: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 📰 内容审核: 剪藏 #c_001 │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ 来源: https://example.com/blog/rust-memory │ │
│ │ 用户: 张三 (zhang@example.com) │ │
│ │ 标记: 用户举报 (原因: "内容不准确") │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ AI 检测: │ │
│ │ • 垃圾信息: 0.12 (低) │ │
│ │ • 毒性内容: 0.05 (低) │ │
│ │ • 版权风险: 0.34 (中) │ │
│ │ • AI生成: 否 │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ 内容预览: │ │
│ │ [内容预览区域...] │ │
│ │ ─────────────────────────────────────────────────────── │ │
│ │ 操作: │ │
│ │ [✅ 通过 - 内容正常] [🚫 移除 - 违规] [⚠️ 警告 - 边缘] │ │
│ │ [👤 警告用户] [📝 内部备注] [⬆️ 升级处理] │ │
│ │ 原因: [输入审核原因...] │ │
│ │ 通知用户: ☑ 发送通知 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘5.6 系统健康监控页面
┌─────────────────────────────────────────────────────────────────┐
│ 🖥️ 系统健康监控 │
│ ═══════════════════════════════════════════════════════════════ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ 🟢 API 服务 │ │ 🟢 数据库 │ │ 🟢 向量数据库 │ │
│ │ 可用率: 99.9% │ │ 延迟: 12ms │ │ ChromaDB │ │
│ │ 平均响应: 45ms│ │ 连接池: 8/20 │ │ 延迟: 23ms │ │
│ │ [查看详情] │ │ [查看详情] │ │ [查看详情] │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │
│ │ 🟢 Redis │ │ 🟡 Ollama │ │ 🟢 磁盘存储 │ │
│ │ 内存: 45% │ │ 模型加载: 3/5 │ │ 使用: 67% │ │
│ │ 键数: 1.2M │ │ 显存: 78% │ │ 可用: 156GB │ │
│ │ [查看详情] │ │ [查看详情] │ │ [清理缓存] │ │
│ └────────────────┘ └────────────────┘ └────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ 📈 实时指标(近1小时) ││
│ │ [多线图:API QPS + 延迟 + 错误率 + 队列深度] ││
│ │ ││
│ │ 当前 QPS: 234 | 平均延迟: 45ms | 错误率: 0.02% | 队列: 3 ││
│ └────────────────────────────────────────────────────────────┘│
│ │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ ⚠️ 告警事件(最近24小时) ││
│ │ ││
│ │ 14:32 🟡 磁盘使用 85% → 已自动清理缓存 → 当前 67% ││
│ │ 12:15 🟡 Ollama 模型 llama3.1:8b 加载失败 → 已重启 → 恢复 ││
│ │ 09:45 🔴 API 延迟峰值 2.3s → 已自动扩容 → 恢复 ││
│ │ 08:20 🟡 异常登录: IP 192.168.x.x 失败 5 次 → 已临时封禁 ││
│ │ ││
│ │ [查看全部告警] [配置告警规则] ││
│ └────────────────────────────────────────────────────────────┘│
│ │
│ ┌────────────────────────────────────────────────────────────┐│
│ │ 📋 系统信息 ││
│ │ 版本: v1.2.3 (Build 20260701) ││
│ │ 运行时间: 45 天 12 小时 ││
│ │ 上次重启: 2026-05-17 02:00 ││
│ │ 部署环境: production / Docker Compose / 4 vCPU / 16GB RAM ││
│ │ [重启服务] [查看日志] [备份数据] [系统升级] ││
│ └────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────┘6. 安全与合规
6.1 管理员认证安全
typescript
// MFA 实现
interface MFAConfig {
enabled: boolean;
method: 'totp' | 'sms' | 'email' | 'hardware_key';
secret: string; // TOTP 密钥(加密存储)
backupCodes: string[]; // 备用码(一次性)
}
// 登录安全策略
interface LoginSecurityPolicy {
maxFailedAttempts: number; // 5 次失败锁定
lockoutDuration: number; // 30 分钟
passwordMinLength: number; // 12 位
passwordComplexity: 'medium' | 'high';
sessionTimeout: number; // 30 分钟无操作登出
requireMfa: boolean; // 是否强制 MFA
ipWhitelist: string[]; // 允许的管理 IP
geoRestriction: string[]; // 允许的国家
}
// 敏感操作二次确认
interface SensitiveAction {
action: 'delete_user' | 'refund_order' | 'change_config' | 'feature_flag_toggle';
requireMfa: boolean;
requireConfirmation: boolean; // 需要二次确认弹窗
requireReason: boolean; // 需要填写原因
auditLevel: 'standard' | 'high' | 'critical';
}6.2 数据脱敏
typescript
// 用户数据脱敏策略
interface DataMaskingPolicy {
// 默认脱敏规则
rules: {
email: 'partial'; // z***@example.com
phone: 'partial'; // 138****5678
password: 'hidden'; // ********
ipAddress: 'partial'; // 192.168.x.x
content: 'truncated'; // 内容截断显示
paymentInfo: 'hidden'; // 支付信息完全隐藏
};
// 按角色覆盖
roleOverrides: {
'super_admin': { email: 'full', phone: 'full' },
'support': { email: 'partial', content: 'full' },
'finance_admin': { paymentInfo: 'full' },
};
}6.3 GDPR/数据合规
typescript
// 数据合规接口
interface ComplianceAPI {
// 用户数据导出(GDPR 数据可携带权)
exportUserData(userId: string): Promise<ExportResult>;
// 用户数据删除(GDPR 被遗忘权)
deleteUserData(userId: string, reason: string): Promise<DeleteResult>;
// 数据匿名化
anonymizeUserData(userId: string): Promise<void>;
// 数据保留策略
dataRetentionPolicy: {
auditLogs: '1year'; // 审计日志保留1年
loginLogs: '6months'; // 登录日志保留6个月
deletedContent: '30days'; // 已删除内容保留30天(用于恢复)
inactiveUsers: '2years'; // 不活跃用户数据保留2年后匿名化
};
}7. 实现优先级
| 优先级 | 模块 | 功能 | 预估时间 |
|---|---|---|---|
| P0 | 认证 | 管理员登录、RBAC 权限中间件 | 2天 |
| P0 | 仪表盘 | 全局统计数据、KPI 卡片 | 2天 |
| P0 | 用户管理 | 用户列表、详情、状态管理 | 2天 |
| P1 | 内容审核 | 内容列表、审核操作、举报处理 | 2天 |
| P1 | 数据统计 | 时间序列、留存、漏斗、图表 | 3天 |
| P1 | 日志审计 | 操作日志、安全事件、导出 | 2天 |
| P2 | 订阅计费 | 订单、订阅、退款、促销 | 3天 |
| P2 | 系统管理 | 配置、Feature Flags、公告、健康监控 | 2天 |
| P2 | 客服工单 | 工单列表、回复、统计 | 2天 |
| P3 | 多租户 | 租户管理、隔离、配额 | 3天 |
| P3 | 高级安全 | MFA、IP 白名单、数据脱敏、GDPR | 2天 |
| P3 | 自动化 | 告警、自动封禁、邮件通知 | 2天 |
8. Admin 路由配置
typescript
// frontend/src/admin/AdminApp.tsx
import { Routes, Route, Navigate } from 'react-router-dom';
import AdminLayout from './layouts/AdminLayout';
import AdminLogin from './pages/AdminLogin';
import AdminDashboard from './pages/AdminDashboard';
import AdminUsers from './pages/users/AdminUsers';
import AdminUserDetail from './pages/users/AdminUserDetail';
import AdminContent from './pages/content/AdminContent';
import AdminStats from './pages/stats/AdminStats';
import AdminBilling from './pages/billing/AdminBilling';
import AdminSystem from './pages/system/AdminSystem';
import AdminLogs from './pages/logs/AdminLogs';
import AdminSupport from './pages/support/AdminSupport';
import { RequireAdminAuth } from './components/RequireAdminAuth';
import { RequirePermission } from './components/RequirePermission';
function AdminApp() {
return (
<Routes>
{/* 登录页(公开) */}
<Route path="/login" element={<AdminLogin />} />
{/* 需要认证的路由 */}
<Route element={<RequireAdminAuth />}>
<Route element={<AdminLayout />}>
{/* Dashboard - 所有管理员可见 */}
<Route path="/" element={<AdminDashboard />} />
{/* 用户管理 - 需要 users:read */}
<Route element={<RequirePermission resource="users" action="read" />}>
<Route path="/users" element={<AdminUsers />} />
<Route path="/users/:id" element={<AdminUserDetail />} />
</Route>
{/* 内容管理 - 需要 content:read */}
<Route element={<RequirePermission resource="content" action="read" />}>
<Route path="/content" element={<AdminContent />} />
</Route>
{/* 数据统计 - 需要 stats:read */}
<Route element={<RequirePermission resource="stats" action="read" />}>
<Route path="/stats" element={<AdminStats />} />
<Route path="/stats/:metric" element={<AdminStats />} />
</Route>
{/* 订阅计费 - 需要 subscriptions:read */}
<Route element={<RequirePermission resource="subscriptions" action="read" />}>
<Route path="/billing" element={<AdminBilling />} />
</Route>
{/* 系统管理 - 需要 system:read */}
<Route element={<RequirePermission resource="system" action="read" />}>
<Route path="/system" element={<AdminSystem />} />
</Route>
{/* 日志审计 - 需要 logs:read */}
<Route element={<RequirePermission resource="logs" action="read" />}>
<Route path="/logs" element={<AdminLogs />} />
</Route>
{/* 客服工单 - 需要 tickets:read */}
<Route element={<RequirePermission resource="tickets" action="read" />}>
<Route path="/support" element={<AdminSupport />} />
</Route>
</Route>
</Route>
{/* 未匹配路由 */}
<Route path="*" element={<Navigate to="/admin" />} />
</Routes>
);
}
export default AdminApp;9. 前后端整合要点
9.1 API 路由隔离
python
# backend/app/main.py
from fastapi import FastAPI
from app.api.admin.router import admin_router
from app.api.v1.router import api_router
app = FastAPI()
# 普通用户 API
app.include_router(api_router, prefix="/api/v1")
# 管理员 API(独立前缀 + 严格认证)
app.include_router(admin_router, prefix="/api/admin")9.2 管理员认证中间件
python
# backend/app/api/admin/middleware.py
from fastapi import Request, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import jwt, JWTError
from datetime import datetime
security = HTTPBearer()
async def require_admin_auth(
credentials: HTTPAuthorizationCredentials = Depends(security)
) -> AdminUser:
"""验证管理员 JWT Token"""
try:
payload = jwt.decode(
credentials.credentials,
SECRET_KEY,
algorithms=[ALGORITHM]
)
admin_id = payload.get("sub")
if not admin_id:
raise HTTPException(status_code=401, detail="Invalid token")
# 检查 Token 类型(必须是 admin)
token_type = payload.get("type")
if token_type != "admin":
raise HTTPException(status_code=403, detail="Admin access required")
# 获取管理员信息
admin = await get_admin_user(admin_id)
if not admin:
raise HTTPException(status_code=401, detail="Admin not found")
if admin.status != "active":
raise HTTPException(status_code=403, detail="Admin account inactive")
return admin
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
async def require_permission(
resource: str,
action: str
):
"""权限检查装饰器"""
async def checker(admin: AdminUser = Depends(require_admin_auth)):
if not has_permission(admin, resource, action):
raise HTTPException(
status_code=403,
detail=f"Permission denied: {resource}:{action}"
)
return admin
return checker
# 使用方式
@router.get("/users", dependencies=[Depends(require_permission("users", "read"))])
async def list_users(admin: AdminUser = Depends(require_admin_auth)):
pass9.3 审计日志自动记录
python
# backend/app/api/admin/decorators.py
from functools import wraps
import json
from datetime import datetime
class AuditLogMiddleware:
"""自动记录管理操作的装饰器"""
def __init__(self, resource_type: str, action: str, risk_level: str = "low"):
self.resource_type = resource_type
self.action = action
self.risk_level = risk_level
def __call__(self, func):
@wraps(func)
async def wrapper(*args, **kwargs):
# 获取管理员信息(从依赖注入)
admin = kwargs.get("admin")
request = kwargs.get("request")
# 记录操作前状态(如果是更新/删除)
before_state = None
if self.action in ["update", "delete"]:
resource_id = kwargs.get("id")
if resource_id:
before_state = await get_resource_state(self.resource_type, resource_id)
# 执行操作
result = await func(*args, **kwargs)
# 记录操作后状态
after_state = None
if self.action in ["create", "update"] and result:
after_state = json.loads(result.json()) if hasattr(result, "json") else result
# 计算变更
changes = []
if before_state and after_state:
changes = calculate_diff(before_state, after_state)
# 写入审计日志
await create_audit_log({
"admin_id": admin.id,
"admin_name": admin.name,
"admin_role": admin.role,
"action": self.action,
"resource_type": self.resource_type,
"resource_id": kwargs.get("id"),
"before_state": json.dumps(before_state) if before_state else None,
"after_state": json.dumps(after_state) if after_state else None,
"changes": json.dumps(changes),
"ip_address": request.client.host if request else None,
"user_agent": request.headers.get("user-agent") if request else None,
"risk_level": self.risk_level,
"created_at": datetime.utcnow()
})
return result
return wrapper
# 使用方式
@router.patch("/users/{id}")
@AuditLogMiddleware(resource_type="users", action="update", risk_level="medium")
async def update_user(
id: str,
data: UserUpdate,
admin: AdminUser = Depends(require_admin_auth),
request: Request = None
):
pass