用户管理指南

本文档介绍如何管理 Vibany 平台的用户,包括用户查看、权限管理和黑名单功能。

用户系统概述

Vibany 使用 Clerk 处理认证,用户数据自动同步到本地 PostgreSQL 数据库。

用户数据结构

// lib/db/schema.ts
users {
  clerkId: string;      // Clerk 用户 ID(主键)
  email: string;        // 邮箱
  username: string;     // 用户名
  avatarUrl: string;    // 头像 URL
  extra: object;        // 扩展字段
  createdAt: Date;      // 创建时间
  updatedAt: Date;      // 更新时间
}

extra 字段包含

  • isBlocklisted: 是否在黑名单
  • blocklistedAt: 加入黑名单时间
  • isSuspended: 是否被暂停

查看用户列表

通过 Admin 后台

  1. 访问 /admin/users
  2. 查看所有用户列表
  3. 支持搜索(按邮箱、用户名)
  4. 支持分页浏览

通过数据库查询

-- 查看所有用户
SELECT * FROM users ORDER BY created_at DESC LIMIT 20;

-- 查看特定用户
SELECT * FROM users WHERE email = 'user@example.com';

-- 查看黑名单用户
SELECT * FROM users 
WHERE extra->>'isBlocklisted' = 'true';

管理员权限

设置管理员

.env.local 中配置:

# 使用 Clerk User ID
ADMIN_USER_IDS=user_abc123,user_def456

# 或使用邮箱
ADMIN_USER_EMAILS=admin@yourdomain.com,operator@yourdomain.com

验证管理员身份

代码中检查:

const adminIds = process.env.ADMIN_USER_IDS?.split(',') || [];
const adminEmails = process.env.ADMIN_USER_EMAILS?.split(',') || [];
const isAdmin = adminIds.includes(userId) || adminEmails.includes(email);

黑名单管理

什么是黑名单

黑名单用于阻止特定用户或邮箱注册/登录。

黑名单类型

类型匹配方式示例
email完整邮箱匹配spammer@example.com
domain域名匹配example.com
ipIP 地址匹配192.168.1.1

添加黑名单

通过 Admin 后台

  1. 访问 /admin/blocklists
  2. 点击 "添加黑名单"
  3. 选择类型(email/domain/ip)
  4. 输入匹配模式
  5. 添加描述(可选)

通过数据库

INSERT INTO blocklists (id, type, pattern, enabled, description, created_at, updated_at)
VALUES (
  gen_random_uuid(),
  'email',
  'spammer@example.com',
  true,
  '垃圾邮件发送者',
  NOW(),
  NOW()
);

黑名单效果

  • 新用户注册:匹配黑名单的邮箱无法注册
  • 已有用户:匹配黑名单的用户会被限制功能
  • 积分发放:黑名单用户获得较少初始积分

用户钱包管理

查看用户积分

SELECT 
  u.email,
  u.username,
  w.permanent_points
FROM users u
JOIN wallets w ON u.clerk_id = w.user_id
WHERE u.email = 'user@example.com';

手动调整积分

通过 Admin 后台

  1. 找到用户
  2. 点击 "调整积分"
  3. 输入积分数量(正数为增加,负数为扣除)
  4. 添加调整原因

通过 API

// 增加积分
await rechargeUserPoints({
  userId: 'user_xxx',
  points: 100,
  description: '手动补偿',
  metadata: { adminId: 'admin_xxx', reason: '系统故障补偿' }
});

// 扣除积分
await deductPoints({
  userId: 'user_xxx',
  points: 50,
  description: '违规处理'
});

用户邀请管理

查看邀请码

SELECT 
  i.invite_code,
  u.username as referrer,
  i.invite_type,
  i.ref_ratio,
  i.max_uses,
  i.expires_at
FROM invitations i
JOIN users u ON i.referrer_id = u.clerk_id
ORDER BY i.created_at DESC;

禁用邀请码

UPDATE invitations 
SET extra = jsonb_set(extra, '{disabled}', 'true')
WHERE invite_code = 'ABC123';

用户数据分析

统计用户增长

-- 每日新增用户
SELECT 
  DATE(created_at) as date,
  COUNT(*) as new_users
FROM users
GROUP BY DATE(created_at)
ORDER BY date DESC;

-- 总用户数
SELECT COUNT(*) FROM users;

-- 活跃用户(最近 7 天有操作)
SELECT COUNT(DISTINCT user_id) 
FROM histories 
WHERE created_at > NOW() - INTERVAL '7 days';

用户画像

-- 积分分布
SELECT 
  CASE 
    WHEN permanent_points < 100 THEN '0-100'
    WHEN permanent_points < 500 THEN '100-500'
    WHEN permanent_points < 1000 THEN '500-1000'
    ELSE '1000+'
  END as points_range,
  COUNT(*) as user_count
FROM wallets
GROUP BY 1;

常见问题

用户无法登录

检查清单

  • 用户邮箱是否在黑名单
  • Clerk 配置是否正确
  • 用户账号是否被暂停

管理员权限不生效

解决方案

  1. 检查 .env.local 中的 ADMIN_USER_IDSADMIN_USER_EMAILS
  2. 确认使用正确的 User ID(不是邮箱)
  3. 重启应用以加载新配置

用户数据不同步

原因

  • Clerk webhook 未触发
  • 数据库连接问题

解决方案

  1. 检查数据库连接
  2. 手动触发同步
  3. 检查 Clerk 日志

相关文档

© copyright Justin 2025. All rights reserved.