用Claude Code从零开发全栈宠物管理App:AI辅助编程实战与避坑指南

发布时间:2026/10/18 9:41:58
用Claude Code从零开发全栈宠物管理App:AI辅助编程实战与避坑指南
最近我用 Claude Code 从零搭了一个宠物生命周期管理 App从需求梳理、数据库设计、接口开发到前端页面、联调测试和部署上线几乎全程在终端里用自然语言驱动完成。这篇不是广告也不是那种十行代码做出一个产品的噱头文而是把我实际跑通的这一套流程连踩过的坑和绕过的弯路一起复盘出来。你如果正打算用 AI 辅助开发新项目、又担心 AI 生成的东西烂尾或者没法收场这篇内容应该对你有直接帮助。先说结论AI 不是不能从零做项目而是很多人用错了方式。把它当成一个不需要睡觉、但偶尔会胡说八道的结对工程师明确交代任务边界、逐步验收、随时回滚整个流程可以跑得非常顺。下面我把每一个环节都拆开讲包括我当时是怎么跟 Claude Code 对话的、为什么做某些技术选型以及在哪些地方差点把项目搞崩。1. 项目选题与技术方案怎么定下来的1.1 为什么选宠物生命周期管理这个方向做新项目最容易踩的坑就是需求太泛。我见过不少人上来就想让 AI 做个智能家居平台结果聊了十几轮AI 连要交付什么都说不清楚。所以选项目时我刻意挑了一个功能边界清晰、但又有足够深度的方向宠物生命周期管理。养宠人群的真实痛点其实很具体不知道什么时候该打第三针疫苗、上次驱虫是什么时候、猫咪从几岁开始算进入老年期、体重连续三个月上涨要不要干预。市面上很多宠物 App 不是偏社交就是偏记账真正围绕生命周期来做提醒和健康管理的反而不多。这个选题的数据模型不复杂但也不是无脑的增删改查它包含时间线、年龄计算、到期提醒、趋势统计这些正好能检验 AI 在业务逻辑上的处理能力。另一个原因是这个项目的领域知识相对稳定。猫狗的生命周期划分、疫苗驱虫的常见周期、体重变化的参考区间这些都能在公开资料里找到相对统一的说法不太会出现AI 瞎编行业规则的问题。对 AI 辅助开发的新手来说选一个有规则可循的领域成功率会高很多。1.2 技术栈选型全栈 TypeScript 一条龙技术栈是我在让 AI 写代码之前就定好的没有把这种关键决策交给 AI。最终选型是Next.js TypeScript Tailwind CSS Prisma SQLite前端和后端放在同一个代码库里。为什么不用前后端分离我实际对比过两种方案。前后端分离意味着两个项目、两套依赖、两套部署Claude Code 在切换上下文时经常会把前端项目里的信息带到后端去造成一些莫名其妙的类型错乱。单体 Next.js 项目的好处是整个项目只有一个代码库AI 读取目录结构、搜索文件、修跨层 bug 都只需要在一个上下文里完成效率高得多。对一个人 AI 的团队结构来说减少上下文切换就是减少出错。数据库先用 SQLite这可能是最有争议的选择。很多人觉得 SQLite 不适合做产品但对 MVP 阶段来说它零配置、单文件、不需要单独部署数据库服务能让整个项目从开发到上线省掉一大半环境问题。Prisma 层面做了抽象后续用户量上来直接改成 PostgreSQL迁移成本不会太高。更重要的是AI 生成代码时SQLite 相关的报错远比 PostgreSQL 少因为不需要处理连接池、权限、网络这些问题。1.3 Claude Code 在这条链路里到底扮演什么角色很多没实际用过 AI 编程工具的人对它有两个极端认知要么觉得它就是个高级自动补全要么觉得它能完全替代程序员。这两种都偏了。Claude Code 这类工具的能力边界是能读写项目文件、能在终端执行命令、能搜索整个代码库、能一次处理大量文件。实际用下来它最擅长四件事搭脚手架、写 CRUD 代码、写测试、解释报错信息。最不擅长的事情则是替你定义产品方向、替你权衡架构、替你做部署决策。这些事如果丢给它它会给出一版看起来很像样、实际完全不适合你场景的方案。在整个项目里我给自己定的角色是技术负责人它负责执行和出方案。我提需求、审代码、做决策它负责落地。这个协作模式在后面几乎没有出现过失控的局面最关键的原因就是我一开始就没指望它替我做判断。2. 开工前要准备的几样东西2.1 本地环境与项目保险机制在让 AI 写任何代码之前我先花了一个小时把所有基础环境清零安装 Node.js 20、配置好 pnpm、确认终端能正常访问代码托管平台。Claude Code 本身按官方文档方式安装后在项目目录里敲claude就能进入对话界面。这里有个特别重要的习惯先把空目录变成 Git 仓库提交第一版空提交。AI 改代码的能力很强但破坏代码的能力同样强。有一次它为了调整一个接口的返回结构顺手把另一个文件的组件签名也改掉了直接导致二十多处引用报错。如果我当时没有在改动前提交版本光靠回滚这段对话恢复现场会非常痛苦。现在我的习惯是每次让 AI 做一批改动之前先让它把改动方案列出来我确认后再执行执行完立即看 diff确认没问题就提交。对于完全没有终端基础的人来说这个阶段可能是最有门槛的部分。但反过来看哪怕你不懂代码把环境跑起来、学会看 git diff 是不是只改了预期文件这件事花不了半天。AI 能帮你生成代码但没人能帮你确认这次改动影响了什么这个底线得自己守住。2.2 让 AI 先把需求和数据模型写清楚很多人打开 Claude Code 第一句话就是帮我做一个宠物 App这基本等于让一个刚入职的工程师直接上手重构核心系统。我的做法是分三步走。第一步让它输出一版需求文档。我给的指令大概是这样的你现在是一名产品经理兼全栈工程师。我要做一个宠物生命周期管理 App目标用户是养猫养狗的人。请基于以下功能清单输出一份 PRD 1. 宠物档案管理记录品种、生日、性别、绝育状态 2. 疫苗和驱虫记录支持预设到期日与提醒 3. 体重记录能绘制成长曲线 4. 医疗记录记录就诊和用药情况 5. 生命周期阶段展示按年龄自动计算幼年/成年/老年 请先输出完整的 PRD 文档重点写清楚用户角色、核心模块、页面清单、数据字段。不要写代码。这段指令的关键在于最后那句不要写代码。AI 有一种急于展示能力的倾向你不拦着它它就会跳进代码细节。让它先写文档是因为后面所有代码都会围绕这份文档展开文档错了代码全错。第二步让它把 PRD 里的数据模型单独抽出来。我要求它给出每个表的字段、类型、关系、枚举值输出成 docs/data-model.md。这一步花了很长时间反复对齐因为 AI 默认会给每个表加上 created_at 到 updated_at 到 deleted_at我明确要求它去掉用不到的软删除字段保持最小可用设计。第三步让 AI 基于数据模型输出 API 清单。这个清单不是让它生成代码而是列出每个页面需要调用哪些接口、传什么参数、返回什么结构。做完这三步项目在代码层面之前已经有了完整的施工图。2.3 脚手架初始化让 AI 跑命令但参数要人定初始化项目的指令比我预想的要顺利。我直接在 Claude Code 里输入在当前空目录下初始化一个 Next.js 14 项目使用 TypeScript、Tailwind CSS、App Router包管理器用 pnpm其余选项默认。初始化完成后输出目录结构摘要。Claude Code 会直接调用脚手架命令处理交互式提问跑完安装流程后把目录结构列给我。但在这一步要注意一个细节脚手架命令的版本参数要自己确认。AI 对最新稳定版的判断经常滞后有时候它会装一个自己训练数据里见过的旧版本导致后面一系列兼容问题。我一般会自己先跑一遍create-next-applatest这类命令或者明确告诉它目标版本号。初始化完成后我做的第一件事是让它把 Tailwind 配置里的内容区域确认一遍然后把项目依赖提交到 Git。很多教程会忽略这一步但我建议每个人都在装完依赖的第一时间提交因为此时项目是最干净的状态后面不管发生什么都有一个可靠的起点。3. 从零到能跑的 MVP核心功能逐步落地3.1 数据模型与数据库初始化让 AI 生成 Prisma Schema数据模型文件是我们前面在文档阶段已经对齐过的所以这一阶段基本就是把文档翻译成 Prisma Schema。我让 Claude Code 按照 docs/data-model.md 生成完整的 schema.prisma并且要求它把枚举值和关系约束写在注释里。实际的 schema 长这样也是让它后续反复参照的基准// prisma/schema.prisma generator client { provider prisma-client-js } datasource db { provider sqlite url file:./dev.db } enum PetSpecies { CAT DOG } enum LifeStage { PUPPY_KITTEN ADULT SENIOR } model Pet { id String id default(cuid()) name String species PetSpecies breed String? gender String birthDate DateTime adoptionDate DateTime? neutered Boolean default(false) avatarUrl String? notes String? createdAt DateTime default(now()) updatedAt DateTime updatedAt vaccines VaccineRecord[] dewormings DewormRecord[] weights WeightRecord[] medicalRecords MedicalRecord[] } model VaccineRecord { id String id default(cuid()) petId String pet Pet relation(fields: [petId], references: [id], onDelete: Cascade) name String givenDate DateTime nextDate DateTime? notes String? createdAt DateTime default(now()) } model WeightRecord { id String id default(cuid()) petId String pet Pet relation(fields: [petId], references: [id], onDelete: Cascade) weightKg Float recordedAt DateTime default(now()) }这段 schema 里有两个值得注意的设计决策。第一所有关联表的外键都加了 onDelete: Cascade这样删除宠物时关联记录会自动清理不会留下孤儿数据。第二疫苗和驱虫记录没有做成一张表虽然它们的字段很像但业务语义差别很大合并会让后续提醒逻辑的判断变复杂保持独立更清晰。生成后我让它直接执行npx prisma migrate dev --name init。migrate 失败也是这个阶段最常见的问题多数是数据库文件路径和权限问题把报错原样贴回对话AI 基本都能解决。3.2 后端接口与业务逻辑把计算和增删改查分开处理数据库初始化完成后接下来是 API 层。项目用到的是 Next.js App Router接口写在 route.ts 文件里我让 Claude Code 按功能模块分批生成/api/pets宠物列表与新增/api/pets/[id]宠物详情、编辑、删除/api/pets/[id]/vaccines疫苗记录管理/api/pets/[id]/dewormings驱虫记录管理/api/pets/[id]/weights体重记录管理/api/reminders统一提醒任务查询生成 CRUD 接口这部分AI 表现得最稳定。但我在 review 代码时发现了两个问题。第一个是缺入参校验。AI 生成的接口直接使用请求体里的数据写入数据库如果前端传了类型错误的值数据库层面可能报错或者更糟一个 undefined 写进字段。我统一加了 Zod 校验每个接口都有一个对应的 schema校验失败返回 400。最开始我觉得这会让代码量翻倍但实际让 Claude Code 补齐这些校验只花了几轮对话安全性提升却很明显。第二个问题在业务逻辑层。项目的核心不只是增删改查还有生命周期计算。这部分我要求 AI 写成独立的纯函数不放进 API 路由文件里方便测试和复用// lib/petLifecycle.ts import { PetSpecies, LifeStage } from prisma/client; export function getAgeInMonths(birthDate: Date, now new Date()): number { const diffMs now.getTime() - birthDate.getTime(); return Math.floor(diffMs / (1000 * 60 * 60 * 24 * 30.44)); } export function getHumanAgeYears(months: number, species: PetSpecies): number { // 常见换算方式第一年约等于15岁第二年约等于24岁之后每年约等于4-5岁 if (species PetSpecies.DOG || species PetSpecies.CAT) { if (months 12) return 15; if (months 24) return 24; return 24 Math.floor((months - 24) / 12) * 4; } return 0; } export function getLifeStage(months: number, species: PetSpecies): LifeStage { if (species PetSpecies.CAT || species PetSpecies.DOG) { if (months 12) return LifeStage.PUPPY_KITTEN; if (months 84) return LifeStage.ADULT; // 7年以内 return LifeStage.SENIOR; } return LifeStage.ADULT; }把年龄计算单独拆出来而不是让 AI 把它塞在某一个接口里这是我复盘后最满意的决策之一。不然当页面同时需要显示当前阶段和相当于人类年龄时就得重复写两遍还容易不一致。提醒查询接口也在这里一起做掉。核心逻辑是查询疫苗和驱虫记录里 nextDate 在最近七天到逾期未完成的数据按到期时间排序。MVP 阶段没有引入消息队列或定时任务前端进入提醒中心页面时实时查询就够用真的到了需要推送通知的时候再考虑任务系统也不迟。3.3 前端页面与联调把设计交出去把布局拿回来前端页面的生成是 Claude Code 效率最高也最需要盯着看的环节。我按页面逐个生成我的指令是在 app/pets/[id]/page.tsx 中生成宠物详情页包含 - 顶部返回按钮和宠物头像、名字、品种信息 - 生命周期状态卡片显示当前阶段、相当于人类年龄、下次需要做的疫苗或驱虫 - 近期提醒列表显示未来7天到期的记录 - 体重曲线图用 recharts 展示最近半年的体重变化 - 疫苗记录表格 - 医疗记录列表 所有数据通过 fetch 调用 /api/pets/[id] 和 /api/reminders 获取请先梳理需要的数据结构再输出页面代码。注意最后一句请先梳理需要的数据结构再输出页面代码这个约束很重要。直接让 AI 写页面它会自创一些接口字段导致前端拿到的数据和后端返回的不一致。让它先梳理数据结构等于强制它把后端接口文档再读一遍。连续生成几个页面之后我发现了一个反复出现的问题AI 喜欢在服务端组件里直接用 fetch 拉数据但项目里部分页面需要用到浏览器 API 处理状态导致use client的位置经常报错。遇到这种问题我会直接在对话里指出来当前页面在 app/pets/[id]/page.tsx 中注意它被父组件作为服务端组件引用但内部用了 useState 和 useEffect这会产生 Hydration 错误。请把这个页面改成客户端组件并确认所有数据加载逻辑只在客户端执行。这种多轮对话修正非常常见我的经验是不要指望一次就完美接受AI 写第一版人来定约束AI 再改第二版这个节奏。列表页和表单页也都让 Claude Code 生成了。表单页是容易出问题的地方因为 AI 对表单校验逻辑的生成往往过于随意。我要求所有表单统一用 Zod 定义校验规则提交失败时把 error 对象里的中文消息渲染在对应字段下方。这样虽然让 AI 多写了一些代码但从体验上避免了很多明明报错但不知道怎么改的尴尬。3.4 提醒、生命阶段这类关键逻辑怎么让 AI 实现这个项目最核心的价值在生命周期四个字上不能只做一个花哨的记录本。所以有三段逻辑我花了很多精力让 AI 打磨。第一是生命周期时间轴。宠物详情页顶部有一条横向时间轴标记出当前处于哪个阶段每个阶段对应什么样的照护建议。比如幼年期提示按月驱虫、成年期提示关注体重和牙齿、老年期提示半年一次体检。这些内容在 PRD 阶段就让 AI 整理好了页面只是把它渲染出来。第二是动态提醒算法。不是简单查一下到期记录而是按宠物的生命周期阶段自动调整提醒优先级。幼年猫狗的疫苗密度普遍更高老年宠物的体检提醒要更突出。实现方式是写一个 reminderPriority 函数输入是宠物阶段和记录类型输出是提醒的显示权重在 API 层已经计算好前端直接按权重排序展示。第三是标准化的建议知识库。我把常见猫狗品种的寿命范围、疫苗周期、驱虫周期整理成一个常量配置让 Claude Code 输出到一个 ts 文件里。这部分不是严格意义上的药品指导就是通用的养护常识用来做页面上的辅助文案展示。写这类内容时AI 反而比真人更谨慎它给出的措辞都比较保守不会出现必须一定能治这类误导性表达。4. 测试、部署与后续扩展4.1 自动化测试只测关键逻辑不追求覆盖率MVP 阶段的测试策略应该务实。我没有让 AI 给所有接口都写测试那样工作量大、收益也低。我让它重点测了三块内容。第一块是 petLifecycle.ts 里的纯函数。这些函数输入输出清晰非常适合单元测试而且如果生命周期划分出错整个产品核心就错了。第二块是提醒查询逻辑我把它单独抽出来变成一个函数输入一组记录、返回应展示的提醒列表测各种临界情况恰好七天、逾期、无提醒。第三块是 API 路由的基础冒烟测试验证每个接口对正常请求和非法请求的返回状态码。测试框架用的 Vitest因为项目本身就是 Vite 生态配置成本几乎为零。让 AI 生成测试用例的文件然后手动跑一遍看覆盖了哪些分支没覆盖的再补。这个阶段 AI 的表现比写业务代码更稳定因为它更擅长根据既定规则生成用例这种模式匹配工作。4.2 部署方案与上线细节部署是我唯一没有完全交给 AI 的环节。不是说 AI 做不了而是部署涉及账号、域名、环境变量这些敏感信息我倾向于自己核对。整个应用本质是一个 Next.js 全栈项目加一个 SQLite 文件所以部署方案其实很轻量。我用 Docker 打包生成的 Dockerfile 分成两阶段先跑构建再把产物和运行依赖复制进一个精简镜像。启动命令是node server.js而不是直接next start因为 Next.js 的独立输出模式更节省容器体积。SQLite 的持久化是个必须处理的细节。容器本身是无状态的数据库文件如果写在容器层每次重启部署数据就会丢失。我把数据库文件挂载到一个持久化目录然后在环境变量里指定数据库路径。这里踩过一个坑Prisma 在容器里找数据库文件时路径可能和本地不一致。解决方式是让 Prisma 的 datasource url 从环境变量读取本地和容器各自配置自己的路径。上线之后我持续观察日志重点看有没有未捕获的异常和慢查询。SQLite 并发能力有限但一个个人项目的访问量完全没问题。期间出现过一次接口偶发 500排查下来是数据库文件锁冲突加了 WAL 模式就稳定了。5. 全程踩过的坑与排查技巧5.1 Prompt 沟通的常见错误以及怎么绕开这一路我总结出 Prompt 沟通中最容易犯的三个错误。第一个是一次给太多需求。有一次我让它把宠物页顺便优化一下加上删除确认同时把列表改成卡片式布局再顺便修一下返回按钮结果它一次性动了十几个文件把不相关的模块也改出问题。现在我的习惯是一次对话只做一件事哪怕这件事要分好几轮也要保持单一目标。这确保了每个改动都可以被 review、被回滚。第二个是不给边界约束。AI 默认有过度实现的倾向。你让它加一个删除功能它可能顺手加上批量删除、回收站、删除确认弹窗。这些不是错但对小项目来说是负担。我现在会在指令里明确写只做 X不要做 Y不要改 Z 相关代码会省掉大量 review 时间。第三个是不把错误信息原样贴回。很多人遇到报错会用自然语言描述它说有个东西找不到然后 AI 开始猜上下文。正确做法是把完整报错堆栈直接贴进对话让 AI 看到真实信息。它定位问题的速度会快非常多。5.2 AI 幻觉代码怎么识别怎么处理AI 生成代码时最可怕的问题不是写得差而是写得看起来完全正确实际根本跑不通。我遇到过它的典型幻觉包括引用了一个项目里根本不存在的依赖包、使用了与 Next.js 版本不兼容的 API、生成了某个根本没有安装在环境里的命令。我总结出一个三层排查策略。第一层凡是 AI 生成的代码里出现 import 或 require先检查 package.json 里有没有这个依赖、版本对不对。第二层凡是涉及 API 调用的都要去确认这个 API 在项目当前版本的文档里真实存在。第三层跑测试或跑构建用报错来验证。这个方法很土但非常有效。说白了AI 写作代码时自信和正确是两个维度的事它可能非常自信地说出一件完全不存在的事。代码本身不会说谎跑一下就知道。5.3 常见报错速查表最近收到不少朋友的私信问各种报错我把高频问题整理成一张表可以直接对照排查现象大概率原因处理办法Cannot find module xxx依赖未安装或版本冲突检查 package.json跑 pnpm install核对版本号Prisma Client could not find the databasemigrate 没执行或环境变量指向错误执行 npx prisma migrate dev检查 DATABASE_URLType error: Property xxx does not exist on type前端拿到的数据结构和后端返回不一致对比 prisma schema 和 API 返回类型统一修正Hydration failed because the initial UI does not match组件用了 useState 却仍在服务端渲染在该组件顶部加 use client或调整数据加载位置listen EADDRINUSE: address already in use本地端口被占用检查占用程序或换启动端口如 pnpm dev --port 3010next build 时出现 .next 目录权限报错旧构建缓存损坏删除 .next 目录后重新 build这个表是我在开发过程中真实遇到的问题整理出来的不是凭空列举。如果你在项目里遇到其他报错最有效的办法依然是把完整报错贴给 Claude Code让它先解释原因再给出修复建议最后让它在终端执行修复命令。不要只贴一句话。6. 最后分享几点我对 AI 辅助开发的真实感受项目从零到能上线整个过程中 Claude Code 承担了百分之七八十的代码生成工作但我始终没有让它脱离执行者这个定位。它最大的价值不是替代思考而是把从想法到代码之间的距离压缩到极短让你可以把精力集中在产品逻辑和判断上。我个人实际跑完这个项目后最大的体会是AI 辅助开发更像开手动挡的车AI 是那个变速箱你依然是司机。你的换挡时机、路线判断、遇到坑的反应速度决定了这辆车能不能安全到达目的地。如果你完全放开方向盘它可能带你去一个地图上不存在的地方。另外一个小技巧是阶段性的成果要记得沉淀下来。我每完成一个模块就让 Claude Code 输出一份简短的 CHANGELOG写明这个模块做了什么、涉及哪些文件。后续你再让它改功能时它会更快地理解当前项目状态上下文续接也更自然。这个宠物生命周期管理 App 后续可以扩展的方向还挺多的接入地图 API 做附近宠物医院导航、增加多宠物家庭的数据看板、生成疫苗年度报告。只要你把基础的数据模型搭得足够稳这些功能都可以继续用 Claude Code 一个个补上去。