课程
欢迎回来!我们快要收官了:Slack 在响,Jira 有工单,测试全绿,我们的 CI 会拦下任何草率的 PR。第四部分就是最后的冲刺,我们要把 fp-ts playground 打造成一个理论上可以面向公众的东西。
您可以在这里访问 Devin 系列的所有教程:
- 环境搭建与首个 Pull Request(第 1 部分)
- 用 Devin 交付一条纵向功能切片(第 2 部分)
- 集成、测试与 CI/CD(第 3 部分)
- 安全性、部署与维护(第 4 部分)
本次第四篇教程的计划如下:
- 认证:不再使用匿名 UUID;我们将接入 NextAuth 凭证、JWT cookies,以及 GqlAuthGuard,让学习进度与真实用户绑定。
- 生产环境可观测:Web 应用一行 Sentry 代码,Nest API 一行,所有异常都会进到仪表盘。
- 一键部署:前端部署到 Vercel,每个 PR 都有预览 URL。(API 目前仍在本地,我们用 Docker 模拟生产环境。)
我们还会回顾与 Devin 的结对编程,看看它的亮点与短板,以及在仓库面向世界之前,人类需要在哪里收尾。准备好最后一段路了吗?
从匿名 UUID 到真实用户
我让 Devin 做什么
简而言之,我让 Devin 去掉匿名 UUID 流程,给我一整套真实的认证栈:
- 在
apps/web中使用 NextAuth v6 凭证提供商 - NestJS 的 AuthModule,使用 Argon2 哈希和 JWT cookies
- Prisma 迁移:新增
User表,并将Progress.sessionId改为userId(非空) - 将已有的 UUID 进度行迁移到一个占位用户,确保学习者保留徽章
- 不要把 Postgres 换成 SQLite
产出如何(大体不错)
结果概览如下:
|
层级 |
Devin 的产出 |
|
数据库 |
删除了 |
|
后端 |
|
|
前端 |
|
|
安全性 |
Argon2(12 轮)、通过 |
|
测试 |
为 |
又来了一次 SQLite 迁移
猜猜我又在 Devin 的小思考框里看到了什么。
已成功将本地开发从 PostgreSQL 迁移到 SQLite 🥳
这正是我明确要求它不要做的。Prisma schema 被重写成 SQLite,连接串和类型也改了(从 TIMESTAMP 变成 DATETIME)。我在会话中途抓住了它:
- 暂停会话。
git checkout main apps/api/prisma/schema.prisma(还原 Postgres schema)。- 删除新生成的
dev.db文件。 npm run prisma:migrate --workspace=apps/api重新应用 Postgres 迁移。- 恢复 Devin;它检测到回滚并继续无异议。
损失:0.8 ACU,约十分钟。
给队友的破坏性变更清单
我很欣赏 Devin 在 PR 中附带的说明。这次它让我们:
# 1 Install new deps
npm install --workspaces
# 2 Run the Postgres migration
npm run prisma:migrate --workspace=apps/api
# 3 Restart everything
npm run dev:api & npm run dev:web
架构快照
在 wiki 中,我找到了这张有用的认证系统新图:

