ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code实战:从空目录到可部署的全栈App搭建全流程

Claude Code实战:从空目录到可部署的全栈App搭建全流程

一个人接活儿的时候,最磨人的不是某个算法想不明白,也不是页面样式调不出来,而是从零启动一个项目的那些琐碎事:初始化目录、装依赖、配环境、起服务、建数据库。这些事不难,但极其消耗耐心,尤其你想快速验证一个产品想法到底值不值得做的时候。我最近用 Claude Code 完整走了一遍「从零搭建新项目」的流程,目标是一款宠物生命周期管理App,从空目录到能跑、能测、能部署,全程 AI 深度参与。

这篇内容就是想把这套流程原原本本记录下来:我是怎么拆需求的,怎么让 Claude Code 干活,哪些地方它能干得又快又好,哪些地方它给的东西必须返工,以及最终的落地形态是什么。如果你也准备用 AI 编码工具从零搭一个项目,或者对「AI 到底能在全流程里承担多少」很好奇,这篇应该能给你一些实在的参考。

1. 为什么选Claude Code来干这件事:AI编码的真实边界

先说结论:Claude Code 不是一个替你思考的工具,它是一个替你执行的手脚。这两者的区别决定了你用它做事的上限。

1.1 一个终端里的结对程序员:到底什么是Claude Code

你可以把 Claude Code 理解成住在终端里的 AI 结对编程搭档。它和你在 IDE 里常用的 AI 补全插件的核心区别是:补全插件只能感知你当前打开的文件,Claude Code 看到的是整个项目目录。它可以在终端里读取文件、创建文件、修改代码、执行命令,甚至在你允许的情况下跑测试和部署脚本。

这意味着什么?意味着它能把「跨文件的脏活累活」揽下来。比如我要给宠物管理 App 新增一个「提醒已读」功能,以前我需要自己找到列表组件、找到状态管理、找到接口层、找到数据库表,改四五个文件。现在我可以直接说:帮我把提醒列表加上已读状态,点击后更新数据库并刷新视图。它会自己定位相关文件,改完告诉我改了哪些地方。

但这个能力是有边界的。它擅长的是「在有明确上下文的情况下做工程化操作」,而不是「替你做产品决策」。我在后面几节会反复提到这个边界,因为所有翻车都源于我越过了这条线。

1.2 我给它划定的工作边界:能放权与不能放权

在实际动手前,我给 Claude Code 划了三条边界,这个动作我认为比任何技术选型都重要。

  • 能放权的:项目脚手架搭建、依赖安装、通用组件编写、接口 CRUD 代码生成、单元测试编写、报错排查。这些任务目标明确、规律性强,AI 的速度是手写的数倍。
  • 能放权但必须复查的:数据库 Schema 设计、状态管理方案、组件划分。它能给出合理方案,但往往不是最适合你这个项目的方案,需要人来做最终判断。
  • 不能放权的:产品需求定义、生命周期阶段的业务规则、提醒策略的体验设计。这些是「凭什么这么做」的问题,只有了解用户的人能定。

我把这个边界写进第一轮对话里,相当于给它一个「工作守则」。之后每一轮协作,它都会遵循这个守则执行。事实证明这个过程很省心。

2. 开工之前:把「宠物生命周期管理」拆成可落地的需求文档

很多人用 AI 写代码失败,不是因为工具不行,而是因为需求本身是糊的。我在开始写任何代码之前,先用两个晚上把产品定义梳理清楚。

2.1 需求原型的「一页纸」:MVP功能清单

宠物生命周期管理 App 这个名字听起来很宽泛,落到功能层面其实是五件事:

  • 宠物档案:添加/编辑多只宠物,记录姓名、种类、品种、生日、性别、绝育状态、头像。
  • 体重记录与曲线:定期记录体重,能看到一条随时间变化的曲线,这是健康判断的基础数据。
  • 健康日历:统一管理疫苗接种、驱虫、体检、用药等事件,记录时间、下次时间、间隔周期。
  • 提醒系统:根据健康日历自动生成「该打疫苗了」「该驱虫了」这类的提醒。
  • 生命周期阶段:根据宠物种类和年龄自动推算当前处于幼年、成年还是老年阶段,并给出对应的关怀建议。

