项目结构

Next.js 模板的目录组织方式。

该模板是一个 Next.js 16 App Router 项目。路由位于 src/app/[locale] 之下,按受众分组,API 处理器放在 src/app/api。其余内容(组件、配置、库、 国际化、内容)都在 src/ 中并列存放。

顶层结构

proxy.ts
source.config.ts

路由分组

每个页面都嵌套在 src/app/[locale] 下,因此整棵树都能拿到当前语言(见 国际化)。在它内部,路由分组(name) 文件夹,不会增加 URL 段)按受众拆分应用并共享布局:

分组URL 前缀包含内容
(marketing)/落地页、博客、法律、关于、联系、AI 演示、支付成功
(dashboard)/dashboard/admin/setting/account已登录的应用界面
(docs)/docs由 Fumadocs 渲染的文档
auth/auth/*登录、注册、忘记/重置密码、确认

auth 是一个普通文件夹,而非路由分组,因此其页面位于 /auth/login/auth/register 等路径。只有 (marketing)(dashboard)(docs) 使用带括号的分组语法。

动态内容位于通配与动态段之后:文档通过 (docs)/docs/[[...slug]] 渲染, 博客/法律页面则从 content/ 中的 MDX 解析各自的 slug。

API 路由

服务端处理器位于 src/app/api,按职责分组:

路由用途
api/auth/[...all]Better Auth 通配处理器
api/user/{profile,settings,subscription,billing}已登录用户数据
api/admin/users受角色保护的管理员用户管理
api/payment/{create,query,notify/creem}Creem 结账 + 签名 Webhook
api/storage/upload-image已鉴权的图片上传
api/ai/{image,audio,video}(含 /queryReplicate 生成 + 轮询
api/chatOpenAI 流式聊天(Vercel AI SDK)
api/contact联系表单邮件

鉴权、校验与响应结构是按路由各自实现的,并非全局强制——不同处理器之间 模式各异。依赖某个守卫前请先阅读对应路由。例如 /admin/usersAPI 会校验管理员角色,但 proxy.ts 中的页面级保护只验证会话 Cookie。

支撑目录

目录作用
src/componentsUI 基础组件(ui/)、功能、布局与动效组件
src/config应用配置(站点、页脚、路由、定价、侧边栏)
src/lib服务端逻辑:authdbemailpaymentaisourceutils
src/i18nnext-intl 路由、请求、导航
messages翻译文件(en.jsonzh.json
content文档、博客与法律页面的 MDX
public静态资源(以及运行时 uploads/,见 存储

请求流程:src/proxy.ts

模板使用 Next.js 16 的 proxy.ts(即重命名后的 middleware.ts),在每个 非 API 请求上完成两件事:

  1. 语言处理——运行 next-intl 中间件以检测并加上语言前缀。
  2. 受保护路径重定向——对 /dashboard/admin/setting/account, 检查 Better Auth 会话 Cookie,缺失时重定向到 /auth/login?callbackUrl=…
src/proxy.ts
const protectedPaths = ["/dashboard", "/admin", "/setting", "/account"];
// ...
export const config = {
  matcher: ["/((?!api|_next|_vercel|.*\\..*).*)"],
};

这个 Cookie 检查是针对未登录流量的重定向,而不是授权边界。它不会校验 会话或用户角色——务必在返回敏感数据的 API 路由或服务端组件内部重新校验 会话(以及角色)。

内容与生成源

文档、博客与法律内容是在 source.config.ts(Fumadocs MDX)中定义的 MDX 集合, 通过 src/lib/source.ts 加载。Fumadocs 会在构建时生成 .source/ 目录——它 由 content/ 重新生成,请勿手动编辑。

需要了解的 Next.js 16 约定

  • 默认是服务端组件。 除非文件以 "use client" 开头,否则即为 RSC。 请把数据获取与密钥保留在服务端。
  • 异步请求 API。 paramssearchParamsheaders()cookies() 需要 await(例如 const { locale } = await params)。
  • React Compiler 已启用,因此很少需要手动写 useMemo/useCallback

相关页面

On this page