部署指南
将 Sistine Starter 部署到生产环境的完整指南
部署指南
本指南将帮助你将 Sistine Starter 部署到生产环境,包括数据库配置、环境变量设置、Webhook 配置和定时任务设置。
部署清单
在开始部署前,请确保完成以下准备工作:
1. 环境准备
- PostgreSQL 数据库: Neon
- 火山引擎 API Key: 申请地址
- Creem 账号和 API Key: 注册地址
- Resend API Key: 注册地址
- Google OAuth 凭据 (可选): Google Cloud Console
- S3 存储配置 (可选): AWS S3 或兼容服务
- 域名 (生产环境): 已备案的域名
2. 账号注册
| 服务 | 用途 | 免费额度 | 注册链接 |
|---|---|---|---|
| Vercel | 应用托管 | 100GB 带宽/月 | vercel.com |
| Neon | PostgreSQL 数据库 | 500MB 存储 + 100小时计算 | neon.tech |
| 火山引擎 | AI 服务 | 试用额度 | volcengine.com |
| Creem | 支付网关 | 测试模式免费 | creem.io |
| Resend | 邮件服务 | 100 封/天 | resend.com |
| PostHog (可选) | 分析工具 | 1M 事件/月 | posthog.com |
数据库迁移步骤
步骤 1: 创建生产数据库
使用 Neon (推荐)
- 访问 neon.tech 并登录
- 点击 Create Project
- 配置项目:
- Project name:
sistine-production - Region: 选择离目标用户最近的区域
- PostgreSQL version: 选择最新稳定版 (16+)
- Project name:
- 创建完成后,复制连接字符串 (包含
?sslmode=require)
示例连接字符串:
postgresql://username:password@ep-xxx.us-east-2.aws.neon.tech/main?sslmode=require步骤 2: 执行数据库迁移
在本地执行迁移,将 Schema 应用到生产数据库:
# 1. 设置生产数据库 URL
export DATABASE_URL="postgresql://user:password@host/db?sslmode=require"
# 2. 执行迁移
pnpm db:migrate
# 3. 验证迁移
pnpm db:studio重要提示:
- ✅ 生产环境推荐使用 迁移文件 (
db:migrate) - ✅ 确保
.env.local中的DATABASE_URL不会被提交到 Git - ✅ 执行迁移前先备份数据库 (如果已有数据)
步骤 3: 验证表结构
使用 Drizzle Studio 或 Neon 的 GUI 验证以下表已创建:
核心表:
user(用户表)session(会话表)account(账户表)payment(支付记录表)subscription(订阅表)creditLedger(积分账本表)subscriptionCreditSchedule(订阅积分调度表)
AI 功能表:
chatSession(对话会话表)chatMessage(对话消息表)generationHistory(生成历史表)
其他表:
passwordResetToken(密码重置表)newsletterSubscription(Newsletter 订阅表)
Vercel 部署指南 (推荐)
Vercel 是部署 Next.js 应用的最佳平台,提供零配置部署、自动 HTTPS、全球 CDN 和边缘函数支持。
步骤 1: 连接 Git 仓库
- 推送代码到 Git:
# 如果尚未初始化 Git
git init
git add .
git commit -m "Initial commit"
# 推送到 GitHub
git remote add origin https://github.com/your-username/your-repo.git
git push -u origin main-
登录 Vercel:
- 访问 vercel.com
- 使用 GitHub 账号登录
-
导入项目:
- 点击 Add New > Project
- 选择你的 GitHub 仓库
- 点击 Import
步骤 2: 配置环境变量
详细的环境变量配置请参考 图文配置手册。
在 Vercel 项目设置中添加所有必需的环境变量: 路径: Project Settings > Environment Variables
步骤 3: 构建设置
Vercel 会自动检测 Next.js 项目,以下是默认配置:
Build Command: pnpm build (自动检测)
Output Directory: .next (自动检测)
Install Command: pnpm install (自动检测)
Node.js Version: 20.x (推荐)
如需自定义,在项目根目录创建 vercel.json:
{
"buildCommand": "pnpm build",
"devCommand": "pnpm dev",
"installCommand": "pnpm install",
"framework": "nextjs",
"regions": ["iad1"],
"functions": {
"app/api/**/*.ts": {
"maxDuration": 60
}
}
}配置说明:
regions: 部署区域 (如iad1= 美国东部,hnd1= 日本东京)maxDuration: API 路由最大执行时间 (Pro 计划可设置 60s+)
步骤 4: 域名配置
使用 Vercel 默认域名
部署完成后,Vercel 会自动分配域名:
https://your-project.vercel.app绑定自定义域名
-
添加域名:
- 进入 Project Settings > Domains
- 输入你的域名 (如
yourdomain.com) - 点击 Add
-
配置 DNS: 在你的域名服务商 (如 Cloudflare、阿里云、腾讯云) 添加 DNS 记录:
方法 A: CNAME (推荐)
类型: CNAME 名称: @ (或 www) 值: cname.vercel-dns.com方法 B: A 记录
类型: A 名称: @ 值: 76.76.21.21 -
验证域名:
- DNS 生效后,Vercel 会自动验证并签发 SSL 证书
- 通常需要 5-10 分钟
-
更新环境变量: 将
BETTER_AUTH_URL和NEXT_PUBLIC_APP_URL更新为自定义域名:BETTER_AUTH_URL="https://yourdomain.com" NEXT_PUBLIC_APP_URL="https://yourdomain.com"
步骤 5: 首次部署
-
点击 Deploy: Vercel 会自动构建和部署应用
-
查看部署日志: 监控构建过程,确保没有错误
-
访问应用: 部署成功后,访问分配的域名验证应用是否正常运行
常见部署错误:
- 构建失败: 检查环境变量是否正确设置
- 数据库连接错误: 确认
DATABASE_URL是否正确 - API 调用失败: 检查 API Key 是否有效
配置 Creem Webhook
Webhook 用于接收支付事件通知,是订阅和支付系统正常工作的关键。
步骤 1: 在 Creem Dashboard 中设置
-
登录 Creem Dashboard: creem.io/dashboard
-
进入 Developers > Webhooks:
- 点击左侧菜单的 Developers
- 选择 Webhooks
-
添加 Endpoint:
- 点击 Add endpoint
- Endpoint URL:
https://yourdomain.com/api/payments/creem/webhook - Description:
Production Webhook
-
选择事件: 勾选以下事件 (或选择 Select all events):
checkout.completed- 支付完成subscription.paid- 订阅续费成功subscription.active- 订阅激活subscription.canceled- 订阅取消subscription.expired- 订阅过期
-
获取 Signing Secret:
- 保存后,复制 Signing Secret (格式:
whsec_...) - 将其添加到 Vercel 环境变量
CREEM_WEBHOOK_SECRET
- 保存后,复制 Signing Secret (格式:
步骤 2: 测试 Webhook
方法 1: 使用 Creem CLI
# 安装 Creem CLI
npm install -g @creem/cli
# 登录
creem login
# 转发 webhook 到本地 (用于开发测试)
creem listen --forward-to localhost:3000/api/payments/creem/webhook方法 2: 发送测试事件
在 Creem Dashboard 的 Webhook 页面:
- 点击刚创建的 Webhook
- 点击 Send test webhook
- 选择事件类型 (如
checkout.completed) - 点击 Send test event
方法 3: 真实测试支付
- 在 Creem 中启用 Test Mode
- 访问你的应用定价页
- 使用测试卡号完成支付:
卡号: 4242 4242 4242 4242 过期日期: 任意未来日期 CVC: 任意 3 位数字 - 检查 Webhook 是否触发并正确处理
步骤 3: 验证 Webhook 签名
Webhook 签名验证在 app/api/payments/creem/webhook/route.ts 中自动处理:
import { verifyWebhookSignature } from '@/lib/payments/creem';
const signature = request.headers.get('creem-signature');
const rawBody = await request.text();
const isValid = verifyWebhookSignature(rawBody, signature, webhookSecret);
if (!isValid) {
return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
}安全提示:
- ✅ 始终验证 Webhook 签名
- ✅ 使用 HTTPS (Vercel 自动提供)
- ✅ 不要在日志中打印敏感信息
步骤 4: 监控 Webhook 事件
在 Creem Dashboard 中查看 Webhook 日志:
- 进入 Developers > Webhooks
- 点击你的 Webhook
- 查看 Recent deliveries
状态码说明:
200: 成功处理401: 签名验证失败500: 服务器错误
配置定时任务 (Vercel Cron Jobs)
定时任务用于自动发放年付订阅的分期积分。
步骤 1: 配置 Cron 端点
在 vercel.json 中添加 Cron 配置:
{
"crons": [
{
"path": "/api/cron/grant-subscription-credits",
"schedule": "0 * * * *"
}
]
}Schedule 语法 (Cron 表达式):
分 时 日 月 周
0 * * * * → 每小时整点执行
0 0 * * * → 每天午夜执行
0 */6 * * * → 每 6 小时执行常用 Schedule:
| 表达式 | 说明 |
|---|---|
0 * * * * | 每小时整点 (推荐) |
0 0 * * * | 每天午夜 |
0 */6 * * * | 每 6 小时 |
0 0 1 * * | 每月 1 号午夜 |
步骤 2: Cron 端点认证
Cron 端点需要认证以防止未授权访问:
方法 1: 使用 Vercel Cron Secret (推荐)
Vercel 自动在 Cron 请求中添加 authorization 头:
// app/api/cron/grant-subscription-credits/route.ts
export async function GET(request: NextRequest) {
// 验证 Vercel Cron Secret
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// 执行积分发放逻辑
// ...
}在 Vercel 环境变量中设置:
CRON_SECRET="生成一个随机密钥"方法 2: 使用 Vercel 内部验证
import { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
// 验证请求来自 Vercel Cron
const cronSecret = request.headers.get('x-vercel-cron-secret');
if (cronSecret !== process.env.CRON_SECRET) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// ...
}步骤 3: 测试定时任务
本地测试
使用 cURL 手动触发:
curl -X GET \
http://localhost:3000/api/cron/grant-subscription-credits \
-H "Authorization: Bearer YOUR_CRON_SECRET"生产环境测试
在 Vercel Dashboard 中:
- 进入 Project > Cron Jobs
- 找到你的 Cron Job
- 点击 Run now 手动触发
步骤 4: 监控 Cron 执行
查看 Cron 执行日志:
- 进入 Vercel Dashboard > Project > Deployments
- 点击 Functions
- 找到
/api/cron/grant-subscription-credits - 查看执行日志和错误信息
调试提示:
- 在 Cron 函数中添加详细日志
- 使用
console.log输出执行状态 - 检查函数执行时间 (避免超时)
创建管理员账户
部署完成后,创建第一个管理员账户以访问管理后台。
方法 1: 使用命令行工具 (推荐)
- 克隆仓库到本地 (如果尚未克隆):
git clone https://github.com/your-username/your-repo.git
cd your-repo- 设置生产数据库 URL:
export DATABASE_URL="postgresql://user:password@host/db?sslmode=require"- 运行管理员设置脚本:
pnpm admin:setup- 按提示输入信息:
Enter admin email: admin@yourdomain.com
Enter admin password: ********
Enter admin name: Admin User- 验证管理员账户:
- 访问
https://yourdomain.com/zh/login - 使用刚创建的邮箱和密码登录
- 访问
https://yourdomain.com/zh/admin确认能访问管理后台
- 访问
方法 2: 手动在数据库中创建
如果没有命令行工具访问权限,可以手动在数据库中设置:
-
登录数据库管理界面 (Neon / Supabase GUI 或 Drizzle Studio)
-
找到你的用户记录:
SELECT id, email, role FROM "user" WHERE email = 'your-email@example.com';- 更新 role 为 admin:
UPDATE "user"
SET role = 'admin'
WHERE email = 'your-email@example.com';- 验证更新:
SELECT id, email, role FROM "user" WHERE email = 'your-email@example.com';应该看到 role 列显示为 admin。
生产环境优化建议
1. 性能优化
启用 Next.js 静态优化
在 next.config.mjs 中:
/** @type {import('next').NextConfig} */
const nextConfig = {
// 启用静态导出 (部分页面)
output: 'standalone',
// 图片优化
images: {
domains: ['yourdomain.com'],
formats: ['image/avif', 'image/webp'],
},
// 压缩
compress: true,
// React 严格模式
reactStrictMode: true,
// 生产环境禁用 source map
productionBrowserSourceMaps: false,
};
export default nextConfig;使用 CDN 加速静态资源
Vercel 自动提供全球 CDN,无需额外配置。
数据库连接池
使用 Neon 的连接池模式:
# Neon 自动使用连接池
DATABASE_URL="postgresql://user:pass@ep-xxx.pooler.us-east-2.aws.neon.tech/main"2. 安全优化
设置安全响应头
在 next.config.mjs 中:
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
],
},
];
},
};限制 API 速率 (Rate Limiting)
安装并配置速率限制中间件:
pnpm add @upstash/ratelimit @upstash/redis// lib/rate-limit.ts
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
export const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '1 m'), // 10 次/分钟
});在 API 路由中使用:
import { ratelimit } from '@/lib/rate-limit';
export async function POST(request: NextRequest) {
const identifier = request.ip ?? 'anonymous';
const { success } = await ratelimit.limit(identifier);
if (!success) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
// 处理请求
}定期轮换密钥
每 3-6 个月更换以下密钥:
BETTER_AUTH_SECRETCRON_SECRETCREEM_WEBHOOK_SECRET
3. 监控和日志
使用 Vercel Analytics
在 app/[locale]/layout.tsx 中添加:
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}集成错误追踪 (Sentry)
pnpm add @sentry/nextjs// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});数据库监控
在 Neon Dashboard 中监控:
- 查询性能
- 连接数
- 存储使用量
- 慢查询日志
4. 备份策略
数据库自动备份
Neon:
- 自动每日备份 (保留 7 天)
- 手动创建快照: Project > Backups > Create snapshot
# 手动备份
pg_dump "postgresql://user:pass@host/db" > backup-$(date +%Y%m%d).sql
# 恢复备份
psql "postgresql://user:pass@host/db" < backup-20251015.sql代码备份
确保代码推送到 Git 远程仓库:
git push origin main5. 扩展性优化
边缘函数 (Edge Functions)
将轻量级 API 迁移到边缘函数以降低延迟:
// app/api/hello/route.ts
export const runtime = 'edge'; // 启用边缘运行时
export async function GET() {
return new Response('Hello from Edge!');
}数据库分区 (针对大规模应用)
对大表进行分区 (如 creditLedger, chatMessage):
例如按月份为 creditLedger 创建分区,具体 SQL 迁移可参考 数据库 文档或你自己的迁移脚本。
缓存策略
使用 Redis 缓存热点数据:
import { Redis } from '@upstash/redis';
const redis = Redis.fromEnv();
// 缓存用户积分
export async function getUserCredits(userId: string) {
const cached = await redis.get(`credits:${userId}`);
if (cached) return cached;
const credits = await db.query.user.findFirst({
where: eq(user.id, userId),
columns: { credits: true },
});
await redis.set(`credits:${userId}`, credits, { ex: 300 }); // 缓存 5 分钟
return credits;
}常见部署问题
1. 构建失败: "Module not found"
原因: 依赖未正确安装
解决方法:
# 清理缓存并重新安装
rm -rf node_modules .next
pnpm install
pnpm build2. 数据库连接超时
原因: 数据库 URL 错误或网络问题
解决方法:
- 检查
DATABASE_URL是否正确 - 确认包含
?sslmode=require - 检查数据库防火墙设置 (允许 Vercel IP)
3. Webhook 未触发
原因: Webhook URL 错误或签名验证失败
解决方法:
- 检查 Creem Dashboard 中的 Webhook URL
- 确认
CREEM_WEBHOOK_SECRET与 Dashboard 一致 - 查看 Creem Webhook 日志中的错误信息
4. Cron Job 未执行
原因: Cron 配置错误或认证失败
解决方法:
- 检查
vercel.json中的 Cron 配置 - 确认
CRON_SECRET环境变量已设置 - 在 Vercel Dashboard 中手动触发测试
5. Google OAuth 重定向错误
原因: 回调 URL 未在 Google Console 中配置
解决方法:
- 在 Google Cloud Console 中添加生产环境回调 URL:
https://yourdomain.com/api/auth/callback/google - 更新
BETTER_AUTH_URL为生产域名
6. 邮件发送失败
原因: 域名未在 Resend 中验证
解决方法:
- 在 Resend Dashboard 中添加域名
- 配置 DNS 记录 (SPF, DKIM)
- 等待验证完成
- 更新
RESEND_FROM_EMAIL使用已验证的域名
7. 页面 404 错误
原因: 动态路由配置问题
解决方法:
- 检查
middleware.ts的 matcher 配置 - 确认
i18n.config.ts中的 locale 设置 - 清除浏览器缓存并重试
部署后检查清单
部署完成后,逐一检查以下项目:
功能测试
- 首页加载正常: 访问
https://yourdomain.com - 用户注册: 注册新账户,确认收到验证邮件
- 用户登录: 使用邮箱密码登录
- Google OAuth: 使用 Google 账号登录 (如果启用)
- 积分显示: 查看仪表板,确认新用户获得 300 积分
- 支付流程: 购买积分包或订阅,确认 Webhook 触发
- AI 功能: 测试对话、图像生成、视频生成
- 管理后台: 使用管理员账户访问
/zh/admin - 语言切换: 切换中英文,确认翻译正确
- 响应式设计: 在移动设备上测试
安全检查
- HTTPS 启用: 所有页面使用 HTTPS
- 环境变量隔离: 不同环境使用不同的 API Key
- Webhook 签名验证: Webhook 端点验证签名
- Cron 认证: Cron 端点需要认证
- SQL 注入防护: 使用参数化查询
- CSRF 保护: Better Auth 自动提供
性能检查
- 首屏加载时间 < 3 秒
- Lighthouse 分数 > 90
- 图片优化: 使用 WebP/AVIF 格式
- CDN 缓存: 静态资源使用 CDN
- 数据库查询优化: 慢查询 < 100ms
监控设置
- 错误追踪: Sentry 或类似工具已配置
- 分析工具: PostHog / Google Analytics 已启用
- 日志监控: Vercel Logs 可查看运行日志
- 告警设置: 关键错误自动发送通知