laobinghu 37742571ae feat: 完成项目初始化并重构部署流程
主要变更:
- 添加完整的项目结构和模块(admin、articles、comments、users、session、oauth2、email、moderation、analytics、jobs 等)
- 实现系统初始化 API(/init/status 和 /init/run)
- 重写部署流程:迁移到 package.json scripts,删除 Makefile
- 优化部署脚本:deploy.sh、healthcheck.sh、backup.sh、restore.sh、verify-env.sh
- 更新 README.md:简化文档,整合部署指南
- 优化 AGENTS.md:精简到约 150 行,包含完整的代码规范和命令速查
- 配置 Docker Compose 自动化部署(prisma migrate deploy + seed)
- 生成 OAuth2 RSA 密钥对支持
- 添加环境变量验证和数据库备份恢复功能
2026-03-28 16:53:25 +08:00

117 lines
3.1 KiB
TypeScript

import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcrypt';
const prisma = new PrismaClient();
async function main() {
// 创建默认 OAuth2 客户端
const defaultClient = await prisma.oAuth2Client.upsert({
where: { clientId: 'web-client' },
update: {},
create: {
clientId: 'web-client',
clientSecret: 'change_me',
redirectUris: ['http://localhost:3000/auth/callback'],
scopes: 'read write',
},
});
console.log('Default OAuth2 client:', defaultClient.clientId);
// 检查是否已有管理员用户
const existingAdmin = await prisma.user.findFirst({
where: { email: 'admin@example.com' },
});
let admin;
if (!existingAdmin) {
const passwordHash = await bcrypt.hash('password123', 12);
admin = await prisma.user.create({
data: {
email: 'admin@example.com',
username: 'admin',
passwordHash,
displayName: 'Admin',
role: 'admin',
},
});
console.log('Created admin user:', admin.email);
} else {
admin = existingAdmin;
console.log('Admin user already exists:', admin.email);
}
// 检查是否已有版主用户
const existingModerator = await prisma.user.findFirst({
where: { email: 'moderator@example.com' },
});
if (!existingModerator) {
const modPasswordHash = await bcrypt.hash('moderator123', 12);
await prisma.user.create({
data: {
email: 'moderator@example.com',
username: 'moderator',
passwordHash: modPasswordHash,
displayName: 'Moderator',
role: 'moderator',
},
});
console.log('Created moderator user: moderator@example.com');
} else {
console.log('Moderator user already exists:', existingModerator.email);
}
// 创建示例文章
const existingArticle = await prisma.article.findFirst({
where: { slug: 'welcome' },
});
if (!existingArticle) {
const article = await prisma.article.create({
data: {
slug: 'welcome',
title: 'Welcome to LinkShare Blog',
content: 'This is a sample article. You can edit or delete it.',
excerpt: 'Short excerpt',
status: 'published',
visibility: 'public',
publishedAt: new Date(),
authorId: admin.id,
},
});
console.log('Created sample article:', article.slug);
} else {
console.log('Sample article already exists:', existingArticle.slug);
}
// 创建 link-access token 示例
const article = await prisma.article.findFirst({
where: { slug: 'welcome' },
});
if (article) {
const existingLink = await prisma.linkAccess.findFirst({
where: { articleId: article.id },
});
if (!existingLink) {
await prisma.linkAccess.create({
data: {
token: 'sample-token-123',
articleId: article.id,
maxViews: 100,
},
});
console.log('Created link-access token for article:', article.slug);
}
}
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});