从零到一:AI SaaS 博客系统完整部署实战
前言
这是一篇详细记录 AI SaaS 博客系统从代码合并、问题排查、数据库同步到最终成功发布文章的完整实战指南。如果你也在使用 Next.js + Supabase 构建博客系统,这篇文章将为你节省大量时间。
技术栈
- 前端框架: Next.js 16 (App Router)
- 数据库: Supabase (PostgreSQL)
- ORM: Drizzle ORM
- 部署平台: Vercel
- 内容管理: MDX + 在线编辑器
第一阶段:代码合并与推送
1. 查看 Git 状态
首先检查当前代码状态和远程分支情况:
cd /Users/public1/Desktop/windsurf/shipany-template-two
git status
git remote -v
发现:
- 本地分支:
dev - 远程仓库:
origin: shipanyai/shipany-template-twoproduction: starqazstar/shipany-production
2. 拉取最新代码
# 获取所有远程分支的最新信息
git fetch --all
# 合并 origin/dev 的更新
git pull origin dev --no-rebase
结果:
- 成功合并 60 个提交
- 新增 213 个文件修改
- 包含重要的数据库 schema 更新
3. 创建示例博客文章
为了测试系统,创建了两篇示例文章:
# 英文版
content/posts/getting-started-with-ai-saas.mdx
# 中文版
content/posts/getting-started-with-ai-saas.zh.mdx
文章内容:完整的 AI SaaS 开发指南,包含代码示例、最佳实践和部署指导。
4. 推送到生产仓库
# 提交新文章
git add content/posts/getting-started-with-ai-saas*.mdx
git commit -m "feat: add AI SaaS getting started guide (EN & ZH)"
# 推送到生产环境
git push production dev:main
成功:代码已推送到 https://github.com/starqazstar/shipany-production
第二阶段:部署失败与问题排查
问题 1:Vercel 构建失败
错误信息:
ShikiError: Language `env` is not included in this bundle
原因分析:
- 代码块使用了
\``env` 语法 - Shiki 语法高亮库不支持
env语言标识符
解决方案:
将所有 \``env改为```bash`
# 修复文件
git add content/posts/getting-started-with-ai-saas*.mdx
git commit -m "fix: change env code blocks to bash for Shiki compatibility"
git push production dev:main
教训:
- 使用标准的语言标识符:
bash,javascript,python等 - 避免使用不常见的标识符如
env,dotenv
第三阶段:数据库同步
问题 2:登录失败 - 字段缺失
合并代码后,尝试登录时出现错误:
错误信息:
column "utm_source" does not exist
原因分析:
合并的代码中,user 表新增了 3 个字段:
utm_source- UTM 来源追踪ip- IP 地址记录locale- 语言偏好设置
但这些字段只存在于代码中,Supabase 数据库尚未更新。
数据库 Schema 变更详情
旧版 Schema
CREATE TABLE "user" (
"id" text PRIMARY KEY,
"name" text NOT NULL,
"email" text NOT NULL UNIQUE,
"email_verified" boolean DEFAULT false NOT NULL,
"image" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
新版 Schema
CREATE TABLE "user" (
"id" text PRIMARY KEY,
"name" text NOT NULL,
"email" text NOT NULL UNIQUE,
"email_verified" boolean DEFAULT false NOT NULL,
"image" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"utm_source" text DEFAULT '' NOT NULL, -- 新增
"ip" text DEFAULT '' NOT NULL, -- 新增
"locale" text DEFAULT '' NOT NULL -- 新增
);
同步尝试 1:使用 Drizzle Push
# 尝试使用 ORM 推送 schema
pnpm db:push
结果:
[✓] Pulling schema from database...
[✓] Changes applied
问题:虽然显示成功,但实际连接的是本地数据库而非 Supabase!
发现:
查看 .env.development 配置:
DATABASE_URL="postgresql://public1@localhost:5432/shipany_dev"
这是本地 PostgreSQL,不是 Supabase!
同步方案 2:直接在 Supabase 执行 SQL ✅
步骤 1:登录 Supabase Dashboard
访问 https://supabase.com,进入项目的 SQL Editor。
步骤 2:执行迁移 SQL
-- 为 user 表添加新字段
ALTER TABLE "user"
ADD COLUMN IF NOT EXISTS "utm_source" text DEFAULT '' NOT NULL,
ADD COLUMN IF NOT EXISTS "ip" text DEFAULT '' NOT NULL,
ADD COLUMN IF NOT EXISTS "locale" text DEFAULT '' NOT NULL;
-- 验证字段已添加
SELECT column_name, data_type, column_default
FROM information_schema.columns
WHERE table_name = 'user'
ORDER BY ordinal_position;
步骤 3:验证结果
执行后确认新字段存在:
column_name | data_type | column_default
----------------+-----------+----------------
utm_source | text | ''::text
ip | text | ''::text
locale | text | ''::text
验证登录功能
# 重启开发服务器
pnpm dev
# 访问登录页
http://localhost:3000/sign-in
成功:可以正常登录了!✅
第四阶段:博客文章管理
在线编辑器功能测试
访问管理后台
http://localhost:3000/admin/posts
编辑器功能清单
-
基础字段
- ✅ 路由标识符(Slug)
- ✅ 文章标题
- ✅ 文章描述
- ✅ 分类选择(下拉菜单)
-
媒体上传
- ✅ 封面图上传(拖拽/点击)
- ✅ 作者头像上传
- ✅ 支持的格式:JPG, PNG, WebP
-
内容编辑
- ✅ Markdown 编辑器(基于 OverType)
- ✅ 实时编辑
- ✅ 支持完整 Markdown 语法
- ✅ 代码高亮
- ✅ 表格支持
-
发布控制
- ✅ 一键发布(状态:published)
- ✅ 自动时间戳
- ✅ 即时生效(无需重新部署)
技术亮点与最佳实践
1. 双模式内容管理
项目支持两种内容管理方式:
方式 A:MDX 文件(静态内容)
优点:
- ✅ 版本控制(Git)
- ✅ 离线编辑
- ✅ 支持 React 组件
- ✅ 构建时生成,性能好
适用场景:技术文档、教程、长期内容
文件结构:
content/posts/
├── article-1.mdx # 英文版
├── article-1.zh.mdx # 中文版
├── article-2.mdx
└── article-2.zh.mdx
方式 B:在线编辑器(动态内容)
优点:
- ✅ 即时发布
- ✅ 无需代码权限
- ✅ 权限控制
- ✅ 适合非技术人员
适用场景:新闻、动态更新、多人协作
2. 数据库设计
User 表字段说明
// 基础字段
id: string // 用户唯一标识
name: string // 用户名
email: string // 邮箱(唯一)
emailVerified: boolean // 邮箱验证状态
image: string // 头像 URL
// 时间戳
createdAt: timestamp // 注册时间
updatedAt: timestamp // 最后更新时间
// 追踪字段(新增)
utmSource: string // 来源追踪(营销分析)
ip: string // IP 地址(安全分析)
locale: string // 语言偏好(国际化)
Post 表结构
id: string // 文章 ID
userId: string // 作者 ID
slug: string // URL 标识符(唯一)
type: string // 类型(article/page/log)
title: string // 标题
description: string // 描述
image: string // 封面图
content: longtext // Markdown 内容
categories: string // 分类 ID(逗号分隔)
tags: string // 标签
authorName: string // 作者名
authorImage: string // 作者头像
status: string // 状态(published/draft/archived)
createdAt: timestamp // 创建时间
updatedAt: timestamp // 更新时间
sort: number // 排序权重
3. 权限管理(RBAC)
系统内置基于角色的访问控制:
// 角色定义
super_admin: ['*'] // 所有权限
admin: ['admin.posts.*'] // 文章增删改查
editor: ['admin.posts.read',
'admin.posts.write'] // 只能增改查
viewer: ['admin.posts.read'] // 只读
初始化权限:
pnpm rbac:init --admin-email=your@email.com
4. 性能优化
ISR(增量静态再生成)
// app/[locale]/(landing)/blog/page.tsx
export const revalidate = 3600; // 1 小时缓存
图片优化
import Image from 'next/image';
<Image
src="/imgs/photo.jpg"
alt="描述"
width={800}
height={600}
quality={85}
/>
数据库连接池
// 生产环境配置
DB_SINGLETON_ENABLED=false // 适合 Serverless
DB_MAX_CONNECTIONS=1 // 单连接模式
常见问题与解决方案
Q1: 如何处理图片?
方案 1:使用 Cloudflare R2
# 配置 R2 存储
CLOUDFLARE_R2_ACCOUNT_ID=...
CLOUDFLARE_R2_ACCESS_KEY_ID=...
CLOUDFLARE_R2_SECRET_ACCESS_KEY=...
方案 2:直接使用 Supabase Storage
# Supabase 内置存储
https://[project-ref].supabase.co/storage/v1/object/public/images/...
方案 3:使用 CDN
# 例如:jsDelivr
https://cdn.jsdelivr.net/gh/user/repo@main/images/...
Q2: 如何支持多语言?
项目内置 i18n 支持:
// 中文路由
/zh/blog/article-slug
// 英文路由
/blog/article-slug
创建多语言文章:
content/posts/article.mdx # 英文
content/posts/article.zh.mdx # 中文
Q3: 如何自定义主题?
/* src/config/style/theme.css */
:root {
--primary: #your-color;
--background: #your-bg;
}
Q4: 如何备份内容?
MDX 文件:已在 Git 版本控制中
数据库内容:
# 导出所有文章
pnpm db:studio
# 或使用 Supabase Dashboard 导出
部署清单
本地开发环境
- [x] Node.js 22+
- [x] pnpm 包管理器
- [x] Git 配置
- [x] 环境变量配置(.env.development)
Supabase 配置
- [x] 创建项目
- [x] 获取数据库连接字符串
- [x] 执行 Schema 迁移
- [x] 初始化 RBAC 权限
- [x] 配置存储桶(可选)
Vercel 部署
- [x] 连接 GitHub 仓库
- [x] 配置环境变量
- [x] 设置构建命令
- [x] 配置域名(可选)
必需的环境变量
# 应用配置
NEXT_PUBLIC_APP_URL=https://your-domain.vercel.app
NEXT_PUBLIC_APP_NAME=Your Blog
# 数据库
DATABASE_PROVIDER=postgresql
DATABASE_URL=postgresql://...
DB_SINGLETON_ENABLED=false
# 认证
AUTH_SECRET=<openssl rand -base64 32>
# AI 服务(可选)
OPENAI_API_KEY=sk-...
性能指标
构建时间
- 首次构建:~3 分钟
- 增量构建:~30 秒
运行性能
- 首页加载:< 1s
- 博客列表:< 2s(含数据库查询)
- 文章详情:< 1.5s
数据库查询
- 用户登录:~50ms
- 文章列表:~100ms
- 文章详情:~80ms
项目架构图
┌─────────────────────────────────────────┐
│ 用户浏览器 │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Vercel Edge Network │
│ (全球 CDN + Edge Functions) │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Next.js App Router │
│ ┌────────────────────────────────────┐ │
│ │ Pages (SSR + ISR) │ │
│ │ - 博客列表(1h 缓存) │ │
│ │ - 文章详情(1h 缓存) │ │
│ │ - 管理后台(实时) │ │
│ └────────────────────────────────────┘ │
│ ┌────────────────────────────────────┐ │
│ │ API Routes │ │
│ │ - /api/auth/* │ │
│ │ - /api/storage/* │ │
│ └────────────────────────────────────┘ │
└───────────────┬─────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Supabase (PostgreSQL) │
│ ┌────────────────────────────────────┐ │
│ │ Tables: │ │
│ │ - user (用户) │ │
│ │ - post (文章) │ │
│ │ - role (角色) │ │
│ │ - permission (权限) │ │
│ └────────────────────────────────────┘ │
│ ┌────────────────────────────────────┐ │
│ │ Storage (图片存储) │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
下一步优化方向
功能增强
- [ ] 评论系统(Giscus/Disqus)
- [ ] 搜索功能(Algolia/自建)
- [ ] 文章统计(浏览量、点赞)
- [ ] RSS 订阅
- [ ] 邮件通知
性能优化
- [ ] 图片懒加载
- [ ] 代码分割
- [ ] Service Worker
- [ ] 预加载关键资源
SEO 优化
- [ ] 结构化数据(Schema.org)
- [ ] Open Graph 标签
- [ ] Twitter Cards
- [ ] XML Sitemap 自动生成
总结
通过这次完整的部署实战,我们成功实现了:
✅ 代码管理:从多个分支合并代码,解决冲突
✅ 问题排查:识别并修复 Shiki 语法高亮问题
✅ 数据库同步:手动执行 SQL 迁移,添加新字段
✅ 功能验证:测试登录、文章管理等核心功能
✅ 部署上线:推送到生产环境,Vercel 自动部署
关键经验
- 环境分离:本地开发和生产环境使用不同数据库
- 版本控制:重要的配置和内容都要纳入 Git
- 渐进式部署:先本地测试,再推送生产
- 错误日志:仔细阅读错误信息,精准定位问题
- 文档记录:及时记录问题和解决方案
适用场景
这套系统适合:
- 🎯 技术博客
- 📚 产品文档
- 🚀 初创公司官网
- 💼 个人品牌建设
- 🎓 教育培训平台
技术优势
- 现代化:使用最新的 Next.js 16 和 React 19
- 高性能:ISR + Edge Functions + CDN
- 易维护:TypeScript + Drizzle ORM + 完整类型
- 可扩展:模块化设计,易于添加功能
- 低成本:Supabase 免费版 + Vercel 免费版即可运行
从零到一,我们成功构建了一个现代化的 AI SaaS 博客系统! 🎉
如果这篇文章对你有帮助,欢迎点赞分享。有任何问题欢迎在评论区讨论!
