AI辅助从零搭建宠物全生命周期管理App:React Native+Fastify实战
1. 项目缘起与整体设计思路1.1 为什么选宠物生命周期管理这个方向养宠物这件事表面上看是喂食、遛弯、看病实际上背后是一条完整的时间线领养或购买、日常喂养、疫苗接种、驱虫、体检、发情期管理、配种或绝育、孕期护理、生产、幼崽成长、老年照护直到最后的临终关怀和纪念。每一个阶段都有不同的记录需求、提醒需求和数据管理需求。市面上大多数宠物类App只做了其中一小块比如单纯记疫苗、单纯做社区、单纯卖货真正把“生命周期”这条主线串起来的工具并不多。我这次想做的事情就是用AI辅助编码的方式从零开始搭建一个覆盖宠物全生命周期的管理应用。选择这个方向有几个原因第一业务模型足够复杂能真正检验AI在项目搭建中的能力边界第二需求场景清晰每个阶段该做什么事情是有行业共识的不需要凭空捏造第三数据关系有层次宠物、主人、事件、提醒、健康记录之间是多对多关系适合用来演示从数据建模到界面呈现的完整链路。这个项目适合谁参考如果你已经会用AI辅助写代码但每次都是从单个文件、单个函数开始不知道怎么让AI帮你把一整个项目从空目录搭到能跑起来那这篇内容就是写给你的。如果你是完全零基础也没关系我会把每一步的操作意图和判断依据都讲清楚你跟着做也能跑通。1.2 技术选型与整体架构决策在动手之前我先确定了技术栈。这里的选择逻辑不是“哪个最流行”而是“哪个最适合让AI参与生成同时后期维护成本最低”。前端我选了React Native Expo的组合。理由很直接宠物管理App的核心使用场景在手机端需要推送提醒、拍照记录、定位遛弯轨迹这些能力。Expo 把原生模块的配置复杂度降到了最低AI生成代码时不容易在原生配置环节卡住。而且 Expo 的热更新和预览机制让我可以在手机实机上快速验证AI生成的界面效果不用每次都走完整的打包流程。后端我选了Node.js Fastify SQLite开发阶段/ PostgreSQL生产阶段。Fastify 的插件体系清晰路由定义简洁AI生成路由代码时出错率低。数据库方面开发阶段用 SQLite 可以零配置启动等数据模型稳定后再迁移到 PostgreSQL迁移成本可控。状态管理用Zustand不用 Redux。原因很简单Redux 的样板代码太多AI生成时容易在 action、reducer、selector 之间产生不一致而 Zustand 的 store 定义就是一个普通函数AI理解起来更直接生成结果也更稳定。AI编码工具方面我使用的是 Claude Code 的命令行交互模式。它的优势在于可以读取整个项目目录的上下文理解文件之间的依赖关系而不是只盯着当前打开的那个文件。这一点在搭建新项目时特别关键因为新项目最大的问题就是“文件之间还没有建立关联”AI如果只看单个文件很容易生成互相不匹配的代码。整体架构分为四层数据层数据库表结构与迁移脚本、服务层业务逻辑与API路由、状态层前端数据缓存与同步、视图层页面组件与交互。每一层我都会让AI先给出方案我审核调整后再让它生成具体代码。这个“先方案后代码”的顺序非常重要后面会详细展开。1.3 让AI参与项目搭建的正确姿势很多人用AI写代码的方式是打开对话框输入“帮我写一个宠物管理App”然后期待它直接吐出一个完整项目。这种做法几乎必然失败因为AI不知道你的技术栈偏好、不知道你的数据模型、不知道你的界面风格它只能按照训练数据里最常见的模式去猜猜出来的结果往往和你的预期差很远。我的做法是分阶段、分层次、带约束地让AI参与。具体来说把整个项目搭建过程拆成六个阶段需求梳理与实体识别、数据模型设计、API接口定义、前端页面结构规划、核心功能实现、联调与问题排查。每个阶段只让AI做一件事做完之后我审核确认再进入下一阶段。在每个阶段给AI的指令中我都会包含三个要素当前阶段的明确目标、上一阶段的产出作为输入、本阶段的约束条件。比如在设计数据模型时我会把需求梳理阶段产出的实体列表和关系描述贴给AI同时约束它“使用 Prisma schema 语法所有表必须包含 createdAt 和 updatedAt 字段外键关系必须显式声明”。这样做的好处是AI的每次输出都是建立在我已经确认过的上下文之上不会出现“前面说要用A方案后面生成B方案代码”的割裂情况。而且分阶段之后每个阶段的输出量都不大我审核起来也快发现问题可以立即纠正不会等到最后才发现整体方向偏了。2. 核心细节解析与实操要点2.1 需求梳理阶段让AI帮你把模糊想法变成实体清单项目刚开始的时候我脑子里只有“宠物生命周期管理”这个大方向具体要管哪些东西、怎么管其实并不清晰。这时候直接让AI写代码是灾难因为它会按照自己的理解去补全需求补出来的东西大概率不是我想要的。我的做法是先自己做一轮头脑风暴把能想到的所有和宠物相关的事件、记录、提醒都列出来不用管顺序和分类先写下来。比如领养日期、品种、性别、绝育状态、疫苗记录、驱虫记录、体重变化、体检报告、用药记录、发情周期、配种记录、孕期检查、生产记录、幼崽信息、日常喂食、遛弯记录、洗护记录、纪念日、临终关怀。然后我把这份原始清单交给AI让它做三件事第一把清单中的条目归类到不同的生命周期阶段第二识别出哪些是实体需要独立建表的对象哪些是实体的属性第三指出清单中缺失但生命周期管理常见的关键项。这一步AI的表现很关键。实测下来它在“识别缺失项”上特别有价值。比如我漏掉了“宠物与主人的多对多关系”一只宠物可能有多个主人一个人也可能有多只宠物AI在分析时主动提出来了。还有“事件与提醒的关联关系”我原本把提醒当成独立功能AI指出提醒应该挂在具体事件上比如疫苗事件产生疫苗提醒这样数据关系更清晰。这个阶段的产出是一份实体关系清单格式大概是这样的实体宠物、主人、宠物主人关系、生命周期事件、健康记录、提醒、附件宠物属性名称、品种、性别、出生日期、领养日期、绝育状态、当前体重、头像事件属性事件类型、发生时间、备注、关联宠物、关联附件提醒属性提醒时间、提醒内容、关联事件、完成状态注意这个阶段千万不要让AI直接生成代码或建表语句。一旦进入代码层面讨论就会被语法细节带偏而需求层面的遗漏反而被忽略。先把实体和关系理清楚后面所有工作都是在这个基础上展开的。2.2 数据模型设计从实体清单到可执行的建表方案实体清单确认之后下一步是把它转化成数据库表结构。我用的工具是 Prisma因为它的 schema 语法接近自然语言AI生成和人工审核都比较容易。给AI的指令是这样的“基于以下实体清单生成 Prisma schema。要求每张表包含 id自增主键、createdAt、updatedAt宠物与主人通过中间表建立多对多关系事件表通过 petId 外键关联宠物提醒表通过 eventId 外键关联事件所有日期字段使用 DateTime 类型枚举类型用 Prisma enum 定义。”AI生成的 schema 初稿基本可用但有几个地方需要调整。第一个问题是它把“事件类型”直接写成了字符串字段没有用 enum。我让它改成 enum因为事件类型是有限集合疫苗、驱虫、体检、用药、发情、配种、生产、洗护、纪念日用 enum 可以在数据库层面做约束避免脏数据。第二个问题是它给“体重”字段用了 Float 类型。我改成了 Decimal因为体重记录需要精确到小数点后两位Float 在某些情况下会有精度丢失。这个细节AI不会主动考虑需要根据业务特点来判断。第三个问题是索引。AI生成的 schema 默认没有加索引但宠物管理App的高频查询是“某只宠物的所有事件按时间倒序排列”所以我在事件表的 petId 和发生时间上加了复合索引。这个优化在数据量小的时候看不出差别但事件记录积累到几千条之后查询速度差异就很明显了。调整后的核心表结构大概是这样的model Pet { id Int id default(autoincrement()) name String breed String? gender Gender birthDate DateTime? adoptDate DateTime? neutered Boolean default(false) currentWeight Decimal? db.Decimal(5, 2) avatar String? owners PetOwner[] events Event[] createdAt DateTime default(now()) updatedAt DateTime updatedAt } model Event { id Int id default(autoincrement()) petId Int pet Pet relation(fields: [petId], references: [id]) type EventType occurredAt DateTime note String? attachments Attachment[] reminders Reminder[] createdAt DateTime default(now()) updatedAt DateTime updatedAt index([petId, occurredAt]) } enum EventType { VACCINE DEWORM CHECKUP MEDICATION ESTRUS MATING PREGNANCY BIRTH GROOMING ANNIVERSARY } enum Gender { MALE FEMALE UNKNOWN }提示Prisma 的 migrate 命令会根据 schema 自动生成迁移文件但在开发阶段我建议先用prisma db push快速同步结构等模型稳定后再生成正式迁移文件。这样改字段的时候不用反复创建迁移记录效率高很多。2.3 API接口定义先定契约再写实现数据模型确定之后下一步是定义API接口。这里我踩过一个坑一开始我让AI直接写路由实现结果它写出来的接口路径和前端调用对不上参数格式也不一致联调的时候改了半天。后来我调整了策略先让AI生成一份API契约文档包含每个接口的路径、方法、请求参数、响应格式、错误码。这份文档确认之后再让AI按照文档去实现路由。这样前后端就有了共同的依据不会出现“各写各的”的情况。接口按资源划分核心的有这几组/api/pets宠物的增删改查/api/pets/:id/events某只宠物的事件列表与创建/api/events/:id/reminders某个事件的提醒管理/api/pets/:id/health-stats健康数据统计体重趋势、疫苗完成率等/api/owners主人信息管理每组接口的响应格式统一为{ code, data, message }结构code 为 0 表示成功非 0 表示业务错误。这个统一格式是让AI在生成每个路由时都遵守的约束避免出现有的接口返回数组、有的返回对象、有的直接抛异常的情况。在定义接口时有一个细节值得展开说分页参数的设计。事件列表可能很长必须分页。我让AI采用 cursor-based 分页而不是 offset-based因为事件是按时间倒序排列的用游标分页在数据插入频繁时不会出现重复或遗漏。具体做法是请求参数带cursor上一页最后一条的 id和limit响应中返回nextCursor。这个设计AI一开始没想到是我明确提出要求后它才实现的。2.4 前端页面结构规划让AI先画骨架再填肉前端部分我同样遵循“先结构后细节”的原则。先让AI根据功能清单规划页面结构确认后再逐个页面实现。宠物生命周期管理App的核心页面有这些首页宠物列表卡片显示头像、名称、品种、下次提醒事项宠物详情页基本信息、生命周期时间线、健康数据图表事件记录页按类型筛选的事件列表支持添加新事件提醒中心待办提醒列表按时间排序支持标记完成统计页体重趋势图、疫苗完成情况、各类型事件数量分布设置页主人信息、通知偏好、数据导出页面结构确认后我让AI为每个页面生成组件树。比如宠物详情页的组件树是PetDetailScreen包含PetHeader、PetInfoCard、LifecycleTimeline、HealthChart、EventQuickAdd。每个组件只负责一块内容数据通过 props 或 store 传递。这样做的好处是AI在实现每个组件时目标非常明确不会在一个文件里堆砌所有逻辑。而且组件拆分之后如果某个组件效果不好我可以单独让它重写不影响其他部分。实操心得让AI生成组件时一定要指定“这个组件接收哪些 props、内部状态有哪些、依赖哪些 store 数据”。如果不指定AI会按照自己的理解去组织数据流生成出来的组件往往和你的状态管理方案不匹配改起来很麻烦。3. 实操过程与核心环节实现3.1 项目初始化从空目录到可运行骨架第一步是创建项目。我用 Expo 的模板命令初始化前端用 Fastify 的脚手架初始化后端。这两个命令AI可以直接给出但要注意版本兼容性。前端初始化npx create-expo-applatest pet-lifecycle-app --template blank-typescript cd pet-lifecycle-app npx expo install expo-router expo-notifications expo-image-picker zustand后端初始化mkdir pet-lifecycle-api cd pet-lifecycle-api npm init -y npm install fastify fastify/cors fastify/multipart prisma prisma/client npx prisma init这里有一个细节Expo 的版本和 React Native 的版本有对应关系如果AI给出的版本组合不对安装后会报错。我的做法是让AI先查一下当前 Expo SDK 的最新稳定版本然后根据这个版本去确定其他依赖的版本。实测下来让AI“先确认版本再给命令”比“直接给命令”的出错率低很多。初始化完成后我让AI生成一个最小的可运行验证前端显示一个“宠物列表”占位页面后端提供一个/api/health健康检查接口。两边都跑起来之后前端调用后端接口确认网络连通。这一步看起来简单但它是后续所有开发的基础如果连不通后面写再多功能也没用。3.2 数据库迁移与种子数据数据库部分我用 Prisma 管理 schema 和迁移。前面已经设计好了 schema接下来是执行迁移和填充种子数据。迁移命令npx prisma migrate dev --name init种子数据我让AI生成了一份包含三只示例宠物和它们的事件记录。种子数据的作用不只是填充数据库更重要的是给前端开发提供真实的测试数据。没有种子数据前端页面只能显示空状态很多布局问题看不出来。种子脚本的核心逻辑// prisma/seed.js const { PrismaClient } require(prisma/client) const prisma new PrismaClient() async function main() { const pet1 await prisma.pet.create({ data: { name: 豆豆, breed: 柯基, gender: MALE, birthDate: new Date(2022-03-15), adoptDate: new Date(2022-05-20), neutered: true, currentWeight: 12.5, events: { create: [ { type: VACCINE, occurredAt: new Date(2022-06-01), note: 狂犬疫苗第一针 }, { type: DEWORM, occurredAt: new Date(2022-07-10), note: 体内驱虫 }, { type: CHECKUP, occurredAt: new Date(2023-01-15), note: 年度体检 }, ], }, }, }) // 更多种子数据... } main()注意种子数据中的日期不要用固定值最好用相对于当前日期的偏移量比如new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)表示30天前。这样无论什么时候运行种子脚本数据看起来都是“最近发生的”方便测试提醒功能。3.3 核心功能实现事件时间线与提醒系统整个App最核心的功能是事件时间线和基于事件的提醒系统。这两块我让AI分步实现每步都先确认方案再写代码。事件时间线的实现思路是从数据库按时间倒序取出某只宠物的所有事件按月份分组在界面上以时间轴形式呈现。每个事件节点显示类型图标、发生时间、备注摘要。点击节点展开详情可以查看附件和关联提醒。AI生成的实现代码中数据分组逻辑一开始写在了组件内部导致每次渲染都要重新计算。我让它把分组逻辑抽成一个独立的工具函数并用useMemo缓存结果。这个优化在事件数量少的时候差别不大但事件超过100条之后滚动流畅度明显提升。提醒系统的实现稍微复杂一些。核心逻辑是当创建一个事件时如果该事件类型有对应的提醒规则比如疫苗事件默认在一年后提醒就自动创建一条提醒记录。提醒记录包含提醒时间、提醒内容、关联事件、完成状态。提醒的触发我用的是 Expo Notifications 的本地通知能力。在App启动时查询所有未完成的提醒为每个提醒注册本地通知。当用户标记提醒完成时取消对应的通知。这里有一个坑本地通知的注册数量有限制。iOS 对同时注册的本地通知数量有上限通常是64条如果提醒很多不能一次性全部注册。我的做法是只注册未来30天内的提醒超过30天的等临近了再注册。这个策略需要在代码中加一个定时任务每天检查一次并更新通知注册。// 注册未来30天内的提醒通知 const thirtyDaysLater new Date(Date.now() 30 * 24 * 60 * 60 * 1000) const upcomingReminders await prisma.reminder.findMany({ where: { completed: false, remindAt: { lte: thirtyDaysLater, gte: new Date() }, }, }) for (const reminder of upcomingReminders) { await Notifications.scheduleNotificationAsync({ content: { title: 宠物提醒, body: reminder.content }, trigger: { date: reminder.remindAt }, }) }3.4 健康数据统计与图表呈现统计页面是体现“生命周期管理”价值的关键页面。我让AI实现了三个统计维度体重变化趋势、疫苗完成率、各类型事件数量分布。体重趋势用折线图呈现数据来源是事件表中类型为 CHECKUP 或单独记录的体重数据。这里有一个数据清洗的问题体重记录可能来自不同来源体检时称的、家里称的单位可能不一致公斤和斤。我让AI在数据进入图表之前先做一次归一化处理统一转成公斤并保留一位小数。疫苗完成率用环形进度图呈现计算逻辑是已完成的疫苗事件数除以该宠物年龄段应完成的疫苗总数。不同年龄段的疫苗要求不同幼犬和成年犬的疫苗计划有差异。这个规则我让AI根据常见的宠物疫苗指南整理了一份对照表然后在代码中根据宠物的出生日期自动判断当前年龄段和应完成的疫苗数。各类型事件数量分布用柱状图呈现按事件类型分组统计。这个图的价值在于让主人一眼看出哪类记录偏少比如驱虫记录明显少于疫苗记录可能提示驱虫做得不够规律。实操心得图表库我选的是react-native-chart-kit它的API简单AI生成配置代码不容易出错。但它的默认样式比较简陋需要手动调整颜色、间距、字体大小。我建议让AI生成图表配置时把样式参数单独抽成一个对象方便后续统一调整。4. 常见问题与排查技巧实录4.1 AI生成代码不一致的排查与预防在项目搭建过程中最常见的问题就是AI生成的代码前后不一致。具体表现有前面定义的数据字段名和后面使用的对不上、接口路径在前后端不一致、状态管理的 store 结构在不同组件中理解不同。排查这类问题的第一步是建立单一数据源。我把 Prisma schema 作为数据字段的唯一权威来源把 API 契约文档作为接口路径和参数格式的唯一权威来源。每次让AI生成代码时都把这两个文件的内容作为上下文贴给它让它基于这些内容生成而不是凭记忆。第二步是生成后做交叉检查。AI生成完一个模块的代码后我会让它自己检查一遍“请检查你生成的代码中所有字段名是否与 Prisma schema 一致所有接口路径是否与 API 契约文档一致。”这个自检步骤能发现大部分不一致问题。第三步是用 TypeScript 的类型检查兜底。前后端都开启严格模式字段名拼写错误、类型不匹配这些问题在编译阶段就会暴露不会留到运行时。实测下来TypeScript 的严格模式能拦截大约70%的AI生成代码中的低级错误。4.2 数据库迁移冲突的处理开发过程中修改 schema 是常态但频繁迁移容易产生冲突。我遇到过一次典型情况我在本地修改了 schema 并执行了迁移但忘记同步到另一台开发机结果两边数据库结构不一致代码跑起来报字段不存在的错误。处理这类问题的原则是schema 变更必须走迁移文件不能直接改数据库。每次修改 schema 后执行prisma migrate dev生成迁移文件把迁移文件提交到版本控制。另一台机器拉取代码后执行prisma migrate deploy应用迁移。这样两边的数据库结构始终一致。如果已经出现了不一致可以用prisma migrate diff对比两个数据库的差异然后手动生成修复迁移。这个命令的输出比较长我通常会让AI帮忙解读差异并生成修复方案。4.3 移动端真机调试的常见坑Expo 的真机调试很方便但有几个坑需要注意。第一个是网络问题。手机和电脑必须在同一局域网内否则 Expo Go 连不上开发服务器。如果公司网络隔离了设备可以用 Expo 的 tunnel 模式但 tunnel 模式下热更新会慢一些。第二个是通知权限。iOS 和 Android 对通知权限的处理不同iOS 需要在首次使用时请求权限Android 13 以上也需要动态请求。如果忘记请求权限通知不会触发而且不会有明显报错。我的做法是在App启动时就请求通知权限并在设置页面提供一个“重新请求权限”的入口。第三个是图片上传的路径问题。Expo ImagePicker 返回的 URI 在 iOS 和 Android 上格式不同iOS 是file://开头Android 是content://开头。上传到后端时需要先统一转成 Blob 或 FormData。这个转换逻辑我让AI写了一个工具函数两端都调用同一个函数处理。4.4 常见问题速查表问题现象可能原因排查方法解决方案前端调用接口返回404接口路径不一致对比前端请求路径和API契约文档统一使用契约文档中的路径数据库报字段不存在schema未同步执行prisma migrate status运行迁移命令同步结构通知不触发权限未请求或通知未注册检查权限状态和注册日志启动时请求权限并注册30天内提醒图表不显示数据数据格式不匹配打印图表组件的data属性检查数据归一化逻辑真机连不上开发服务器网络隔离检查手机和电脑是否同网段切换tunnel模式或调整网络AI生成代码字段名不一致上下文不足对比schema和生成代码生成时附带schema作为上下文提示这份速查表建议放在项目根目录的TROUBLESHOOTING.md中每次遇到新问题就补充一行。积累下来它比任何官方文档都更贴合你的项目实际。5. 项目扩展与个人经验体会5.1 后续可以扩展的方向这个项目的基础版本跑通之后有几个自然的扩展方向。第一个是多宠物家庭的数据隔离与共享现在虽然支持多主人多宠物但界面上的切换体验还比较粗糙可以做成顶部宠物切换栏快速在不同宠物之间跳转。第二个是健康数据的智能分析。现在只是展示原始数据和简单统计后续可以加入异常检测比如体重连续下降超过一定比例时自动提醒主人关注或者疫苗间隔时间异常时给出提示。这部分可以结合简单的规则引擎来实现不一定需要复杂的模型。第三个是数据导出与分享。宠物就医时医生往往需要了解完整的疫苗和用药历史。提供一个一键导出PDF病历摘要的功能实用性很强。这个功能的技术难点在于PDF排版可以用react-native-html-to-pdf或者在后端生成PDF再下载。第四个是离线优先的数据同步。现在所有数据都依赖网络请求如果在地下停车场、电梯里等信号不好的地方记录事件体验会受影响。可以引入本地数据库如 WatermelonDB 或 SQLite做离线存储网络恢复后再同步到服务端。这个改造的工作量不小但能显著提升核心场景的可用性。5.2 我用AI搭建项目的一些真实体会回过头看整个项目从零到跑通的过程最大的体会是AI不是替代你思考而是放大你的思考。如果你自己对项目结构、数据关系、技术选型没有清晰的判断AI生成的东西只会让你更混乱。但如果你能把问题拆解清楚把约束条件说明白AI的执行效率确实比手动写代码高很多。另一个体会是分阶段确认的价值。我试过一次性让AI生成整个项目结果是一堆看起来能跑但互相不匹配的代码改起来比自己写还累。后来改成每个阶段只做一件事做完确认再继续整体效率反而更高。这个道理其实不限于AI编码任何复杂项目的推进都应该遵循类似的节奏。还有一个细节让AI写代码时注释和文档要同步生成。我一开始只让AI写实现代码后来发现过两周再看某些模块自己都忘了当时的逻辑。后来我要求AI在生成每个模块时同步生成一段简短的模块说明包括这个模块解决什么问题、关键数据结构是什么、有哪些注意事项。这些说明积累起来就是项目最好的文档。最后分享一个小技巧当你觉得AI生成的代码“差不多能用但总觉得哪里不对”的时候不要急着改代码先让AI解释一遍它的实现思路。很多时候问题出在它对需求的理解有偏差而不是代码本身有bug。把理解对齐了代码自然就对了。这个习惯帮我省了很多来回修改的时间。