跳至内容
AI 代理
人工智能

使用 Devin 进行软件开发:安全性、部署与维护(第 4 部分)

了解如何使用 Devin 通过 NextAuth 添加真实用户认证、用 Sentry 监控错误,并将前端部署到 Vercel,生成预览 URL。
Marie Fayard's photo
Marie Fayard
已更新 · 12分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。

欢迎回来!我们快要收官了:Slack 在响,Jira 有工单,测试全绿,我们的 CI 会拦下任何草率的 PR。第四部分就是最后的冲刺,我们要把 fp-ts playground 打造成一个理论上可以面向公众的东西。

您可以在这里访问 Devin 系列的所有教程:

  1. 环境搭建与首个 Pull Request(第 1 部分)
  2. 用 Devin 交付一条纵向功能切片(第 2 部分)
  3. 集成、测试与 CI/CD(第 3 部分) 
  4. 安全性、部署与维护(第 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 的产出

数据库

删除了 Session 表;新增 User 模型,包含 email、hash、连续天数字段和时间戳。迁移脚本将旧的每条 sessionId 行回填到一个名为 legacy-<uuid>@anon.local 的伪用户下。

后端

AuthModule、AuthService、GraphQL AuthResolver、JwtStrategy 与 GqlAuthGuard。全部符合 Nest 规范,类型 100% 完整。

前端

AuthProvider React 上下文,LoginForm、RegisterForm,在受保护路由上弹出登录模态框,以及仪表盘页眉中的登出按钮。

安全性

Argon2(12 轮)、通过 class-validator 进行 DTO 校验、JWT 存在 localStorage、为每个 progress 的 resolver 加了守卫。

测试

为 AuthService.register/login 编写了单元测试,并新增一个 e2e 变更测试,断言守卫会拒绝缺失 token 的请求。(第二次提示它才加上测试)

又来了一次 SQLite 迁移

猜猜我又在 Devin 的小思考框里看到了什么。

已成功将本地开发从 PostgreSQL 迁移到 SQLite 🥳

这正是我明确要求它不要做的。Prisma schema 被重写成 SQLite,连接串和类型也改了(从 TIMESTAMP 变成 DATETIME)。我在会话中途抓住了它:

  1. 暂停会话。
  2. git checkout main apps/api/prisma/schema.prisma(还原 Postgres schema)。
  3. 删除新生成的 dev.db 文件。
  4. npm run prisma:migrate --workspace=apps/api 重新应用 Postgres 迁移。
  5. 恢复 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 中,我找到了这张有用的认证系统新图:

Devin's diagram for our new auth system

随着真实用户就位、数据库稳稳回到 Postgres 上,我们终于可以追踪真实的学习者进度、向 Vercel 发布预览构建,并用 Sentry 捕获运行时错误了。

前端部署到 Vercel,每个 PR 都有预览链接

有了安全的登录,下一步显然就是让大家能点到点得到的东西。我们决定目前只部署 Next.js 前端。API 和 Postgres 将继续留在我的本地机器,直到我们选定符合预算的托管方案。

手动连接账户(0 ACU)

暂时还无法通过原生集成把 Devin 连到我的个人 Vercel 账户。所以我在 Vercel 控制台手动完成:

  1. 登录 Vercel,点击“New Project → Import Git Repository”。
  2. 选择 fp-ts-exercises 仓库,构建命令保持为 npm run build --workspace apps/web,然后点 Deploy。
  3. 把生成的 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。

在提示词中访问

在提示词或命令中使用 $.<NAME>。Devin 会在执行 shell 前解析。

示例:DATABASE_URL=$.POSTGRES_URL

大小限制

每个键 4 KB,Core 方案每个团队 100 个键。

足够存放 PEM 证书或私钥。

添加一个 secret

添加 secret 的步骤如下:

  1. 在 Devin 控制台打开 Team → Secrets。
  2. 点击 “Add Secret”,输入名称(SENTRY_DSN_WEB)及其值。
  3. Devin 确认存储;该键现可通过 $.SENTRY_DSN_WEB 使用。

store a new secret in devin

在任务中使用 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)

apps/web/sentry.client.config.tsx apps/web/sentry.server.config.ts,以及在 app/layout.tsx 中的一处引入

ts import * as Sentry from '@sentry/nextjs'; Sentry.init({ dsn: process.env.SENTRY_DSN_WEB, tracesSampleRate: 1.0 });

NestJS(API)

apps/api/src/sentry.ts,以及在 main.ts 中的两行代码

ts import * as Sentry from '@sentry/node'; Sentry.init({ dsn: process.env.SENTRY_DSN_API }); app.useGlobalFilters(new Sentry.GqlExceptionFilter());

环境模板

在 .env.example 中新增占位符

SENTRY_DSN_WEB=   SENTRY_DSN_API=

测试

添加 Jest spy,断言在人为触发错误时会调用 Sentry.captureException。

 

我手动完成的步骤

我采取的步骤如下:

  1. 把我 Sentry 项目的 DSN 复制到 .env。
  2. 重启两个开发服务器。
  3. 用一个故意写错的查询请求 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 的优势是什么?”页面列出了四个主打用例:

devin strengths

文档把跨越 UI、API 和数据流的功能开发称作“实验性”。它们被描述为大型、开放式的任务,代理“可能需要大量的人为审查与迭代”。这与我们看到的情况完全一致:比如 Sandpack 硬编码测试,或仪表盘看着不错却无法实际计算数据。

所以,经验法则是:

把 Devin 用在那些资深开发者也能用脚本自动化的事情上;而需要产品直觉的任务,请亲自掌舵。

结语

我们的四部分教程到此结束:

  1. 环境搭建与首个 Pull Request(第 1 部分)
  2. 用 Devin 交付一条纵向功能切片(第 2 部分) 
  3. 集成、测试与 CI/CD(第 3 部分) 
  4. 安全性、部署与维护(第 4 部分)

接下来我们可以做几件事:

  1. 托管 API,让预览构建(以及未来的用户)能访问真实后端。
  2. 确保核心功能可用,并修复我知道的那 30 个 bug
  3. 打磨 UI
  4. 添加更多内容与练习
  5. 发布给大家使用!

如果您也走同样的路,请记住:可以把浇筑地基的活交给代理,但房子还是要您来设计。编码愉快!


Marie Fayard's photo
Author
Marie Fayard

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

主题
AI 代理
人工智能

用以下课程构建 AI 代理:

课程

AI 智能体入门

1 小时 30 分钟
146.4K
了解 AI 智能体的基础、组成部分及实际应用——无需编程。
查看详情开始课程

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。
查看更多