Files
ai-directory-platform/scripts/setup-admin.ts
T
CoolChange.AI 8976caaaad feat: 初始化 Toolso.AI 开源 AI 工具导航站项目
🎯 项目概述
- 一个开源的 AI 工具导航站,帮助用户发现和探索优秀的 AI 工具
- 基于 Next.js 16 + React 19 构建的现代化全栈应用

✨ 核心功能
- AI 工具目录:分类展示、搜索筛选、工具详情页
- 工具提交:用户可提交新工具,社区驱动
- 管理后台:工具审核、用户管理、角色权限控制
- 博客系统:MDX 驱动,AI 资讯和教程
- 国际化支持:中文/英文双语 (next-intl)
- 用户认证:Better Auth + Google OAuth
- 深色/浅色主题切换

🛠 技术栈
- 前端:Next.js 16 (App Router) + React 19 + TypeScript
- 样式:Tailwind CSS + Framer Motion 动画
- UI 组件:自定义组件库 + Radix UI
- 表单验证:React Hook Form + Zod
- 数据库:PostgreSQL + Drizzle ORM
- 认证:Better Auth (邮箱密码 + Google OAuth)
- 邮件:Resend (验证邮件 + Newsletter)
- 存储:Cloudflare R2 / AWS S3 兼容

📁 项目结构
- src/app/[locale]/(auth) - 认证页面
- src/app/[locale]/(marketing) - 营销页面 (首页、博客、工具目录)
- src/app/[locale]/(protected) - 受保护页面 (仪表板、个人资料)
- src/app/[locale]/(admin) - 管理后台
- src/features - 功能模块
- src/lib - 核心业务逻辑
- messages - 国际化翻译文件

🗄 数据库
- 包含 user, session, account, verification, passwordResetToken 等核心表
- 支持 Drizzle ORM 迁移管理

📝 文档
- 完整的 CLAUDE.md 项目指南
- 环境变量配置示例 (.env.example)
- MIT 开源许可证
2026-01-03 23:52:28 +08:00

111 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env tsx
/**
* 管理员初始化脚本
* 用于设置第一个管理员账号
*
* 使用方法:
* 1. 设置环境变量 ADMIN_EMAIL
* 2. 运行: pnpm admin:setup
* 或直接运行: ADMIN_EMAIL=admin@example.com pnpm admin:setup
*/
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import { eq } from "drizzle-orm";
import dotenv from "dotenv";
import { resolve } from "path";
import { pgTable, text, timestamp, boolean, integer } from "drizzle-orm/pg-core";
// 加载环境变量
dotenv.config({ path: resolve(process.cwd(), ".env.local") });
// 定义 user 表结构(复制自 schema)
const user = pgTable("user", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").default(false).notNull(),
image: text("image"),
credits: integer("credits").default(0).notNull(),
role: text("role").default("user").notNull(),
banned: boolean("banned").default(false).notNull(),
banReason: text("ban_reason"),
banExpires: timestamp("ban_expires"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
.defaultNow()
.$onUpdate(() => new Date())
.notNull(),
});
async function setupAdmin() {
const adminEmail = process.env.ADMIN_EMAIL;
if (!adminEmail) {
console.error("❌ 请设置环境变量 ADMIN_EMAIL");
console.log("例如: ADMIN_EMAIL=admin@example.com pnpm admin:setup");
process.exit(1);
}
if (!process.env.DATABASE_URL) {
console.error("❌ 未找到 DATABASE_URL 环境变量");
console.log("请确保 .env.local 文件中设置了 DATABASE_URL");
process.exit(1);
}
// 创建数据库连接
const queryClient = postgres(process.env.DATABASE_URL);
const db = drizzle(queryClient);
try {
console.log("🔍 正在查找用户:", adminEmail);
// 检查用户是否存在
const existingUser = await db
.select()
.from(user)
.where(eq(user.email, adminEmail))
.limit(1);
if (existingUser.length === 0) {
console.error(`❌ 用户 ${adminEmail} 不存在`);
console.log("请先使用此邮箱注册一个账号,然后再运行此脚本");
await queryClient.end();
process.exit(1);
}
const currentUser = existingUser[0];
console.log(`✓ 找到用户: ${currentUser.name} (当前角色: ${currentUser.role})`);
if (currentUser.role === "admin") {
console.log(`✅ 用户 ${adminEmail} 已经是管理员`);
await queryClient.end();
process.exit(0);
}
// 更新用户为管理员
console.log("📝 正在更新用户角色...");
await db
.update(user)
.set({
role: "admin",
updatedAt: new Date()
})
.where(eq(user.email, adminEmail));
console.log(`✅ 成功将用户 ${adminEmail} 设置为管理员`);
console.log("🚀 现在你可以访问 /admin 路径来进入管理后台");
} catch (error) {
console.error("❌ 设置管理员失败:", error);
await queryClient.end();
process.exit(1);
}
// 关闭数据库连接
await queryClient.end();
process.exit(0);
}
// 运行脚本
setupAdmin();