生产运维
安全执行预检、迁移、订阅积分定时发放、Webhook 回放和版本升级。
保障生产安全的前提,是明确每条命令能够证明什么。预检、数据库迁移、应用验证和端到端验收彼此独立。
预检内容
运行下面的命令,查看便于阅读的报告:
npm run preflight自动化流程可以获取内容相同、敏感信息已脱敏的 JSON 报告:
npm run --silent preflight -- --json预检会检查:
DATABASE_URL、BETTER_AUTH_SECRET,以及不指向 localhost 的NEXT_PUBLIC_SITE_URL- 每项已启用能力的配置完整性,包括支付、Google OAuth 和 One Tap、AI 图片生成、Turnstile、对象存储与邮件投递
- 实时 PostgreSQL 连接
- 会阻止已提交唯一索引落地的重复订阅、积分来源和 Webhook 事件记录
- 整个仓库的 TypeScript 编译
报告会隐藏密钥值,以及常见连接字符串中嵌入的凭据。
预检不会执行迁移、检查源码格式、运行测试或构建应用。npm run validate 的范围也小于完整门禁:它只运行 Starter 当前的文档校验、i18n 校验和源码 lint。
发布前,请运行与本次改动相匹配、等同仓库 CI 的检查,包括类型检查、单元与集成测试、lint 和生产构建。依赖支付服务商的验收还必须包含真实 HTTPS Webhook、测试支付和数据库回读。
数据库变更只能使用迁移
任何环境都禁止直接推送数据库结构:
npm run db:push该命令会有意报错退出。请改用以下流程:
# Edit src/lib/db/schema.ts
npm run db:generate
# Review and commit the new drizzle/*.sql and drizzle/meta changes
npm run db:migrate生产迁移执行器会:
- 在需要时创建
app_migrations追踪表; - 直接读取
drizzle/下已提交的.sql文件; - 按文件名字典序执行尚未应用的文件;
- 在同一个 PostgreSQL 事务中执行每个 SQL 文件并写入追踪记录;
- 遇到追踪、SQL 或连接失败时立即停止。
执行器不支持向下迁移,也不提供分布式迁移锁。请备份重要数据,先在非生产数据库测试,同一时间只允许一个迁移进程操作同一个数据库。需要回滚时,请使用前向修复迁移或经过验证的数据库恢复方案。迁移文件名一旦被记录为已应用,绝不能再修改该文件。
Drizzle journal 用于记录生成与审查历史;生产迁移执行器则根据 SQL 文件名和 app_migrations 决定执行内容。
订阅积分调度器
Vercel 会按已提交的计划调用以下路由:
5 0 * * *
GET /api/cron/subscription-credits任务每天 00:05 UTC 运行,但它不会每天发放积分。它会查找独立保存的月度发放边界已经到期的订阅,并发放配置好的月度积分。
只要配置了订阅产品,就应设置高强度且仅服务端可见的 CRON_SECRET。Vercel 会以如下形式发送:
Authorization: Bearer <CRON_SECRET>路由行为:
| 结果 | 状态 |
|---|---|
缺少 CRON_SECRET | 503 |
| 缺少 Bearer token 或 token 错误 | 401 |
| 发放处理失败 | 500 |
| 运行成功 | 200,并返回发放与订阅数量 |
月度发放以订阅周期为锚点,使用与服务商无关的幂等来源,并在下一个发放边界或订阅周期结束时过期。任务延迟时可以补发多个边界,但每个订阅单次运行最多补发 24 次。发票类 Webhook 只更新计费状态,不会直接发放这些按月调度的积分。
运行结束后,检查函数日志,并回读受影响的 subscriptions 和 credit_transactions 数据行。如果没有积分到期,200 且发放数为零是正常结果。
支付 Webhook 运维
Stripe 和 Creem 共用一个应用端点:
POST /api/payments/webhook对于新的 Webhook 流量,当前 PAYMENTS_PROVIDER 决定使用哪个签名验证器。处理器会验证未经修改的请求体、标准化服务商事件,并在应用计费变更前把投递身份写入 webhook_inbox。
系统按服务商加事件 ID 或载荷哈希去重。成功处理过的事件再次投递时,会返回 200 和 deduped: true。处理时会为每条事件占用两分钟处理租约;处理器失败时会尽可能释放租约,尚未处理且已经过期的租约可以由后续投递重新取得。
| 响应 | 含义 |
|---|---|
200, deduped: false | 投递已接收并处理 |
200, deduped: true | 投递已处理,或当前由另一次尝试持有 |
400 | 缺少签名或签名无效 |
503 | 所选服务商配置不完整 |
500 | 验签成功,但应用处理失败 |
回放失败事件时:
- 确认端点和当前服务商与发送方一致。
- 确认签名密钥属于这个准确的端点和测试模式或生产模式。
- 从服务商控制台或开发 CLI 回放,不要修改事件载荷。
- 检查 HTTP 响应和应用日志。
- 回读
webhook_inbox,以及相关的subscriptions、orders或credit_transactions数据行。
在本地转发 Stripe 事件:
stripe listen --forward-to localhost:3000/api/payments/webhook本地监听器输出的签名密钥只能用于对应的本地环境。
升级 Starter
package.json 是已安装版本的权威来源。升级经过定制的项目时,请谨慎操作:
- 阅读跨越的每个版本的 changelog。
- 提交或备份应用代码和数据库数据。
- 在独立分支应用版本改动,不要直接覆盖定制文件。
- 使用已提交的锁文件运行
npm ci。 - 审查每一个新增 SQL 迁移和 Drizzle journal 记录。
- 数据库变更只能通过
npm run db:migrate执行。 - 运行
npm run starter:check和覆盖本次修改的测试。 - 先部署并验证非生产环境,再进入生产环境。
跨过主版本或修改过购买的源码,都可能需要手动集成。Starter 不会自动把上游改动合并到定制应用中。