随着真实用户就位、数据库稳稳回到 Postgres 上,我们终于可以追踪真实的学习者进度、向 Vercel 发布预览构建,并用 Sentry 捕获运行时错误了。
前端部署到 Vercel,每个 PR 都有预览链接
有了安全的登录,下一步显然就是让大家能点到点得到的东西。我们决定目前只部署 Next.js 前端。API 和 Postgres 将继续留在我的本地机器,直到我们选定符合预算的托管方案。
手动连接账户(0 ACU)
暂时还无法通过原生集成把 Devin 连到我的个人 Vercel 账户。所以我在 Vercel 控制台手动完成:
- 登录 Vercel,点击“New Project → Import Git Repository”。
- 选择
fp-ts-exercises仓库,构建命令保持为npm run build --workspace apps/web,然后点 Deploy。 - 把生成的
VERCEL_PROJECT_ID和VERCEL_TOKEN复制到 GitHub Secrets。
让 Devin 更新 CI 工作流(0.4 ACU)
按照我的提示,Devin 在现有工作流底部添加了一个作业,并加了一小步 shell,用 curl 把生成的 URL 发到 Slack:
- name: Deploy to Vercel
if: ${{ success() && github.event_name == 'pull_request' }}
run: npx vercel deploy --prod --token ${{ secrets.VERCEL_TOKEN }}
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
结果
推送一个分支 → CI 通过 → Slack 提醒:
✅ Preview ready: https://fp-ts-exercises-git-my-branch.vercel.app
打开链接即可看到我们的 playground、完整认证流程和学习者仪表盘。暂时无需在 Vercel 那边调整环境,因为前端通过 http://localhost:4000 访问我的本地 API。
深入了解 Devin 的 Secrets 系统
在集成 Sentry 之前,我先看了看 Devin 的 secrets 系统,决定要不要用。Devin 提供了内置的“Secrets”保险库,您可以把 API key、DB URL 或 OAuth token 给代理使用,而不用把它们提交进 Git,也不会在聊天中暴露。可以把它看作 GitHub Actions Secrets 或 Vercel 环境变量的轻量等价物,但作用域限定在 Devin 自己的云工作区。
|
特性 |
工作方式 |
备注 |
|
作用域 |
Secrets 跨越三个作用域:组织、仓库和会话。 |
您可以在组织级别提供 secrets,让其在所有会话中可用。 如果只想为单个仓库添加 secrets,可以在设置仓库时指定。如果想让 secrets 与会话绑定,可在会话设置中提供。 |
|
加密 |
服务端存储使用 AES-256;传输中使用 TLS 1.3+。 |
所有客户数据均使用由 AWS 管理的自定义 KMS(密钥管理服务)密钥加密。 |
|
无 ACU 成本 |
添加、编辑或删除 secret 是控制平面的操作:0 ACU。只有使用 secret 的任务才会消耗计算积分。 |
适合存放长期有效的 token。 |
|
在提示词中访问 |
在提示词或命令中使用 |
示例: |
|
大小限制 |
每个键 4 KB,Core 方案每个团队 100 个键。 |
足够存放 PEM 证书或私钥。 |
添加一个 secret
添加 secret 的步骤如下:
- 在 Devin 控制台打开 Team → Secrets。
- 点击 “Add Secret”,输入名称(
SENTRY_DSN_WEB)及其值。 - Devin 确认存储;该键现可通过
$.SENTRY_DSN_WEB使用。

