"全程我没有写一行代码" —— 这不是标题党,而是真实发生在我身上的事情。数据库设计、初始化、系统设计、代码调试、系统部署,全部是 cursor 自己完成的,我只是在其中一步步指导他。
感兴趣的同学,可以访问下部署到cloudflare的实际访问链接:https://vault-house-frontend.pages.dev/
前言:AI 编程的真正能力边界在哪里?
2026 年初,当我准备开发一个密码管理系统时,我决定做一个实验:让 AI 完全接管代码开发工作,而我只负责提需求和做决策。
结果出乎意料——在不到一天的时间里,一个完整的、生产级别的密码管理系统就诞生了:
- ✅ React 前端应用:完整的用户界面、认证流程、密码管理功能
- ✅ Cloudflare Workers 后端:RESTful API、JWT 认证、D1 数据库
- ✅ 生产部署:成功部署到 Cloudflare 全球边缘网络
这不是一个玩具项目,而是一个真正可用的企业级应用。
一、项目背景:为什么要做密码管理系统?
1.1 需求来源
作为一个互联网从业者,我每天要登录几十个不同的网站和服务。用同一个密码?太危险。每个网站用不同密码?根本记不住。
市面上的密码管理工具(1Password、LastPass)虽然好用,但:
于是,我决定自己做一个。
1.2 技术选型
在开始之前,我心里有一个大概的技术栈:
| | |
|---|
| React + TypeScript + Tailwind CSS | |
| Cloudflare Workers + Hono | |
| | |
| | |
| | |
二、开发过程:AI 是如何一步步完成的?
2.1 第一步:规划与架构设计
我对 Cursor 说的第一句话是:
"我需要你仔细阅读当前项目的整体系统安排和当前进度,给我计划接下来我们应该做什么。记住,我的最终目标是把这个系统部署到 Cloudflare 平台上。"
AI 的反应让我印象深刻——它没有立即开始写代码,而是:
- 系统性地探索项目结构:读取了 28 个文件,花费约 2 分钟
- 生成完整的项目计划:创建了
PROJECT_PLAN.md,包含 4 个阶段、详细的任务清单
📁 项目架构分析├── backend/ ✅ 完整的控制器和路由框架├── frontend/ ✅ 完整的页面组件,需要集成状态管理├── extension/ ⚠️ 基础架构完成,功能待实现└── shared/ ✅ 加密工具、类型定义完整
关键洞察:好的 AI 不会急于动手,而是先理解全局。
2.2 第二步:策略调整
当我说 "我希望先完成后端、Web 端的上线,让种子用户试用"时,AI 立即调整了计划:
# 策略调整:先 Web 应用后浏览器扩展核心变更:优先完成 Web 应用的开发和部署,获取种子用户反馈,再完善浏览器扩展功能。
这种灵活应变的能力是我没有预料到的——AI 不是机械地执行任务,而是能够根据业务优先级调整技术方案。
2.3 第三步:前端状态管理集成
这是最有意思的部分。AI 发现前端的 Zustand 状态管理有大量 TODO 注释:
// 修改前:充满 TODO 的代码fetchPasswords: async () => {// TODO: 调用 API 获取密码列表// 模拟数据set({ passwords: [ { id: '1', websiteName: 'GitHub', ... }, { id: '2', websiteName: 'Google', ... }, ], });}
AI 一次性完成了所有 TODO 的实现:
// 修改后:真实的 API 调用fetchPasswords: async () => {set({ isLoading: true });try {const { tags, ...otherParams } = get().searchParams;const queryParams = Object.entries({ ...otherParams, ...(tags?.length ? { tags: JSON.stringify(tags) } : {}), }).reduce((acc, [key, value]) => {if (value !== undefined && value !== null) { acc[key] = String(value); }return acc; }, {} as Record<string, string>);const response = await apiClient.get('/api/passwords', { query: queryParams });if (response.success && response.data?.passwords) {set({ passwords: response.data.passwords }); } } catch (error) {console.error('获取密码列表失败:', error); } finally {set({ isLoading: false }); }}
注意看细节:AI 不仅实现了功能,还处理了:
- TypeScript 类型安全(
Record<string, string> 转换)
2.4 第四步:类型错误修复
在运行 npm run typecheck 时,出现了类型错误:
error TS2322: Type 'SearchParams' is not assignable to type'Record<string, string>'.
AI 的调试过程非常系统:
- 读取类型定义:查看
src/types/index.ts - 分析错误原因:SearchParams 包含 number 类型的 page/limit 字段
- 提出解决方案:使用
Object.entries + reduce 转换类型
这个过程完全自动化,我没有介入任何一步。
2.5 第五步:数据库 Schema 设计
AI 创建了完整的数据库设计:
-- 用户表CREATETABLEIFNOTEXISTSusers (idTEXT PRIMARY KEYNOTNULL, email TEXTNOTNULLUNIQUE,nameTEXTNOTNULL, encrypted_master_key TEXTNOTNULL,saltTEXTNOTNULL, iterations INTEGERNOTNULLDEFAULT100000, created_at DATETIME DEFAULTCURRENT_TIMESTAMP, updated_at DATETIME DEFAULTCURRENT_TIMESTAMP);-- 密码条目表CREATETABLEIFNOTEXISTS password_entries (idTEXT PRIMARY KEYNOTNULL, user_id TEXTNOTNULL, website_name TEXTNOTNULL, website_url TEXT,accountTEXTNOTNULL, encrypted_password TEXTNOTNULL, ...FOREIGNKEY (user_id) REFERENCESusers(id) ONDELETECASCADE);-- 以及完整的索引设计CREATEINDEX idx_users_email ONusers(email);CREATEINDEX idx_password_entries_user ON password_entries(user_id);...
2.6 第六步:Cloudflare 部署配置
这是最复杂的部分,涉及到多个云服务的配置:
# AI 执行的命令序列npm install -g wranglerwrangler loginwrangler d1 create vault-house-dbwrangler d1 execute vault-house-db --file=./schema.sql --remote
当部署遇到问题时,AI 的问题诊断能力让我印象深刻:
问题 1:libsodium-wrappers 在 Workers 环境不兼容
✘ [ERROR] Could not resolve "./libsodium.mjs"
AI 的解决方案:完全重写加密模块,使用 Web Crypto API 替代 libsodium:
// 使用 Web Crypto API 实现 AES-256-GCM 加密exportasyncfunctionencrypt(data: string, key: string): Promise<string> {const encoder = new TextEncoder();const keyBytes = Uint8Array.from(atob(key), c => c.charCodeAt(0));const iv = crypto.getRandomValues(newUint8Array(12));const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM', length: 256 },false, ['encrypt'] );const encryptedBytes = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encoder.encode(data) );// 合并 IV 和密文const combined = newUint8Array(iv.length + encryptedBytes.byteLength); combined.set(iv); combined.set(newUint8Array(encryptedBytes), iv.length);return btoa(String.fromCharCode(...combined));}
这不是简单的 "换个库",而是一次完整的架构调整——把所有加密函数从同步改为异步,同时保持 API 兼容性。
三、最终成果:一个完整的密码管理系统
3.1 功能清单
3.2 项目结构
vault-house/├── backend/ # Cloudflare Workers 后端│ ├── src/│ │ ├── controllers/ # 6 个控制器│ │ ├── routes/ # 6 个路由模块│ │ ├── middleware/ # 认证、CORS、错误处理│ │ └── utils/ # 工具函数│ └── schema.sql # D1 数据库 Schema├── frontend/ # React 前端应用│ └── src/│ ├── components/ # UI 组件│ ├── pages/ # 12 个页面│ ├── hooks/ # 自定义 Hooks│ └── store/ # Zustand 状态管理├── extension/ # Chrome 浏览器扩展│ └── src/│ ├── background.ts # 背景脚本│ ├── content.ts # 内容脚本│ └── components/ # 扩展 UI└── shared/ # 共享库 └── src/ ├── types/ # TypeScript 类型 ├── schemas/ # Zod 验证 └── utils/ # 加密工具
3.3 技术亮点
1. 端到端加密设计
用户的密码在客户端加密后才上传到服务器,服务器只能看到密文:
用户输入密码 → 派生主密钥(PBKDF2) → 加密密码(AES-256-GCM) → 上传密文
2. 无服务器架构
基于 Cloudflare Workers,享受:
3. 类型安全
全栈 TypeScript,共享类型定义:
// shared/src/types/index.tsexportinterface PasswordEntry { id: string; userId: string; websiteName: string; websiteUrl?: string; account: string; encryptedPassword: string; categoryId?: string; tags?: string[]; createdAt: Date; updatedAt: Date;}
四、AI 辅助开发的最佳实践
通过这次实验,我总结出一套 "AI 从零搭建系统" 的最佳实践:
4.1 实践一:明确目标,让 AI 先规划
❌ 错误做法:直接说 "帮我写一个登录页面"
✅ 正确做法:
我需要你仔细阅读当前项目的整体系统安排和当前进度,给我计划接下来我们应该做什么。记住,我的最终目标是把这个系统部署到 Cloudflare 平台上。
为什么:让 AI 先理解全局,避免局部最优陷阱。
4.2 实践二:保持高层决策权
在项目中,我只做了两类决策:
- 业务优先级:"先完成 Web 端上线,再做浏览器扩展"
- 技术选型:"使用 Cloudflare 的全家桶"
其他细节全部交给 AI。这种分工让开发效率最大化。
4.3 实践三:让 AI 自己调试
当 AI 遇到错误时,不要急于介入。比如:
> npm run typecheckerror TS2322: Type 'SearchParams' is not assignable to type...
AI 会自动:
这个闭环通常不需要人工干预。
4.4 实践四:渐进式部署验证
不要等所有功能都完成才部署。我们的部署顺序是:
Day 1 上午:后端 API 部署 → 验证 → Day 1 下午:前端部署 → 验证 → Day 1 晚上:端到端测试 → 修复问题
每一步都验证,确保问题及时发现。
4.5 实践五:文档即代码
AI 不仅写代码,还会生成文档:
这些文档对后续维护非常有价值。
五、一些思考
5.1 AI 编程的能力边界
AI 擅长的:
AI 不擅长的:
5.2 这意味着什么?
对于个人开发者:你可以独立完成原来需要团队才能做的事。
对于团队:开发效率可以提升 5-10 倍。
对于行业:软件开发的门槛正在急剧降低。
5.3 建议
如果你也想尝试 AI 辅助开发,我的建议是:
- 从小项目开始:先用 AI 做一些小工具,熟悉协作模式
结语
一天时间,零行手写代码,一个完整的企业级密码管理系统。
这不是炫技,而是一种新的工作方式的探索。
在 AI 时代,创造力和决策能力比编码能力更重要。我们要学会的是如何成为一个优秀的 "AI 指挥官",而不是一个优秀的 "代码搬运工"。
希望这篇文章对你有所启发。如果你有任何问题,欢迎在评论区交流。
项目地址:VaultHouse GitHub Repository
技术栈:
- 前端:React 18 + TypeScript + Tailwind CSS + Vite
- 后端:Cloudflare Workers + Hono + D1
- 加密:Web Crypto API (AES-256-GCM)
- 扩展:Chrome Extension Manifest V3
完成时间:2026 年 1 月 22 日
如果觉得有用,请点赞、收藏、转发三连,你的支持是我持续输出的动力!
附录:关键代码片段
A. 前端认证 Hook
// frontend/src/hooks/useAuth.tsxexportconst useAuth = () => {const { user, token, setUser, setToken, logout } = useAuthStore();const [isLoading, setIsLoading] = useState(true);const login = async (email: string, password: string) => {const response = await apiClient.post('/api/auth/login', { email, password });if (response.success && response.data) { setUser(response.data.user); setToken(response.data.token); localStorage.setItem('token', response.data.token); }return response; };const register = async (name: string, email: string, password: string) => {const response = await apiClient.post('/api/auth/register', { name, email, password });if (response.success && response.data) { setUser(response.data.user); setToken(response.data.token); localStorage.setItem('token', response.data.token); }return response; };return { user, token, isAuthenticated: !!token, isLoading, login, register, logout };};
B. 后端密码控制器
// backend/src/controllers/passwords.tsexportconst createPassword = async (c: Context) => {const userId = c.get('userId');const db = c.env.DB;const body = await c.req.json();const id = crypto.randomUUID();const now = newDate().toISOString();await db.prepare(` INSERT INTO password_entries (id, user_id, website_name, website_url, account, encrypted_password, notes, category_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).bind(id, userId, body.websiteName, body.websiteUrl, body.account, body.encryptedPassword, body.notes, body.categoryId, now, now).run();return c.json({ success: true, data: { id, ...body, createdAt: now } });};
C. 端到端加密流程
// shared/src/utils/encryption.tsexportasyncfunctionencrypt(data: string, key: string): Promise<string> {const encoder = new TextEncoder();const keyBytes = Uint8Array.from(atob(key), c => c.charCodeAt(0));const iv = crypto.getRandomValues(newUint8Array(12));const cryptoKey = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-GCM', length: 256 }, false, ['encrypt'] );const encryptedBytes = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encoder.encode(data) );const combined = newUint8Array(iv.length + encryptedBytes.byteLength); combined.set(iv); combined.set(newUint8Array(encryptedBytes), iv.length);return btoa(String.fromCharCode(...combined));}
附录:遇到的主要问题及解决方案
问题 1:SearchParams 类型不兼容
错误信息:
Type 'SearchParams' is not assignable to type'Record<string, string>'.Property 'page' is incompatible with index signature.Type 'number' is not assignable to type'string'.
解决方案:使用 Object.entries + reduce 进行类型转换
const queryParams = Object.entries(params).reduce((acc, [key, value]) => {if (value !== undefined && value !== null) { acc[key] = String(value); }return acc;}, {} as Record<string, string>);
问题 2:libsodium 在 Workers 环境不兼容
错误信息:
Could not resolve "./libsodium.mjs"
解决方案:使用 Web Crypto API 完全重写加密模块
问题 3:Wrangler 版本过旧
解决方案:更新 wrangler 到 v4.x
{"devDependencies": {"wrangler": "^4.59.3" }}
本文首发于微信公众号,转载请注明出处。