从零到一:AI SaaS 博客系统完整部署实战

Jan 13, 2026

从零到一: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-two
    • production: 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 个字段:

  1. utm_source - UTM 来源追踪
  2. ip - IP 地址记录
  3. 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

编辑器功能清单

  1. 基础字段

    • ✅ 路由标识符(Slug)
    • ✅ 文章标题
    • ✅ 文章描述
    • ✅ 分类选择(下拉菜单)
  2. 媒体上传

    • ✅ 封面图上传(拖拽/点击)
    • ✅ 作者头像上传
    • ✅ 支持的格式:JPG, PNG, WebP
  3. 内容编辑

    • ✅ Markdown 编辑器(基于 OverType)
    • ✅ 实时编辑
    • ✅ 支持完整 Markdown 语法
    • ✅ 代码高亮
    • ✅ 表格支持
  4. 发布控制

    • ✅ 一键发布(状态: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 (图片存储)                 │ │
│  └────────────────────────────────────┘ │
└─────────────────────────────────────────┘

下一步优化方向

功能增强

  1. [ ] 评论系统(Giscus/Disqus)
  2. [ ] 搜索功能(Algolia/自建)
  3. [ ] 文章统计(浏览量、点赞)
  4. [ ] RSS 订阅
  5. [ ] 邮件通知

性能优化

  1. [ ] 图片懒加载
  2. [ ] 代码分割
  3. [ ] Service Worker
  4. [ ] 预加载关键资源

SEO 优化

  1. [ ] 结构化数据(Schema.org
  2. [ ] Open Graph 标签
  3. [ ] Twitter Cards
  4. [ ] XML Sitemap 自动生成

总结

通过这次完整的部署实战,我们成功实现了:

代码管理:从多个分支合并代码,解决冲突
问题排查:识别并修复 Shiki 语法高亮问题
数据库同步:手动执行 SQL 迁移,添加新字段
功能验证:测试登录、文章管理等核心功能
部署上线:推送到生产环境,Vercel 自动部署

关键经验

  1. 环境分离:本地开发和生产环境使用不同数据库
  2. 版本控制:重要的配置和内容都要纳入 Git
  3. 渐进式部署:先本地测试,再推送生产
  4. 错误日志:仔细阅读错误信息,精准定位问题
  5. 文档记录:及时记录问题和解决方案

适用场景

这套系统适合:

  • 🎯 技术博客
  • 📚 产品文档
  • 🚀 初创公司官网
  • 💼 个人品牌建设
  • 🎓 教育培训平台

技术优势

  • 现代化:使用最新的 Next.js 16 和 React 19
  • 高性能:ISR + Edge Functions + CDN
  • 易维护:TypeScript + Drizzle ORM + 完整类型
  • 可扩展:模块化设计,易于添加功能
  • 低成本:Supabase 免费版 + Vercel 免费版即可运行

从零到一,我们成功构建了一个现代化的 AI SaaS 博客系统! 🎉

如果这篇文章对你有帮助,欢迎点赞分享。有任何问题欢迎在评论区讨论!

国虎

从零到一:AI SaaS 博客系统完整部署实战 | Blog