这些东西如果一开始全做,项目周期会拖得没头没尾。我明确圈定 MVP 范围:档案 + 体重曲线 + 健康日历里的疫苗记录 + 提醒列表。至于生命周期阶段展示,作为首页的一个模块先做出来,但不做复杂的推送。

2.2 技术选型的取舍:为什么是Web App+PWA

对于「App」这个词,常规思路是 React Native 或者 Flutter。我最终选择了 Web 技术栈:React + Vite + Tailwind CSS 做前端,Express 做后端,SQLite 做数据库,最终通过 PWA 方式让它可以「安装」到手机桌面。

理由很朴素:一个人做项目,时间是最稀缺的资源。Web 全栈的迭代速度最快,调试工具最成熟,SQLite 零运维成本。PWA 虽然不如原生 App 能调用系统级能力,但对于「记录宠物健康信息」这个场景,桌面图标、离线可用、本地通知这几个能力已经足够。Claude Code 在 Web 技术栈上的训练数据也最充足,生成的代码质量最高。

2.3 让AI反向输出TODO:用Claude Code验证需求完整性

需求清单列完,我没有直接让它写代码,而是先把需求描述喂给它,要求它「反向输出一份开发任务分解清单,并指出需求中模糊、可能产生歧义的地方」。

这一步的价值被严重低估。它输出的 TODO 里,有两条确实是我没想清楚的:一是「幼年/成年/老年」的定义没有明确标准,不同物种不同体型差异很大;二是提醒的「跳过逻辑」——如果用户漏打了一次疫苗,下次提醒应该按原计划顺延还是重置周期?这两个问题如果不提前定义,开发时必然返工。

我把这两条拍板:生命周期阶段按物种和体型分档定义,具体规则下一节讲;漏打后的提醒按「重置为新的起始日」处理。需求到这里才算真正可执行。

3. 从空目录到首版可运行:Claude Code的项目初始化实操

需求定了,接下来就是让 Claude Code 发挥长项的第一个环节:搭骨架。

3.1 从空目录到前后端骨架:一次会话搞定

我的操作方式是:在一个空目录里启动 Claude Code 会话,然后给它一段完整的任务描述——我要做什么项目、用哪些技术栈、目录结构希望怎么组织。它很快就开始执行,创建文件、生成配置、安装依赖,整个过程我可以实时看到它操作的每一步。

最终生成的骨架大概是这个样子:

pet-lifecycle-app/ ├── client/ # React + Vite + Tailwind 前端 │ ├── src/ │ │ ├── components/ # 各功能组件 │ │ ├── pages/ # 路由页面 │ │ ├── api/ # 后端接口封装 │ │ └── App.tsx │ └── package.json ├── server/ # Express 后端 │ ├── routes/ # 路由定义 │ ├── db/ # 数据库初始化与迁移脚本 │ ├── utils/ # 工具函数(生命周期计算、日期处理等) │ └── index.js ├── package.json # 根目录脚本,一键启动前后端 └── README.md

这一轮它干得干净利落。我在验证后做了一件值得提倡的事:要求它生成一份「项目启动说明」写进 README,避免第二天自己都忘了怎么跑起来。

3.2 第一次「npm run dev」后的连锁问题

骨架生成不等于能跑。第一次执行启动命令,问题一个接一个冒出来。

第一个问题是 Node 版本不匹配。我本机的 Node 版本比较旧,而它生成的 Vite 模板要求更高的版本。这不是代码问题,是环境问题。解决方式很简单:升级本机 Node 环境,然后重新安装依赖。

