配置
让每个文件只负责一种运行环境或一类配置,可以降低仓库维护成本。
文件职责表
| 文件 | 负责 | 不负责 |
|---|---|---|
.env.local | local-app 的应用/本地密钥与运行时值 | Wrangler 专用本地变量、预览/生产租户身份 |
.dev.vars.dev | local-worker 的本地 Wrangler 变量 | app 环境默认值、预览/生产密钥 |
.env.cloudflare / .env.cloudflare.preview | 远端辅助程序、seed 与 Cloudflare API 凭据 | 提交到仓库的部署身份 |
wrangler.toml | 受版本控制的模板安全基线与本地开发配置 | 私有预览/生产租户 ID 和路由 |
wrangler.remote.toml | 私有预览/生产 Cloudflare 租户配置 | 仅本地开发的默认值 |
从仓库中的 wrangler.remote.example.toml 创建 wrangler.remote.toml。
应用组合
src/config/product.ts 拥有可安全用于客户端的品牌信息与显式能力选择。SaaS 基础模板没有默认示例业务或组织模块。
capabilities: {
docs: true, blog: true,
...productCompositions.core, // or productCompositions["personal-paid"]
feedbackAttachments: false,
analyticsClient: false, analyticsServer: false, devReview: false,
}| 组合 | 新购买 | 所需能力 |
|---|---|---|
core | 关闭 | 认证与已初始化数据库;基本资料和后台管理 |
personal-paid | 真实结账 | 核心能力,加受支持的 Stripe 配置及已发布的产品/报价版本 |
随附配置选择真实结账。供应商或目录配置缺失时仍不可用。live 允许现有 Stripe 流程使用测试或真实凭据,但不能证明支付或生产就绪。demo 不能用于真实购买,也不会授予访问权限。
新购买需要可信 APP_URL、受支持的 STRIPE_SECRET_KEY、PAYMENT_PROVIDER=stripe、同源返回路径与准确的已发布报价版本。配置 STRIPE_WEBHOOK_SECRET 以接收签名回执。结账为 off 时,/pricing 返回 404,新结账命令被拒绝;/me/billing 保留已有购买、原尝试恢复与受支持的账单管理。只要这些义务仍存在,就应保留供应商配置。
客户从 /me 查看基本资料和修改已有密码。注册与登录默认进入该账户页。模板不再公开 Bookmark、Decision Log、组织协作、工具仪表盘、客户收件箱、API 凭据、导出、用量或偏好中心。源码退场不会清除历史数据库记录。
选择能力不等于授权。按业务集成指南添加真实领域;其命令和查询必须执行当前身份与资源归属检查。Docs、Blog 和分析仍独立选择。
条款、隐私与支持链接
在 src/config/product.ts 的 brand.links 中设置可选目的地址:
links: {
terms: null,
privacy: null,
support: null,
repository: null,
docsRepositoryBase: null,
}只有具备要发布的目的地址时才替换 null。使用 /policies/terms 这样的本地绝对路径,或 https://help.your-domain.com/support 这样的无凭据 HTTPS URL。允许本地查询参数和片段。相对路径、协议相对 URL、HTTP、可执行 scheme、内嵌凭据、错误转义、空白与控制字符,会在配置加载或构建时被拒绝。这些是公开源码值,绝不能放入访问令牌或私有 URL。修改后重新构建;无需新增环境变量。
已配置入口会一致出现在主站页脚、文档页脚及登录/注册信息链接中。未设置的入口保持隐藏,空页脚或导航也不显示。链接在当前标签页打开;外部链接不发送来源页面信息。模板不创建目的页面或探测其可用性。请发布并维护自己的文档与支持入口。
这些链接只提供信息,不增加接受复选框、不记录同意、不改变认证,也不证明政策在法律上充分或已被用户接受。
可选内容模块
在 src/config/product.ts 设置 capabilities.docs 与 capabilities.blog,然后重新构建并启动应用。两者默认均为 true。
| 选择 | 应用行为 |
|---|---|
| 关闭 Docs | 隐藏导航,/docs 及下级文档路由返回未找到 |
| 关闭 Blog | 隐藏导航与编辑路由;公开列表/详情返回未找到,编辑 Actions 返回不可用,不注册 Blog 刷新任务 |
| 启用 Blog,未配置 CMS | 随附 MDX 与已配置的数据库发布内容可用;不加载外部 CMS 来源 |
| 启用 Blog,CMS 输入不全 | 系统诊断指出缺失输入名,该来源报告不可用,其他内容仍可使用 |
Notion 需要 NOTION_TOKEN 与 NOTION_DATABASE_ID;Sanity 需要 SANITY_PROJECT_ID 与 SANITY_DATASET,可选 SANITY_READ_TOKEN。Blog 关闭时忽略残留 CMS 凭据。配置允许初始化,不能证明连通性。编辑操作始终检查当前管理员权限。停用模块会保留已存内容与构建依赖。
带类型的环境变量层
应用运行时值由 @t3-oss/env-nextjs 验证。标准类型入口是 src/env.ts,它组合 src/env/* 下的领域 schema。
新增变量通常按以下流程:
- 在
src/env/下正确的 schema 文件中添加变量。 - 通过
src/env.ts重新导出。 - 确定默认应由哪个配置文件保存值。
- 更新对应示例文件。
只有需要直接访问进程环境的地方(如 CLI 脚本或运行时桥接)才直接使用 process.env。
local-app 示例
APP_URL="http://localhost:3101"
AUTH_SECRET="replace-me-with-a-local-secret"
DATABASE_URL="file:./dev.db"
XADMIN_SECRET="replace-me-for-local-seeding"这是标准 Next.js + Playwright 开发环境。
local-worker 示例
将 .dev.vars.example 复制为 .dev.vars.dev,本地 Wrangler 地址保持使用端口 8787:
APP_URL="http://localhost:8787"
AUTH_SECRET="replace-me-with-a-local-worker-secret"
XADMIN_SECRET="replace-me-for-local-worker-seeding"
CRON_SECRET="replace-me-for-local-worker-cron"
TRIGGER_SECRET="replace-me-for-local-worker-triggers"即使同时在本地使用 Wrangler,.env.local 仍只用于 app 环境。
远端辅助配置示例
生产辅助流程使用 .env.cloudflare,预览辅助流程使用 .env.cloudflare.preview:
CLOUDFLARE_API_TOKEN="replace-me-with-api-token"
CLOUDFLARE_D1_TOKEN="replace-me-with-d1-or-api-token"
APP_URL="https://your-app.example.com"
XADMIN_SECRET="replace-me-with-remote-admin-secret"这些文件存放辅助凭据与远端脚本输入,不应存放预览或生产的账户 ID、路由或绑定 ID。
Cloudflare 配置文件
wrangler.toml- 受版本控制
- 模板安全基线
- 本地开发默认值
wrangler.remote.toml- 不纳入版本控制
- 私有预览与生产租户身份
- 从
wrangler.remote.example.toml创建
不要将真实预览或生产租户 ID 直接写入受版本控制的 wrangler.toml。
端口与地址
local-app:http://localhost:3101local-worker:http://localhost:8787remote-cloudflare:私有远端配置中指定的域名或路由
明确区分各环境地址,不要让三个环境复用同一个 APP_URL。
常用可选环境变量组
账户与商业能力
从 /me 与选定的管理员路由开始。基本资料和密码流程不需要商业报价。Auth 拥有账户身份;Payments 拥有已发布产品、不可变报价版本、已确认支付事实与个人账单。目录标签或返回 URL 不会授予业务访问权限。
付费业务操作必须通过明确的领域权益策略与真实调用方接入。基础模板没有默认 Bookmark 或 Decision 规则。已有购买身份与账单恢复独立于新销售,仍然有效。
OAuth 供应商
AUTH_GITHUB_ID="your-github-client-id"
AUTH_GITHUB_SECRET="your-github-client-secret"
AUTH_GOOGLE_ID="your-google-client-id"
AUTH_GOOGLE_SECRET="your-google-client-secret"
AUTH_DISCORD_ID="your-discord-client-id"
AUTH_DISCORD_SECRET="your-discord-client-secret"支付
PAYMENT_PROVIDER="mock"
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..."邮件
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="smtp-user"
SMTP_PASS="smtp-pass"
SMTP_FROM="Product <no-reply@example.com>"分析
浏览器分析默认关闭。构建时设置 NEXT_PUBLIC_ANALYTICS_ENABLED="true" 与供应商 key,无需修改源码。显式 false 同时关闭 GA4 与 PostHog。未设置或为空时,沿用 src/config/product.ts 的 capabilities.analyticsClient(模板默认为 false)。
Google Analytics 4 配置:
NEXT_PUBLIC_ANALYTICS_ENABLED="true"
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID="G-XXXXXXXXXX"创建 GA4 网站数据流,使用其衡量 ID,而不是 GTM 或 Universal Analytics ID。关闭该数据流的增强型衡量:应用在首次加载与每次 pathname 变化时发送一次页面浏览。页面 URL 与来源信息不带 query/hash,标题使用 pathname。修改任一公开值后,重新构建并部署;本地开发则重启。仅运行时 Worker secret 无法改变已构建的浏览器包。部署后在 GA 实时报告中验证接收。
PostHog 可选且独立,可替代 GA4 或与其同时配置:
NEXT_PUBLIC_POSTHOG_KEY="phc_..."
NEXT_PUBLIC_POSTHOG_HOST="https://app.posthog.com"服务端认证事件使用现有 PostHog 选择 capabilities.analyticsServer=true,以及以下仅服务端输入:
POSTHOG_API_KEY="phc_..."
POSTHOG_HOST="https://app.posthog.com"浏览器页面浏览只包含 origin 与路径,排除查询参数、片段、来源页面及自动营销归因;会话回放和自动采集已禁用。缺少 key 或 host 无效时,所选能力保持不可用。修改配置后重启本地应用;公开配置改变时重新构建部署。
Google 登录与 Search Console
数据库和部署初始化后,可与上述分析配置一并设置:
APP_URL="https://www.your-company.com"
AUTH_SECRET="your-stable-random-secret"
AUTH_TRUST_HOST="1"
AUTH_GOOGLE_ID="your-client-id.apps.googleusercontent.com"
AUTH_GOOGLE_SECRET="your-client-secret"
GOOGLE_SITE_VERIFICATION="your-meta-content-token"本地应用使用 .env.local。生产环境将公开值提供给 Next 构建,将服务端凭据提供给运行时;生产构建校验也需要 AUTH_SECRET。构建与运行时的 APP_URL、GOOGLE_SITE_VERIFICATION 应保持一致,修改后重新构建,保持编译配置与运行时一致。Docs 按请求解析语言。保留已有认证密钥;新部署可用 openssl rand -base64 32 生成。只对自己控制的部署入口启用 Trust Host。安装与部署步骤初始化 SQLite 或 D1 DB 及 Worker KV;Google 配置不会创建这些资源。
- **Google 登录:**在 Google Auth Platform 创建 OAuth Web 应用。注册准确的重定向 URI
https://your-domain/api/auth/callback/google;本地使用准确主机与端口,如http://localhost:3101/api/auth/callback/google。按该 Google 项目要求配置受众与测试用户。两项凭据会启用已有登录和注册按钮,不需改动 UI 或认证源码。供应商账户关联规则仍然适用。 - Search Console:创建匹配
APP_URL的 URL 前缀资源,选择 HTML 标签验证,只填写标签的content值。部署并完成验证后,提交https://your-domain/sitemap.xml。网域资源需要 DNS TXT 验证,不能用此 meta 标签替代。保留所用验证方式。
GA4、Google OAuth 与 Search Console 使用不同标识符。部署后,用自己的 Google 账户检查登录,检查响应 HTML 中的验证 meta 标签与 /sitemap.xml;本地测试不能证明 Google 已接受配置或完成索引。
应避免的配置方式
- 常规本地开发不要用通用
.env流程替代.env.local。 - 不要将本地 Wrangler 变量放入
.env.local。 - 不要将远端租户身份存入受版本控制的
wrangler.toml。 - 不要将
.env.cloudflare*当作部署身份文件。
数据库说明
修改 schema 后,生成并审阅 SQL,再将完整迁移链应用到受保护的 local-app 数据库:
npm run db:generate
npm run db:push远端 D1 使用显式迁移发布流程。这里的 db:push 是 local-app 命令,不发布远端结构。
下一步
完成配置后,可继续阅读:
公开发现与规范地址
将 APP_URL 设为站点 HTTPS origin,例如 https://www.your-company.com,不要包含凭据、路径、查询参数或片段。生产发现拒绝 loopback 与保留的 example/test/invalid 主机。本地开发接受显式配置的 loopback HTTP origin,如 http://127.0.0.1:3101;请求 Host 与转发头永远不决定规范地址。构建与运行时保持 APP_URL 一致,修改后重新构建:发现过程使用可信配置值,Docs 按请求解析语言。
/sitemap.xml 在构建时自动发现公开 App Router 页面文件,包括定价页及选中的 Docs/Blog 页面。新增普通页面后部署即可,无需维护 URL 列表。动态 /blog/[slug] 地址在请求时从当前公开文章展开。其他动态领域每个领域需要一个公开数据 reader,而非每个 URL 一条记录;未解析占位符不会输出。新增私有区域必须加入 src/config/sitemap-policy.ts 的集中排除项。/robots.txt 声明 sitemap,并建议爬虫不要抓取账户、运营与已停用内容路由。Robots 仅提供建议,私有页面仍由认证和授权保护。在 src/config/product.ts 关闭 Blog 或 Docs 后,发现过程不初始化该模块的 reader 或供应商。
生产快照使用已有 SQLite 缓存或 Worker KV,最长一小时。每次请求检查当前 Blog 发布版本,因此发布或撤回文章会立即改变缓存键。过期条目在下次请求时重新生成,无需额外 cron 或 sitemap 环境设置。源码 MDX 变化仍需构建。Google 自行决定何时抓取与索引这些 URL。
APP_URL 缺失或不安全时,保留页面文字 metadata,省略规范/分享 URL,并请求不索引。Robots 禁止抓取且不提供 sitemap 地址;sitemap 请求返回错误。格式错误的 URL 可能在应用提供服务前就使环境校验失败。向爬虫开放前应修复配置。已配置内容来源失败时,sitemap 也失败,不发布不完整列表;有意为空的来源仍有效。
当前单个 sitemap 最多支持 10,000 个不同 URL,每个最长 2,048 字符。若转义后的 UTF-8 大小加保守 XML 标记余量超过 50 MiB,也会被拒绝。超过限制时明确失败。它复用已有完整 Blog 列表与来源限制,包括 Notion 单页限制,不增加搜索服务或分页框架。不输出虚构修改时间。手工恢复或导入旧发布代次后,清除 public-sitemap 缓存,或使用新 build ID 重建。
数据库文章的保存草稿保留已发布标题、地址、描述和分享图片。发布已保存草稿选择新值;撤回、归档、删除或发布非公开受众都会使文章退出公开发现。Meta Description 回退到摘要或标题;Cover Image URL 提供可选分享图片。外部 CMS 卡片保留外部目的地址,不作为本地文章页发布。
语言与隐私就绪情况
应用共用一套路由和组件,提供英文与简体中文界面消息。Blog 与 Docs 使用明确的 /en/...、/zh-CN/... 内容地址,独立维护完整版本。随附的全部八篇 Docs 与三篇 Blog 均有完整英中版本。没有已发布译文的内容提供英文阅读链接。
NEXT_PUBLIC_ANALYTICS_ENABLED 只选择可选集成,不授权采集。先在 src/privacy/config.ts 中填写真实的双语发布主体、联系方式、处理、保留与翻译审阅字段;设备必须显式保存同意选择后,符合条件的分析服务才会加载。没有符合条件的可选服务时不显示横幅。阅读 /privacy 与 /cookies,使用页脚隐私设置查看或撤回选择。缺少所需当前主体、用途与权限时,服务端分析不发送事件。不要编造运营方资料来制造模板已就绪的假象。