项目结构
理解 Sistine Starter 的项目组织和代码架构
项目结构
Sistine Starter 采用模块化架构,基于 Next.js App Router,强调可扩展性和代码组织。
高层结构
sistine-starter/
├── app/ # Next.js App Router (前端页面和 API)
├── lib/ # 核心业务逻辑和工具函数
├── components/ # UI 组件库
├── features/ # 功能模块
├── content/ # 博客和文档内容
├── public/ # 静态资源
├── messages/ # 国际化翻译文件
├── constants/ # 常量定义
├── emails/ # 邮件模板
├── scripts/ # 实用脚本
├── drizzle/ # 数据库迁移
├── next.config.mjs # Next.js 配置
├── tailwind.config.ts # Tailwind CSS 配置
├── tsconfig.json # TypeScript 配置
└── package.json # 项目依赖
详细目录说明
1. app/ - Next.js App Router
app/
├── layout.tsx # 根布局
├── globals.css # 全局样式
├── favicon.ico
├── [locale]/ # 国际化路由
│ ├── layout.tsx # 语言级布局 (主题, i18n, 分析)
│ ├── (auth)/ # 认证相关路由 (分组)
│ │ ├── login/page.tsx
│ │ ├── signup/page.tsx
│ │ ├── forgot-password/page.tsx
│ │ └── reset-password/page.tsx
│ ├── (marketing)/ # 营销页面 (分组)
│ │ ├── layout.tsx
│ │ ├── page.tsx # 首页
│ │ ├── blog/page.tsx # 博客列表
│ │ ├── blog/[slug]/page.tsx # 博客文章
│ │ ├── pricing/page.tsx
│ │ ├── contact/page.tsx
│ │ ├── privacy/page.tsx
│ │ ├── terms/page.tsx
│ │ └── refund/page.tsx
│ ├── (protected)/ # 受保护页面 (需要认证)
│ │ ├── layout.tsx
│ │ ├── dashboard/page.tsx
│ │ ├── profile/page.tsx
│ │ └── credits/page.tsx
│ ├── (admin)/ # 管理员页面 (需要 admin 权限)
│ │ ├── layout.tsx
│ │ ├── admin/page.tsx
│ │ ├── admin/users/page.tsx
│ │ ├── admin/subscriptions/page.tsx
│ │ └── admin/credits/page.tsx
│ ├── demo/ # AI 功能演示
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ ├── chat/page.tsx
│ │ ├── image/page.tsx
│ │ └── video/page.tsx
│ ├── verify-email/page.tsx
│ └── check-email/page.tsx
├── api/ # API 路由
│ ├── auth/[...all]/route.ts # Better Auth 集成
│ ├── chat/route.ts # AI 对话 (非流)
│ ├── chat/stream/route.ts # 流式对话
│ ├── image/generate/route.ts # 图像生成
│ ├── video/generate/route.ts # 视频生成
│ ├── video/status/route.ts # 视频状态查询
│ ├── user/profile/route.ts # 用户信息
│ ├── user/credits/history/route.ts # 积分历史
│ ├── user/admin-status/route.ts # 检查管理员权限
│ ├── payments/creem/ # 支付相关
│ │ ├── checkout/route.ts
│ │ ├── webhook/route.ts
│ │ └── redirect-placeholder/route.ts
│ ├── upload/
│ │ ├── simple/route.ts # 简单上传
│ │ └── image/route.ts # 图片上传
│ ├── admin/users/[userId]/ # 管理员 API
│ │ ├── credits/route.ts # 调整积分
│ │ └── subscription/route.ts # 修改订阅
│ ├── newsletter/ # 新闻通讯
│ │ ├── subscribe/route.ts
│ │ └── unsubscribe/route.ts
│ ├── cron/subscription-grants/route.ts # 定时任务: 发放积分
│ └── llms-full.txt/route.ts # LLM 完整文档端点
└── og/ # Open Graph 图像生成
└── [slug]/route.tsx
路由分组说明:
(auth)
- 不影响 URL,用于组织认证相关路由(marketing)
- 营销页面组(protected)
- 受保护页面(自动重定向到登录)(admin)
- 管理员页面
2. lib/ - 核心业务逻辑
lib/
├── auth.ts # Better Auth 配置
├── auth-client.ts # 客户端认证 Hook
├── i18n.ts # 国际化配置
├── blog.ts # 博客加载逻辑
├── credits.ts # 积分系统核心
│ ├── getUserCredits() # 获取用户积分
│ ├── canUserAfford() # 检查积分是否足够
│ ├── deductCredits() # 扣除积分 (事务性)
│ └── refundCredits() # 退还积分
├── email.ts # 邮件发送
├── utils.ts # 通用工具函数
├── r2-storage.ts # S3 兼容存储
├── db/
│ ├── index.ts # Drizzle ORM 初始化
│ └── schema.ts # 完整数据库 Schema
├── auth/
│ └── admin.ts # 管理员权限检查
├── billing/
│ └── subscription.ts # 订阅和积分发放
├── payments/
│ └── creem.ts # Creem 支付 API
└── volcano-engine/ # 火山引擎 AI 服务
├── index.ts
├── chat.ts # 对话 API
├── image.ts # 图像生成 API
├── video.ts # 视频生成 API
├── config.ts
└── types.ts
3. components/ - UI 组件库
components/
├── analytics/ # 分析工具脚本
│ ├── analytics.tsx
│ ├── google-analytics.tsx
│ ├── clarity-analytics.tsx
│ └── posthog-analytics.tsx
├── navbar.tsx # 导航栏
├── footer.tsx # 页脚
├── hero.tsx # 首页 Hero 部分
├── features.tsx # 功能展示
├── cta.tsx # 行动呼吁
├── blog-card.tsx # 博客卡片
├── blog-layout.tsx # 博客文章布局
├── container.tsx # 容器组件
├── heading.tsx # 标题组件
├── button.tsx # 按钮组件
├── badge.tsx # 徽章组件
├── language-switcher.tsx # 语言切换器
├── theme-switcher.tsx # 主题切换器
├── grid-lines.tsx # 网格背景
├── cobe.tsx # 全球地球仪 (可选)
└── [...其他 UI 组件]
4. features/ - 功能模块
features/
├── navigation/ # 导航功能
│ ├── navbar/
│ └── sidebar/
├── auth/ # 认证功能
│ ├── login/
│ ├── signup/
│ └── password-reset/
├── admin/ # 管理后台功能
│ ├── user-management/
│ ├── subscription-management/
│ └── analytics/
├── billing/ # 计费功能
│ ├── pricing-table/
│ └── checkout/
└── ai/ # AI 功能
├── chat/
├── image-generation/
└── video-generation/
5. constants/ - 常量定义
constants/
├── website.ts # 网站配置
│ ├── WEBSITE_NAME
│ ├── WEBSITE_DESCRIPTION
│ ├── SOCIAL_LINKS
│ └── ANALYTICS_CONFIG
├── billing.ts # 定价和积分配置
│ ├── PRICING_PLANS
│ ├── CREDIT_COSTS
│ └── SUBSCRIPTIONS
├── tier.ts # 用户等级定义
└── routes.ts # 路由定义
6. messages/ - 国际化翻译
messages/
├── en/
│ ├── common.json # 通用翻译
│ ├── nav.json # 导航翻译
│ ├── forms.json # 表单翻译
│ ├── seo.json # SEO 元数据
│ └── [...其他页面翻译]
├── zh/
│ ├── common.json
│ ├── nav.json
│ ├── forms.json
│ ├── seo.json
│ └── [...其他页面翻译]
└── i18n.config.ts # i18n 配置
7. 其他目录
content/
├── blog/ # 博客文章 (MDX)
│ ├── article-1/
│ │ ├── en.mdx
│ │ ├── zh.mdx
│ │ └── thumbnail.jpeg
│ └── [...更多文章]
└── docs/ # 文档 (可选)
public/
├── og/ # OG 图像
├── avatars/ # 头像
└── [其他静态资源]
emails/
├── verify-email.tsx # 验证邮件模板
├── reset-password.tsx # 重置密码模板
└── [...其他邮件模板]
scripts/
├── setup-admin.ts # 创建管理员脚本
└── generate-blog.mjs # 生成博客清单脚本
drizzle/
└── [日期]_xxxxx.sql # 数据库迁移文件
关键配置文件
middleware.ts - 国际化和路由保护
import createMiddleware from 'next-intl/middleware';
import { locales, defaultLocale } from './i18n.config';
export default createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed'
});
export const config = {
matcher: ['/', '/((?!api|_next|_vercel|.*\\..*).*)',]
};
i18n.config.ts - 国际化配置
export const locales = ['en', 'zh'] as const;
export const defaultLocale = 'en' as const;
export type Locale = (typeof locales)[number];
export const pathnames = {
'/': '/',
'/about': {
en: '/about',
zh: '/about',
},
'/blog': {
en: '/blog',
zh: '/blog',
},
// ...
};
routes.ts - 路由定义
export const routes = {
home: '/',
dashboard: '/dashboard',
blog: '/blog',
pricing: '/pricing',
login: '/login',
signup: '/signup',
admin: '/admin',
profile: '/profile',
};
代码组织最佳实践
1. 单一职责原则
每个文件应只做一件事:
// ✅ 好: 专注的 hook
export function useCredits(userId: string) {
// 仅处理积分逻辑
}
// ❌ 避免: 混合多个职责
export function useCreditsAndAuth(userId: string) {
// 混合了积分和认证逻辑
}
2. 导出约定
使用 barrel exports 简化导入:
// components/index.ts
export { Button } from './button';
export { Card, CardContent } from './card';
export { Navbar } from './navbar';
// 使用
import { Button, Card, Navbar } from '@/components';
3. 路由保护
使用 middleware 和布局保护:
// app/[locale]/(protected)/layout.tsx
import { requireAuth } from '@/lib/auth';
export default async function ProtectedLayout({ children }) {
await requireAuth(); // 自动重定向未认证用户
return <>{children}</>;
}
4. 服务端 vs 客户端
标记客户端组件:
'use client'; // 必须在文件顶部
import { useTheme } from 'next-themes';
export function ThemeSwitcher() {
const { theme, setTheme } = useTheme();
// ...
}
依赖关系图
app/
├─ 使用 → lib/ (业务逻辑)
│ ├─ 使用 → lib/db/ (数据库)
│ ├─ 使用 → lib/auth/ (认证)
│ └─ 使用 → lib/payments/ (支付)
│
├─ 使用 → components/ (UI)
│ └─ 使用 → constants/ (配置)
│
├─ 使用 → features/ (功能)
│ └─ 使用 → components/
│
└─ 使用 → messages/ (翻译)
└─ 使用 → i18n/
lib/
└─ 不依赖 app/ 或 components/ (解耦)
常见问题
1. 如何添加新功能模块?
1. 在 features/ 下创建新文件夹
features/my-feature/
├── index.ts
├── component.tsx
└── hook.ts
2. 创建 app/ 路由
app/[locale]/(protected)/my-feature/page.tsx
3. 添加 lib/ 支持
lib/my-feature.ts (业务逻辑)
2. 如何共享状态?
// 使用 Context API (轻量)
context/my-context.tsx
// 或使用 Zustand (复杂状态)
store/my-store.ts
3. 如何处理跨路由状态?
// 存储在 lib/ 并通过 prop drilling
// 或使用 URL 查询参数
// 或使用 Cookie (持久化)