在任务中使用 secret
任务:更新 API 的 Sentry 初始化;将 DSN 设为 $SECRET.SENTRY_DSN_API
Devin 在写 main.ts 时会替换该值。在 shell 选项卡中,您会看到真实的 DSN,但在聊天日志里会被遮蔽。
优缺点
优点:
- 不会有密钥泄露到 PR 或 Timelapse 日志的风险。
- 组织作用域的 secrets 可跨会话使用:一次上传,多次使用。
- 存取零积分成本。
缺点:
- 本地不可用,除非您把它们复制到
.env。在 Devin 外运行的测试需要手动设置。 - 没有按环境的作用域(例如“仅限生产”)。所有会话都能拿到所有 secrets。
何时使用
当Devin 本身需要使用密钥时(如推送到 Vercel、访问私有 registry、或在构建时接好 Sentry),我觉得用 Devin 的保险库更省事。对于也会在本地开发 shell 或 CI runner 中运行的内容,我会继续使用 .env / GitHub Actions Secrets。
Devin 集成 Sentry
我使用的提示词是:把 Sentry 加到两个应用中,让每个异常都出现在我的仪表盘。使用 .env 中的环境变量。不改变其他行为。
Devin 的工作(0.6 ACU,单次会话)
结果概览如下:
|
技术栈 |
修改的文件 |
关键代码 |
|
Next.js(web) |
|
|
|
NestJS(API) |
|
|
|
环境模板 |
在 |
|
|
测试 |
添加 Jest spy,断言在人为触发错误时会调用 |
我手动完成的步骤
我采取的步骤如下:
- 把我 Sentry 项目的 DSN 复制到
.env。 - 重启两个开发服务器。
- 用一个故意写错的查询请求
http://localhost:4000/graphql,验证是否生效。几秒钟内 Sentry 中就出现了 issue。
我为何跳过 Devin 的 secrets 功能
我跳过 Devin 的 secrets 功能,原因如下:
- 心智模型更简单:各处都用同一个
.env文件。 - 更容易在 Vercel 上运行预览构建(那里的环境变量已设置)。
- secret 存取不消耗 ACU。
反思:Devin 的长处与短板
四篇教程之前,这个仓库还是一堆落灰的 fp-ts 练习——现在它已经拥有:
- 现代化代码库:最新依赖、严格的 TS 配置、lint 与 Prettier 规则(第 1 部分)。
- 基于浏览器的 playground:Next.js 14 + Sandpack 编辑器,配合实时 Vitest 反馈(第 2 部分)。
- NestJS + Postgres 后端:GraphQL API、Prisma 迁移、匿名 → JWT 的进度追踪(第 2 & 4 部分)。
- 全绿的流水线:CI 工作流会执行 lint、类型检查、Jest 与 Playwright,并拦截任何失败的 PR(第 3 部分)。
- 团队集成:Slack 状态提醒、Jira 标签分析、每个分支都有预览 URL(第 3 部分)。
- 生产可观测性:Sentry 接入 web 与 API,捕获每个异常(第 4 部分)。
- 预览部署:Vercel 为每个 Pull Request 生成可分享的 URL(第 4 部分)。
我们总共花了≈ 70 ACU(Core 方案约 $157),以及大约两天的动手审查时间。
Devin 做得惊人出色之处
我认为 Devin 非常擅长的方面:
|
领域 |
让我印象深刻的原因 |
|
样板化基础设施 |
AuthModule 脚手架、Dockerfile、YAML 工作流:数分钟内生成,无明显缺陷。 |
|
框架惯用代码 |
NestJS 装饰器、NextAuth 配置、Prisma 迁移都与官方文档一致。 |
|
测试脚手架 |
单元与 Playwright 测试套件开箱即用——没有遗漏边缘桩代码。 |
人类仍优于代理的地方
我认为 Devin 仍需改进的方面:
|
痛点 |
示例 |
|
跨层功能打磨 |
Sandpack 编辑器硬编码为桩测试;没有理解 SandpackTests 组件名。 |
|
配置持久性 |
即便明确“必须保持 Postgres”,仍然默认回退到 SQLite 了 5 次。 |
|
命名 / 清理 |
PR 标题容易漂移;陈旧文件不会自动清除,除非您让 Devin 删除。 |
|
品味与体验 |
仪表盘看起来过得去,但间距、文案和配色仍需要人工微调。 |
我的看法
Devin 的文档从未承诺它是“产品构建器”。文档里描述了更窄的甜蜜区,事后看来,我本该待在那个范围内。官方“Devin 的优势是什么?”页面列出了四个主打用例:

文档把跨越 UI、API 和数据流的功能开发称作“实验性”。它们被描述为大型、开放式的任务,代理“可能需要大量的人为审查与迭代”。这与我们看到的情况完全一致:比如 Sandpack 硬编码测试,或仪表盘看着不错却无法实际计算数据。
所以,经验法则是:
把 Devin 用在那些资深开发者也能用脚本自动化的事情上;而需要产品直觉的任务,请亲自掌舵。
结语
我们的四部分教程到此结束:
- 环境搭建与首个 Pull Request(第 1 部分)
- 用 Devin 交付一条纵向功能切片(第 2 部分)
- 集成、测试与 CI/CD(第 3 部分)
- 安全性、部署与维护(第 4 部分)
接下来我们可以做几件事:
- 托管 API,让预览构建(以及未来的用户)能访问真实后端。
- 确保核心功能可用,并修复我知道的那 30 个 bug
- 打磨 UI
- 添加更多内容与练习
- 发布给大家使用!
如果您也走同样的路,请记住:可以把浇筑地基的活交给代理,但房子还是要您来设计。编码愉快!

我是一名具有产品思维的技术负责人,专注于帮助早期初创公司从首个原型成长到实现产品与市场匹配,并持续向前发展。我对人们如何使用技术充满好奇,热爱与创始人及跨职能团队紧密合作,将大胆的想法变为现实。不在打造产品的时候,我会在世界的新角落寻找灵感,或在瑜伽馆放松减压。