第二个问题是client里的开发服务器与server的 API 服务端口不一致,前端请求后端需要跨域。Claude Code 给出的方案是在 Vite 配置里添加代理规则,把前端的/api请求转发到后端的启动端口。这个方案是可行的,但我在 review 时要求它解释为什么这样做——它说明了代理路径避免浏览器跨域限制的原理。我确认逻辑合理后才让它落地。

第三个问题是它自动生成的 TypeScript 检查比较严格,几个接口的类型没有对齐,导致编译报错。这类问题很适合丢给它:「编译报错了,你看下怎么修」,通常一轮就能解决。

3.3 首版代码的人工体检清单

跑通之后,我没有着急进入功能开发,而是做了一轮人工体检。我的体检清单大概是这样:

  • 依赖版本是否过新或过旧:Claude Code 倾向生成最新的依赖写法,有些 API 已经变化,需要按实际情况调整。
  • 目录结构是否真的符合项目体量:对于一个小型 MVP,它的分层刚好,没有过度设计。
  • 启动脚本和说明是否完整:确保换一台电脑也能五分钟跑起来。
  • 是否有无关的样板内容:生成的模板里自带了一些 Demo 组件,全部清理掉。

这一步虽然花了一个多小时,但避免了代码地基不稳导致全盘返工。看似「慢」,其实是快。

4. 宠物管理App的数据模型设计:AI建模过程的完整记录

骨架跑通后,最核心的一件事来了:数据模型。宠物生命周期管理 App 的所有功能都建立在这几张表之上,这里的设计好坏直接决定后面能不能顺畅迭代。

4.1 五张表的设计:宠物档案、健康记录、体重日志、提醒与生命周期事件

我在需求阶段就想好了核心实体,然后把这个粗框架交给 Claude Code,让它生成第一版 Schema。我告诉它的实体有:宠物(pet)、体重记录(weight_log)、健康记录(health_record)、提醒(reminder)、生命周期事件(lifecycle_event)。

它生成的表结构基本覆盖了我的需求,但有几个地方需要推敲。比如它最初把「下一次到期时间」直接存在健康记录表里,这初看合理,但一旦用户漏打、重置周期,这个字段就要连同提醒一起联动更新。我决定:健康记录表存「本次发生日期」和「推荐间隔天数」,下一次到期时间通过计算得出,不落库。这样保持了单一数据源,避免多份数据相互矛盾。

4.2 AI生成的Schema与我修正的细节

最终的数据库结构经过了几轮修正,核心表的要点如下:

CREATE TABLE pets ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, species TEXT NOT NULL, -- 'cat' | 'dog' breed TEXT, birthday TEXT NOT NULL, -- YYYY-MM-DD gender TEXT, neutered_flag INTEGER DEFAULT 0, avatar_path TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE health_records ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL REFERENCES pets(id) ON DELETE CASCADE, record_type TEXT NOT NULL, -- 'vaccine' | 'deworm' | 'checkup' | 'medication' title TEXT NOT NULL, occurred_date TEXT NOT NULL, interval_days INTEGER, -- 距下一次该事项的建议间隔,可为空 note TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE reminders ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL REFERENCES pets(id) ON DELETE CASCADE, health_record_id INTEGER REFERENCES health_records(id), type TEXT NOT NULL, title TEXT NOT NULL, remind_date TEXT NOT NULL, -- 到期日 status TEXT DEFAULT 'pending', -- 'pending' | 'done' | 'expired' created_at TEXT DEFAULT CURRENT_TIMESTAMP );

我修正的最重要的三个细节:

  • 外键都加了ON DELETE CASCADE:删除一只宠物时,它的健康记录、体重、提醒全部自动清理,不会留下孤儿数据。
  • 所有日期都用TEXT存储、格式统一为YYYY-MM-DD:这和时区问题直接相关,后面我会专门讲。
  • reminders表里的status字段必须加索引:因为用户打开 App 首页时,最频繁的查询就是「今天到期的待处理提醒」。

