设计师的Claude代码:生产前指南遗漏内容
摘要
我们在 Social Animal 的 18 个月内部署了 30+ 个无头项目。我们最近接收的大约三分之一是来自设计师主导构建的救援工作,这些构建发布了演示但在生产环境中出现故障。Michael Nervegna 在 Substack 上发布的"Claude Code for Designers"指南对原型设计非常有益 -- 但它在行级安全性(RLS)、身份验证令牌刷新、数据库抽象选择、部署回滚、内容安全策略和管理员身份验证之前就停止了。本文涵盖了这些空白。如果你要部署到生产环境,你需要这些。
目录
- Claude Code 是什么以及为什么设计师在使用它?
- Nervegna 指南做对了什么?
- 指南在哪里不足?
- Claude 无法捕捉的行级安全性陷阱
- 身份验证交接:原型和生产之间的差距
- Supabase vs Prisma:Claude Code 应该为哪个生成代码?
- 部署回滚:当你的 AI 生成代码破坏时会发生什么
- 代理资产的内容安全策略
- 你什么时候真正需要管理员身份验证?
- 推送到生产环境前:检查清单
- 常见问题
Claude Code 是什么以及为什么设计师在使用它?
Claude Code 是 Anthropic 在 2025 年初推出的基于终端的编码工具。它作为 @anthropic-ai/claude-code 运行,需要 Claude Pro($20/月)或 Team($30/座位/月)以及 API 访问权限。你可以在终端中通过自然语言编写、编辑和调试代码。
设计师使用它是因为它缩小了"我在 Figma 中设计了这个"和"这是一个工作的 Next.js 应用"之间的差距。与 v0 或 Bolt 不同,Claude Code 在你的实际文件系统上运行。它读取你的项目结构、修改文件、运行你的开发服务器,并根据错误输出进行迭代。对于理解组件层次结构但不想死记 TypeScript 泛型的人来说,这确实很有用。
Nervegna 将其定位为让设计师"系统化思考"而不是"语法化思考"的工具。我们同意。我们的分歧在于第一个 npm run dev 成功后会发生什么。
Nervegna 指南做对了什么?
Nervegna 在大多数 AI 编码教程中遗漏的三件事上做得很好。
第一:项目上下文。 他建议向 Claude Code 提供一个 CLAUDE.md 文件,其中包含你的项目约定、技术栈和设计令牌。我们见过 Claude Code 在使用 CSS Modules 的项目中针对 Tailwind 工具生成代码,因为没有人告诉它约定。在编写代码之前建立上下文是正确的做法。
第二:迭代循环。 提示、审查输出、纠正方向、重复。他没有把 Claude Code 当作"描述并发布"按钮。他把它当作一个需要监督的配对伙伴。这是正确的心智模型。
第三:从小处开始。 在尝试完整的应用程序脚手架之前,先构建单个组件或页面。我们见过设计师在一条消息中提示"为我构建一个完整的 SaaS 仪表板,包括身份验证、计费和管理"。结果总是一团糟。Nervegna 的增量方法避免了这种情况。
Nervegna 指南在 0 到原型阶段对设计师很有帮助。问题是原型会变成生产代码,这就是差距最重要的地方。
指南在哪里不足?
Nervegna 的文章在原型设计阶段表现很好。它没有涉及当你连接真实数据库、真实用户和真实部署基础设施时变得紧急的问题。
缺少的内容:
- 行级安全性 (RLS) -- Claude Code 生成的 Supabase 项目几乎从不具有正确的 RLS 策略
- 身份验证交接 -- Supabase Auth 在开发中与生产流程(包括令牌刷新、会话管理和重定向处理)之间的差距
- 数据库抽象决策 -- 何时直接使用 Supabase 客户端与 Prisma 或 Drizzle ORM 相比较
- 部署回滚策略 -- 当 Claude Code 提交在生产环境中破坏时会发生什么
- 内容安全策略 -- 特别是对于带有代理/外部资产的 Next.js Image
- 管理员身份验证 -- 何时需要超越简单用户身份验证的基于角色的访问
让我们逐个讨论。
Claude 无法捕捉的行级安全性陷阱
行级安全性是 Supabase 的一种机制,用于确保数据库查询只返回请求用户有权查看的行。在 Supabase 中创建表时,RLS 默认是禁用的。任何经过身份验证的用户 -- 或在某些配置中,任何匿名请求 -- 都可以读取每一行。
当 Claude Code 搭建 Supabase 项目时,它会创建表并编写客户端查询。如果你要求,有时会添加 RLS 策略。但它生成的策略通常以微妙的方式出现错误。
AI 生成代码中的常见 RLS 错误
| 错误 | 会发生什么 | 如何修复 |
|---|---|---|
| 根本没有启用 RLS | 任何经过身份验证的用户读取所有数据 | ALTER TABLE your_table ENABLE ROW LEVEL SECURITY; |
策略使用 auth.uid() 但表没有 user_id 列 |
策略可以编译但匹配零行,阻止所有访问 | 添加 user_id UUID REFERENCES auth.users(id) 并填充它 |
| SELECT 策略存在但没有 INSERT/UPDATE/DELETE 策略 | 用户可以读取但不能写入他们自己的数据 | 为每个操作分别创建策略 |
策略仅使用 auth.role() = 'authenticated' |
任何登录用户都可以看到所有行,而不仅仅是他们自己的 | 添加 auth.uid() = user_id 条件 |
| 服务角色密钥在客户端代码中使用 | RLS 被完全绕过 | 永远不要在客户端捆绑包中公开 SUPABASE_SERVICE_ROLE_KEY |
我们在今年三个单独的设计师构建的项目中看到了最后一个 -- 客户端代码中的服务角色密钥。Claude Code 有时会使用服务角色密钥,因为它"有效"且不会抛出权限错误。该密钥绕过所有 RLS。它只属于服务器端代码(API 路由、服务器操作、边缘函数)。永远不要在 use client 组件中使用。
Nervegna 在他的指南中没有涵盖 RLS,这是可以理解的。但如果你遵循他的工作流并连接到 Supabase,请手动检查每个表。在 Supabase SQL 编辑器中运行:
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = 'public';
如果任何保存用户数据的表的 rowsecurity 为 false,在部署前停下来修复它。
身份验证交接:原型和生产之间的差距
身份验证是设计师主导构建中最常见的故障点。不是因为初始设置是错误的 -- Supabase Auth 很容易搭建 -- 而是因为生产身份验证涉及在本地开发期间不会出现的边界情况。
Nervegna 的指南侧重于让事情在本地运行。以下是部署时会破坏的内容:
令牌刷新故障
Supabase Auth 令牌默认在 3600 秒(1 小时)后过期。Supabase 客户端理论上会自动处理刷新。在实践中,如果你的 Next.js 中间件或服务器组件在每个请求上创建新的 Supabase 客户端而不传递现有会话,你会在第一小时后间歇性地获得 401 错误。
对于 Next.js App Router,你需要 @supabase/ssr(截至 2025 年 2 月版本 0.5.x)和中间件中正确的 cookie 处理。Claude Code 通常生成较旧的 @supabase/auth-helpers-nextjs 包,这已弃用。检查你的 package.json。
重定向 URI 不匹配
OAuth 提供商(Google、GitHub)需要精确的重定向 URI。Claude Code 为 localhost:3000 配置这些。当你部署到 Vercel 或 Netlify 时,你需要在 OAuth 提供商的控制台和 Supabase Auth 设置中的"重定向 URL"下添加你的生产 URL 和任何预览部署 URL。这需要 5 分钟,但如果你错过了,会 100% 阻止 OAuth 登录。
会话同步问题
在 Next.js 14+ 中,你有服务器组件、客户端组件、中间件、API 路由和服务器操作 -- 所有这些都可能需要当前用户会话。Supabase 客户端必须在每个上下文中以不同的方式创建。Claude Code 通常创建单个 createClient() 实用程序并在任何地方使用它,这会导致水合不匹配和过时的会话。
你至少需要三个客户端创建函数:
createBrowserClient()用于客户端组件createServerClient()用于服务器组件和服务器操作createMiddlewareClient()用于中间件
这在 Supabase 的 SSR 指南中有文档说明,但 Claude Code 不能始终正确地生成它。
Supabase vs Prisma:Claude Code 应该为哪个生成代码?
Nervegna 没有涉及这个决定,但它比大多数设计师意识到的要重要得多。
Supabase 客户端(@supabase/supabase-js) 通过 Supabase 的 PostgREST API 查询数据库。它很方便,不需要架构定义文件,并直接与 RLS 配合使用。但除了 Supabase 生成的内容外,它不提供类型安全,并且将应用程序紧密耦合到 Supabase 的基础设施。
Prisma ORM(目前 v6.x)直接连接到 PostgreSQL。它为你提供架构文件(schema.prisma)、生成的 TypeScript 类型、迁移和数据库无关的查询。但它不遵重 RLS 策略(它作为特权用户连接),并且需要构建步骤来生成客户端。
Drizzle ORM(v0.36.x)是一个更轻的替代品,具有类似 SQL 的语法和更好的边缘运行时支持。
决策矩阵
| 因素 | Supabase 客户端 | Prisma | Drizzle |
|---|---|---|---|
| RLS 支持 | 原生 | 必须在应用层实现 | 必须在应用层实现 |
| 类型安全 | 通过 CLI 生成 | 从架构生成 | 架构即代码 |
| 边缘运行时兼容 | 是 | 有限(需要 Prisma Accelerate) | 是 |
| 设计师学习曲线 | 低 | 中等 | 中等 |
| 供应商锁定 | 高(Supabase) | 低 | 低 |
| Claude Code 生成质量 | 好 | 好 | 不一致 |
我们的建议:如果你正在构建原型或将始终在 Supabase 上运行,请使用 Supabase 客户端。如果你需要迁出 Supabase 或想要严格的架构驱动开发,请使用 Drizzle。由于边缘运行时限制,我们已经停止将 Prisma 用于新项目,尽管 Prisma Accelerate(600K 查询/月为 $0,之后 $49/月)已经改进了这一点。
在你的 CLAUDE.md 文件中明确告诉 Claude Code 你的决定。如果你不这样做,它会混合方法 -- 有时通过 Supabase 客户端查询,有时通过 ORM -- 最终你会在同一个项目中使用两种不同的数据访问模式。
部署回滚:当你的 AI 生成代码破坏时会发生什么
Nervegna 的指南介绍了如何迭代构建功能。它没有涉及当 Claude Code 会话生成在本地开发中通过但在生产环境中破坏的提交时会发生什么。
这比你预期的发生更频繁。Claude Code 可以在单个提示响应中修改 15 个文件。如果你将其提交为一个单位并部署,回滚意味着恢复所有 15 个更改 -- 即使其中 13 个很好。
实用的回滚策略
1. 每个逻辑更改后提交,而不是每个 Claude Code 会话后。 如果 Claude 在一个会话中修改了身份验证、UI 和数据库架构,请进行三个单独的提交。
2. 使用 Vercel 的即时回滚。 如果你在 Vercel 上部署,每个部署都是不可变的。你可以从仪表板在 10 秒内回滚到任何以前的部署。Netlify 提供相同的功能。
3. 永远不要直接从 Claude Code 运行数据库迁移。 如果 Claude 生成迁移文件,在运行 npx supabase db push 或 npx prisma migrate deploy 之前手动审查它。删除列不是你可以通过 git 恢复来回滚的。
4. 标记已知良好的状态。 在开始接触关键路径(身份验证、支付、数据模型)的 Claude Code 会话之前,创建 git 标签:git tag pre-auth-refactor。如果出现问题,git reset --hard pre-auth-refactor 会让你回到原点。
5. 预览部署是必须的,不是可选的。 Vercel 和 Netlify 都为每个 PR 创建预览部署。不要在不点击预览的情况下合并到主分支。Claude Code 可以生成在本地运行但在生产环境中失败的代码,原因是缺少环境变量、边缘运行时不兼容性或 CSP 违规。
代理资产的内容安全策略
这很小众,但当你部署设计师构建的网站时会让人咬牙切齿。
Next.js 的 <Image> 组件默认通过 /_next/image 代理外部图像。这对优化很好。但如果你有内容安全策略标头(你应该有),你需要明确允许你的图像来自的域。
Claude Code 会在 next.config.js 中设置带有 remotePatterns 的图像优化,但不会添加 CSP 标头。当你在 Vercel 的安全标头后面部署或通过中间件添加你自己的标头时,外部图像会无声地破坏 -- 它们在本地加载(CSP 通常很宽松),但在生产环境中失败。
以下是你在中间件或 next.config.js 标头中需要的最低要求:
// middleware.ts
const cspHeader = `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data: https://your-supabase-project.supabase.co https://your-cdn.com;
font-src 'self';
connect-src 'self' https://your-supabase-project.supabase.co;
frame-ancestors 'none';
`;
用 nonce 替换 'unsafe-eval' 和 'unsafe-inline' 以进行生产加固。关键是:如果 Claude Code 从 Unsplash、Supabase Storage 或任何外部 CDN 拉入图像,而你没有将这些域添加到你的 CSP img-src 指令,你会在生产环境中获得损坏的图像,开发中控制台中零错误。
你什么时候真正需要管理员身份验证?
Nervegna 的指南涵盖了基本的用户身份验证。许多设计师构建的项目需要管理员界面 -- 站点所有者或内容团队无需接触数据库直接管理数据的一种方式。
问题是:何时需要管理员身份验证作为独立关注与仅使用 Supabase 仪表板相比。
你不需要自定义管理员身份验证当:
- 你是唯一管理内容的人
- 你的客户对使用 Supabase 表编辑器感到满意
- 项目少于 3 种内容类型
- 更新频率每周不到一次
你需要自定义管理员身份验证当:
- 非技术团队成员需要管理内容
- 你需要审批工作流程或草稿/发布状态
- 项目具有基于角色的访问权限(编辑器与管理员与查看者)
- 你正在管理需要审核的用户生成内容
如果你需要管理员身份验证,最简单的方法是在你的 profiles 表上使用 role 列(它镜像 auth.users),带有枚举:'user' | 'editor' | 'admin'。然后添加检查此角色的 RLS 策略:
CREATE POLICY "Admins can do anything"
ON public.posts
FOR ALL
USING (
EXISTS (
SELECT 1 FROM public.profiles
WHERE profiles.id = auth.uid()
AND profiles.role = 'admin'
)
);
如果你特别提示 Claude Code,它可以生成这个。没有提示,它会默认使用简单的 auth.uid() = user_id 策略,这些策略不考虑管理员访问。你会以一个无法看到其他用户内容的管理员告终。
Nervegna 在 CLAUDE.md 文件中定义需求的工作流程会捕捉到这一点 -- 如果你想在开始构建前在文件中包含基于角色的访问。在开始构建之前将其添加到文件中。
推送到生产环境前:检查清单
这是我们在 Social Animal 部署任何由 AI 编码工具构建或大幅协助的项目前使用的清单。
数据库与安全性
- RLS 在
public架构中的每个表上都启用了 - RLS 策略在每个表上对 SELECT、INSERT、UPDATE 和 DELETE 存在
-
SUPABASE_SERVICE_ROLE_KEY仅在服务器端代码中使用(grep 你的代码库:grep -r "SERVICE_ROLE" --include="*.ts" --include="*.tsx") - 没有 Supabase 客户端用服务角色密钥创建在任何包含
'use client'的文件中 - 数据库迁移已手动审查
- 外键约束在预期的地方存在
- 索引在 WHERE 子句和 RLS 策略中使用的列上存在
身份验证
- 使用了
@supabase/ssr(不是已弃用的@supabase/auth-helpers-nextjs) - 为浏览器、服务器和中间件上下文存在单独的客户端创建函数
- OAuth 重定向 URI 为生产域和预览部署域配置了
- 令牌刷新已测试(临时设置短过期时间并验证会话存活)
- 受保护的路由在会话缺失时重定向到登录
- 登出清除所有 cookie 和服务器端会话状态
管理员和角色
- 如果管理员功能存在,角色检查在 RLS 级别进行(不仅仅是 UI 级别隐藏)
- 管理员路由由中间件保护,而不仅仅是条件性呈现
- 新用户的默认角色是最少特权角色
部署与回滚
- 在部署平台中设置了环境变量
- 在最后一次主要 AI 辅助更改前存在已知良好的 git 标签
- 预览部署已通过点击核心流程进行测试
- Vercel/Netlify 即时回滚已理解并为团队记录了
- 启用了数据库备份(Supabase Pro 计划包括 $25/月的日常备份)
内容安全与资产
- CSP 标头在
img-src中包含所有外部图像域 - CSP 标头在
connect-src中包含 Supabase 项目 URL -
next.config.jsremotePatterns与 CSPimg-src域匹配 - 字体是自托管或其 CDN 在
font-src中 - 没有混合内容(HTTPS 页面上的 HTTP 资源)
代码质量
- TypeScript 严格模式已启用(
tsconfig.json中的"strict": true) - 没有
@ts-ignore或 Claude Code 添加的any类型来压制错误 -
npm run build不带警告通过(不仅仅是npm run dev) - 错误边界存在于获取数据的客户端组件中
- 异步操作存在加载和错误状态
性能
- 图像使用 Next.js
<Image>组件与width和height或fill - 没有客户端数据获取可以在服务器组件中获取的数据
- 已检查了包大小(
npx next@latest build显示路由大小) - Lighthouse 得分在性能方面高于 90(在预览部署上运行,而不是 localhost)
这个检查清单不是详尽的。这是涉及 Supabase、Next.js 和 AI 生成代码的项目的最低要求。
常见问题
Claude Code 对设计师构建生产应用来说足够好吗? Claude Code 在从设计意图生成工作代码方面表现出色。但生产就绪需要工具无法主动提供的安全性、身份验证和基础设施知识。将其与检查清单和来自具有后端经验的人的代码审查配对。
Nervegna 的指南是否适用于原型以外的项目? Nervegna 的工作流程 -- 优先上下文提示、增量构建、迭代审查 -- 可以很好地扩展。差距在于生产问题,如 RLS、身份验证边界情况和部署策略。他的方法是健全的;它需要对任何面向用户的东西进行补充。
我应该将 Supabase 或 Prisma 与 Claude Code 一起使用吗? 如果你想要在数据库级别强制 RLS 并且你致力于 Supabase 平台,请使用 Supabase 的客户端库。如果你想要数据库可移植性和边缘运行时兼容性,请使用 Drizzle ORM。由于边缘限制,我们已经停止对新项目使用 Prisma。
我如何防止 Claude Code 在客户端代码中使用 Supabase 服务角色密钥?
在你的 CLAUDE.md 文件中添加明确的规则:"永远不要在客户端组件中使用 SUPABASE_SERVICE_ROLE_KEY。仅在服务器操作、API 路由或中间件中使用它。"当明确陈述时,Claude Code 尊重项目级说明。
部署 Claude Code 生成的 Next.js 应用的最便宜方式是什么? Vercel 的免费 Hobby 计划支持每个项目一个生产部署。Supabase 的免费套餐包括 2 个项目,500MB 数据库和 1GB 文件存储。总成本:低流量网站 $0/月。一旦你有真实用户,预期迁移到 Vercel Pro($20/月)和 Supabase Pro($25/月)。
Claude Code 多频繁生成具有安全问题的代码? 根据我们的经验,大约 40% 涉及数据库操作的 Claude Code 会话生成至少一个 RLS 间隙的代码。这不是恶意的 -- 工具优化"工作"代码,RLS 违规不会产生错误。他们只是无声地暴露数据。总是手动审计。