4.3 生命周期阶段的业务规则:猫狗不同、体型不同

这个规则是整款 App 里唯一需要「产品判断」的地方,AI 不能替我做,但可以把规则翻译成代码。

我定义的规则是:

  • 猫:不满 1 岁为「幼猫」,1 到 7 岁为「成年猫」,7 岁以上为「熟龄猫」。
  • 狗:不满 9 个月为「幼犬」;之后按体型区分——小型犬(10kg 以下)9 个月到 8 岁算成年,8 岁以上算老年;中型犬(10-25kg)9 个月到 7 岁算成年;大型犬(25kg 以上)9 个月到 6 岁算成年。

这个划分肯定有争议,不同机构的标准不同。但产品必须有明确规则,后续如果要做精准化,可以把品种差异做得更细。关键是:这种判断不该由 AI 生成,而应该由产品拥有者确认。

我把规则文档写好,然后让 Claude Code 按规则实现一个纯函数,输入物种、体重、出生日期,输出当前阶段标签。这个函数也成了后面首页「阶段卡片」的数据来源。

5. 核心功能开发实录:提醒、健康日历、生命周期事件是怎么一步步长出来的

数据模型落地后,功能开发进入正题。我没有一次性丢给 AI 一个巨型需求让它一口气写完,而是拆成三个迭代,每轮聚焦一个能独立验证的功能。

5.1 迭代一:宠物档案的增删改查

第一轮迭代做档案 CRUD。我给 Claude Code 的任务是:「实现宠物列表页、新增页面、详情页和编辑功能,表单包含所有 pets 表字段,姓名和种类必填,生日用日期选择器,性别用单选,保存成功后跳转详情页」。

这一轮它在 20 分钟内给出了完整的前后端代码。但我在 review 时发现它犯了一个典型错误:表单里的「体重」字段直接放了一个文本输入框。这会导致用户填入任意文本,脏数据流向后端。我不能接受这个设计。

我要求它改成专门的数字输入组件,并加一个联动逻辑:用户在新增宠物时填写初始体重,系统自动生成一条体重记录,并作为体重曲线的起点。它修改后的逻辑是对的,这个例子也说明:AI 生成的代码可以很快,但「产品交互的合理性」仍需要人来盯。

5.2 迭代二:健康日历与间隔提醒

这一轮的核心是健康记录和提醒的联动。业务逻辑是:用户在健康日历里新增一条疫苗记录,填写接种日期和推荐间隔天数,系统自动在「接种日期 + 间隔天数」生成一条待办提醒。

这里涉及一个隐藏条件:如果用户给同一只宠物添加了同类型的第二条记录(比如第二次疫苗),那么之前那条记录对应的未完成提醒应该被自动标记为「过期」,然后新生成一条提醒。这个逻辑很容易被忽略,我用自然语言描述了这个需求,Claude Code 很好地理解了「旧提醒过期、新提醒生成」的事务关系,并且把它实现在同一个数据库事务里,保证了数据不会出现「两条疫苗提醒同时 pending」的情况。

5.3 迭代三:生命周期事件的时间线

最后一轮是生命周期事件。这里的体验点在于:与其冷冰冰地显示「你的狗处于成年期」,不如把阶段变化做成有温度的时间线。

我在首页设计了一个「生命阶段进度条」,按照当前宠物所属物种和体型,把生命周期拆成几个阶段,用进度环展示当前走到哪个阶段,旁边显示一句文案,比如「奶狗期结束,进入叛逆期」「要开始注意关节健康了」。同时,宠物满岁、转阶段时生成一条「里程碑事件」记录,展示在时间线页里。

Claude Code 在实现时间线组件和里程碑生成逻辑上表现不错。但我后来又手动加了一个细节:转阶段的历史事件没有回填,也就是说一条宠物从幼年成为成年时,时间线上能看到「成年」这个里程碑,但看不到一条「幼年结束」的记录。我让它补了一个逻辑:计算阶段转换点在时间线上是否应该展示。这类细节是人更容易察觉的,AI 默认只会按你描述的需求做,描述得越细,成品越完整。

5.4 协作心法:怎么给AI下达清晰任务

三轮迭代下来,我发现一个规律:我给 Claude Code 的任务描述质量,直接决定代码产出质量。

我的任务描述模板是四段式:

  • 背景:先说清楚当前项目的上下文。例如「我们已经有 pets 表和 health_records 表,结构如下……」
  • 目标:一句话说清这次要实现什么功能,解决什么问题。
  • 约束:明确技术栈、命名规范、需要遵守的既有代码风格。
  • 验收方式:说清楚「我期望看到的效果」,必要时举例。

这样它输出的东西几乎不需要风格统一性的大改,我只需要关注业务逻辑是否正确。

6. 前端体验打磨:AI做界面时的通病与我的修正方案

因为要保证整体完成度,我专门留了一轮给前端体验。这一轮的主角不再是写功能,而是「挑毛病」。

6.1 AI界面产品的三个典型毛病

当 Claude Code 首轮生成的界面跑起来时,我看到了三个典型的通病。

第一个是「模板感」。因为 AI 的生成逻辑倾向于「按常见模式套」,所有页面都是顶部导航加内容区、卡片加按钮的通用布局,功能上没问题,但缺少产品想要的情感层次。宠物管理这种偏生活化的产品,界面应该更温暖、更有「陪伴感」,而不是一个表格后台。

第二个是空状态缺失。第一次使用 App 的用户的宠物列表是空的、健康日历是空的。AI 默认会在这种时候渲染一个空白页面,用户完全不知道下一步该干嘛。这是产品体验的大缺口。

第三个是移动端适配粗糙。虽然用了 Tailwind 的响应式类,但组件在窄屏下的换行、间距、列表滚动表现明显不佳。既然目标是 PWA 安装到手机用,这个必须重做。

6.2 把首页改造成「驾驶舱」:宠物卡片、今日提醒、阶段进度

我的修正方案是重新设计首页信息架构,让它变成「一打开就能看到最重要的三件事」的驾驶舱页面:

  • 顶部是当前选中宠物的头像卡片,看一眼知道是哪只宠物。
  • 中间是一个大号的今日提醒卡片:今天到期的疫苗、驱虫事项,有「标记完成」按钮直接操作。
  • 下方是生命周期阶段进度条和一句阶段寄语。
  • 再往下才是健康日历的最近记录入口。

这个重构让 Claude Code 擅长和不擅长的部分都充分暴露了:让它实现布局、响应式、进度条组件,很快;但「信息优先级判断」是我的职责。我给它的关键指令是「首页只保留一个主要行动点,其余都做成入口」,它执行的正是这个判断。

6.3 PWA与移动端适配的落地操作

把 Web 应用变成可安装的 PWA,需要做三件事:配置 manifest 文件、注册 Service Worker、准备合适的图标。

Claude Code 完成了 manifest 和 Service Worker 的基础版本,但我发现 Service Worker 的缓存策略有问题——它默认做了「网络优先」的缓存,结果开发环境下修改代码后页面一直显示旧版本。我让它改成「网络优先、缓存兜底」的策略,并且在后端接口请求上配置了排除规则,避免 API 响应被错误地缓存。

移动端适配方面,我要求所有主要页面在 375px 宽度下走一遍,逐屏截图检查。发现的问题包括:日期选择器被键盘遮挡、宠物卡片图片在窄屏下变形、表格类内容在手机上横滚。这些问题说不上是 AI 的错,它们只存在于「认真用真机/模拟器过一遍」这个环节。

7. 测试与上线前检查:AI生成的代码不能直接上生产

功能全部跑通后,我意识到一件事:Claude Code 生成的代码,如果直接发布,风险极高。它在写代码时目标是「实现功能逻辑」,而不是「覆盖所有边界情况」。用户不会按你预期的路径操作,数据也不会总是干净的。

7.1 测试策略:只测核心不追覆盖率

对于这类小项目,追求测试覆盖率不现实,也不划算。我的策略是:只对两类逻辑写单元测试,一类是生命周期阶段计算函数,另一类是提醒到期日期计算。

比如生命周期阶段函数,输入不同的物种、体重、出生日期,必须稳定输出正确的阶段和对应的文案。这类纯函数测试起来成本低收益高。提醒日期计算则要覆盖间隔跨月、跨年的场景。

UI 层面我不做单测,但做了两轮手动验收:第一轮按正常流程走一遍(新增宠物到标记提醒完成),第二轮故意走「反人类」流程(空着必填项提交、重复点击保存按钮、同一只宠物快速添加多条疫苗记录)。第二轮抓出的 bug 比第一轮多得多。

7.2 三次实测翻车与根因

必须承认,测试阶段翻车不少,我挑了三个典型的说说。

第一个是日期偏移。这个问题在提醒计算里暴露。当时 Claude Code 生成的逻辑里用了new Date('YYYY-MM-DD')这种方式,代码在其本机环境里跑没问题,但部署到服务器后,由于服务器时区设置不同,部分日期被解析成前一天。根因是「把日期字符串当成了时间戳来处理」。修复方式是:所有日期处理逻辑都统一用「年月日拆分计算」,不经过new Date()的时区转换。这也是我在数据模型设计时坚持日期用TEXT存储的原因。

第二个是 SQLite 的并发写入问题。本地开发时通常只有我一个连接,但上线后有多个用户同时写入提醒时,SQLite 会报「database is locked」。这个问题不是 AI 能单独解决的,它源于选型。我的处理思路是:所有写数据库的操作强制经过同一个连接串行执行,并且把单次事务时间压到最短。对一个小型 MVP 来说,这个方案代价最低。

第三个是提醒重复触发。标记为「已完成」的提醒,在列表重新渲染后偶尔会变回待办。排查后发现,前端更新状态时只是改了本地内存里的对象,没有同步调用后端接口,导致刷新后数据还是旧的。修复方式很简单:把状态更新改为「乐观更新 + 后端确认回写」。这也提醒了我:AI 改前端交互逻辑时,不太会自动补齐「数据一致性」的闭环,需要人去推演数据流。

7.3 上线前的安全与部署清单

部署之前我自查了三件事:

  • 环境变量全部外置:数据库路径、接口密钥、监听端口,不能写死在代码里。Claude Code 生成的基础代码里隐藏了一个「默认口令」配置,这类硬编码必须清理。
  • 输入校验覆盖后端:前端校验可以提升体验,但后端必须自己再做一层校验。我要求它在所有写接口上加了字段校验,非法数据一律 400 拒绝。
  • 依赖安全扫描:运行依赖检查命令,确认没有高危漏洞,有的话逐项升级或处理。

部署路径上,我最终选择的是:前端构建后部署到支持静态资源的托管平台,后端 Express 部署到一个支持 Node 的托管服务,SQLite 数据库文件存放在后端的持久化存储目录里。为了演示方便,整个部署过程也是让 Claude Code 配合执行的,但每一步生成的环境配置我都先看懂、再执行。

这轮做完,项目就到了一个「可以真正用起来」的状态。从有这个想法到跑通全流程,花了大约两周的业余时间,其中大量琐碎工作由 AI 分担,我在其中的角色更像产品经理加代码审查员。

最后再分享一个小技巧:多轮协作之后,Claude Code 会积累大量上下文。每次让它完成一个大阶段,我会让它顺手把这个阶段的改动要点、涉及文件、尚未解决事项写进项目里的一个开发日志文档。这个习惯帮了大忙——因为我发现它对自己的操作是有短期记忆的,但「周一来、周五用」,中间的决策过程可能就模糊了。让 AI 把工作留痕在项目里,相当于给自己的工程流程加了一个「思维备份」。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进