AI辅助从零搭建宠物生命周期管理App:状态机与提醒引擎实战
1. 为什么我选择用AI辅助从零搭建一个宠物生命周期管理App宠物生命周期管理这个需求乍一听好像挺小众但真正养过宠物的人都知道从接回家第一天到最终告别中间涉及的事情极其琐碎疫苗记录、驱虫周期、体重曲线、发情期、绝育时间、慢性病用药、体检报告、甚至临终关怀和身后事安排。我身边养宠的朋友几乎每个人都在用备忘录、Excel或者聊天记录来管理这些信息散落在四五个地方关键时刻翻半天找不着。市面上现有的宠物管理类App大多数只做了提醒这一层比如疫苗提醒、驱虫提醒但宠物生命周期是一个连续的、有状态迁移的过程——幼年期、成年期、老年期每个阶段的关注点完全不同。幼年期核心是疫苗和社交化训练成年期核心是体重管理和行为问题老年期核心是慢性病监测和生活质量评估。这些阶段之间的过渡以及每个阶段内部的周期性事件需要一个有状态管理的系统来承载。我决定用Claude Code来从零搭建这个项目原因有三个。第一这个项目的业务逻辑复杂度适中既不像CRUD后台那么无聊也不至于复杂到AI无法理解全局第二宠物生命周期管理涉及大量时间计算和状态迁移正好可以测试AI在业务逻辑建模上的能力第三我想验证一个假设在2025年的工具条件下一个全栈开发者借助AI能不能在几天内从零交付一个可用的移动端应用。这篇文章会完整记录我从需求拆解、技术选型、数据建模、核心功能实现到最终跑通的全部过程。不是那种AI帮我写了个Hello World的演示而是真实项目里会遇到的状态机设计、时间边界处理、数据迁移这些硬骨头。如果你也在考虑用AI辅助做side project或者你对宠物管理类应用的技术实现感兴趣这篇内容应该能给你不少参考。2. 需求拆解宠物生命周期到底要管哪些状态2.1 从提醒工具到状态机的思维转变大多数人做宠物管理App第一反应是做一个提醒列表疫苗提醒、驱虫提醒、洗澡提醒。这个思路的问题在于提醒是离散的、无状态的而宠物的生命周期是连续的、有状态的。举个例子一只猫在幼年期需要打三针疫苗每针间隔21天打完三针之后进入成年期成年期每年加强一针。如果你只是做提醒你需要手动设置四个提醒但如果你做状态机你只需要定义疫苗状态这个字段系统根据当前状态和日期自动计算下一个事件。我在需求拆解阶段做的第一件事是把宠物的生命周期拆成几个核心状态维度生命阶段幼年、成年、老年。这个维度决定了其他所有事件的默认频率和关注重点。繁殖状态未绝育、已绝育、发情期、怀孕、哺乳。这个维度影响行为预测和健康建议。健康状态健康、慢性病管理、术后恢复、临终关怀。这个维度影响提醒的优先级和内容。疫苗状态未开始、接种中、已完成、需加强。这个维度直接驱动提醒系统。这四个维度不是独立的它们之间有约束关系。比如怀孕状态下不能接种某些疫苗老年阶段慢性病筛查频率要提高。这些约束关系就是业务逻辑的核心也是AI最容易写错的地方。2.2 核心实体与关系建模在动手写代码之前我用Claude Code帮我做了一轮实体关系梳理。我给的提示词大概是这样的我要做一个宠物生命周期管理App核心实体包括宠物、主人、事件记录、健康指标、提醒规则。 请帮我梳理实体之间的关系并指出哪些关系是一对多、哪些是多对多以及哪些字段需要做状态机管理。Claude Code给出的建模建议里有几个点我觉得很有价值第一宠物和主人之间应该是多对多关系。一开始我想的是一对多但实际场景里一只宠物可能有多个主人比如家庭成员共同照顾一个人也可能有多只宠物。这个关系如果做成一対多后期扩展会很痛苦。第二事件记录应该是一个统一的表而不是按类型分表。疫苗、驱虫、体检、用药、体重记录这些本质上都是在某个时间点发生的、与宠物相关的事件只是携带的数据不同。统一表的好处是时间线展示极其简单坏处是字段会有冗余。我最终选择了统一表加JSON字段的方案核心字段时间、类型、标题独立扩展字段放JSON。第三提醒规则不应该和事件记录混在一起。提醒规则是未来要发生什么事件记录是过去发生了什么。这两者的生命周期完全不同混在一起会导致查询逻辑极其复杂。下面是我最终确定的核心数据模型简化版// 宠物核心状态 interface Pet { id: string; name: string; species: dog | cat | other; breed: string; birthDate: Date; lifeStage: puppy | adult | senior; // 根据birthDate自动计算 reproductiveStatus: intact | neutered | estrus | pregnant | nursing; healthStatus: healthy | chronic | recovery | hospice; vaccineStatus: not_started | in_progress | completed | booster_due; weightHistory: WeightRecord[]; createdAt: Date; updatedAt: Date; } // 统一事件记录 interface PetEvent { id: string; petId: string; type: vaccine | deworming | checkup | medication | weight | symptom | other; title: string; occurredAt: Date; notes?: string; metadata: Recordstring, any; // 类型相关的扩展字段 createdAt: Date; } // 提醒规则 interface ReminderRule { id: string; petId: string; eventType: string; triggerCondition: { type: interval | date | state_change; value: number; // 天数或具体日期 baseEventId?: string; // 基于哪个事件触发 }; nextTriggerAt: Date; isActive: boolean; priority: low | normal | high | urgent; }这个模型跑通之后我发现一个关键点lifeStage不应该手动设置而应该根据birthDate自动计算。不同品种的猫狗幼年期和老年期的划分标准不一样。大型犬7岁就算老年小型犬可能10岁才算。所以我在Pet表里加了一个breed字段配合一个品种数据库来计算生命阶段。2.3 时间计算的边界情况宠物生命周期管理里最麻烦的不是业务逻辑而是时间计算。我踩过的坑包括闰年问题疫苗间隔21天如果跨越2月29日计算会出错。这个用日期库如date-fns可以解决但要注意时区。月份加减有些驱虫药是每月一次但每月到底是30天还是自然月我最终选择了自然月因为用户的心智模型是每个月固定那几天。时区问题用户可能带宠物跨时区旅行事件记录的时间应该以用户当地时间为准但存储用UTC。这个在移动端尤其要注意。未来日期用户可能提前记录未来的事件比如预约了下周的体检提醒系统要能处理未来事件。这些边界情况我在写代码之前就让Claude Code帮我列了一个清单然后逐个写测试用例覆盖。实测下来这个做法比写完再补测试效率高很多。3. 技术选型为什么我最终选了这套技术栈3.1 移动端框架的取舍宠物管理App的核心使用场景是移动端因为用户需要在宠物医院、家里、路上随时记录。移动端框架我考虑了三个选项方案优势劣势适用场景React Native生态成熟社区大热更新方便性能不如原生复杂动画吃力快速迭代的中小型AppFlutter性能好UI一致性强Dart语言学习成本包体积大对UI要求高的App原生开发性能最优系统能力调用方便双端开发成本高大型商业App我最终选了React Native Expo。原因很实际这个项目是个人side project我需要快速验证想法而不是花两周时间配置原生环境。Expo的托管工作流让我可以在手机上直接扫码预览改代码即时生效这个反馈速度对独立开发者来说太重要了。但Expo也有坑。比如推送通知Expo的推送服务在国内Android设备上到达率不稳定。我的解决方案是本地提醒用Expo Notifications远程推送用第三方推送服务做兜底。这个后面会详细说。3.2 后端方案为什么我没用Serverless后端我一开始想用Serverless比如云函数云数据库因为不用管服务器成本低。但仔细想了想宠物管理App的数据特征我放弃了这个方案第一数据关系复杂。宠物、事件、提醒规则之间有大量关联查询Serverless数据库如某些文档型数据库做关联查询很别扭。第二时间计算密集。提醒规则的触发计算需要频繁跑定时任务Serverless的冷启动和计费模式不适合这种场景。第三数据敏感性。宠物的健康数据虽然不像人的医疗数据那么敏感但用户也不希望这些数据散落在多个云服务里。最终我选了Node.js Fastify PostgreSQL的组合。Fastify比Express快插件体系清晰PostgreSQL的JSONB字段完美支持我前面说的统一事件表扩展字段设计而且PostgreSQL的窗口函数和CTE在计算生命周期统计时非常好用。# 项目初始化命令 npx create-expo-app pet-lifecycle --template blank-typescript cd pet-lifecycle npm install fastify fastify/cors fastify/jwt pg date-fns zod npm install -D types/node types/pg typescript tsx3.3 状态管理Zustand还是Redux前端状态管理我纠结了很久。Redux Toolkit生态最成熟但样板代码多Zustand轻量但生态相对小。考虑到这个App的状态主要是当前宠物和事件列表复杂度不高我最终选了Zustand。实测下来Zustand的体验很好。核心store大概长这样import { create } from zustand; interface PetStore { currentPet: Pet | null; events: PetEvent[]; reminders: ReminderRule[]; setCurrentPet: (pet: Pet) void; addEvent: (event: PetEvent) void; refreshReminders: () Promisevoid; } export const usePetStore createPetStore((set, get) ({ currentPet: null, events: [], reminders: [], setCurrentPet: (pet) set({ currentPet: pet }), addEvent: (event) set((state) ({ events: [event, ...state.events] })), refreshReminders: async () { const pet get().currentPet; if (!pet) return; const reminders await api.getReminders(pet.id); set({ reminders }); }, }));这里有个经验不要把服务端数据完全同步到客户端store。我一开始把所有事件都拉到本地结果宠物多了之后内存占用很高。后来改成按需加载当前宠物的事件才加载历史事件分页拉取。4. 用Claude Code实现核心功能从状态机到提醒引擎4.1 生命阶段自动计算一个容易被低估的复杂逻辑生命阶段计算看起来简单——根据出生日期算年龄然后对照品种标准判断阶段。但实际写起来有几个坑第一品种标准不统一。我查了一些公开的宠物健康资料大型犬如金毛、拉布拉多的老年期从7岁开始中型犬8-9岁小型犬10-11岁。猫的老年期一般从11岁开始。这些数据需要做成配置表。第二幼年期的结束时间也有讲究。狗一般1岁算成年但大型犬可能1.5-2岁才完全成年。猫一般1岁算成年。第三计算逻辑要可测试。我让Claude Code帮我写了一个纯函数输入出生日期、品种、当前日期输出生命阶段。这个函数没有任何副作用方便写单元测试。type LifeStage puppy | adult | senior; interface BreedProfile { species: dog | cat; sizeCategory: small | medium | large; adultAgeMonths: number; seniorAgeMonths: number; } const BREED_PROFILES: Recordstring, BreedProfile { golden_retriever: { species: dog, sizeCategory: large, adultAgeMonths: 18, seniorAgeMonths: 84 }, labrador: { species: dog, sizeCategory: large, adultAgeMonths: 18, seniorAgeMonths: 84 }, poodle_toy: { species: dog, sizeCategory: small, adultAgeMonths: 12, seniorAgeMonths: 120 }, domestic_shorthair: { species: cat, sizeCategory: medium, adultAgeMonths: 12, seniorAgeMonths: 132 }, // ... 更多品种 }; export function calculateLifeStage( birthDate: Date, breedKey: string, currentDate: Date new Date() ): LifeStage { const profile BREED_PROFILES[breedKey]; if (!profile) { // 未知品种用默认值 return calculateLifeStage(birthDate, domestic_shorthair, currentDate); } const ageMonths differenceInMonths(currentDate, birthDate); if (ageMonths profile.adultAgeMonths) return puppy; if (ageMonths profile.seniorAgeMonths) return adult; return senior; }这个函数我写了大概20个测试用例覆盖了闰年出生、品种未知、边界月份等情况。Claude Code在写测试用例时帮了大忙它会自动想到一些我没想到的边界比如出生日期是未来日期这种异常输入。4.2 提醒引擎如何避免提醒轰炸提醒引擎是这个App的核心也是最容易做砸的地方。我见过太多App提醒设置得太频繁用户直接关掉通知权限然后整个App就废了。我的设计原则是提醒要少而准每条提醒都要有明确的行动指向。具体实现上提醒引擎分三层第一层规则生成。根据宠物的当前状态自动生成提醒规则。比如幼年期的猫自动生成疫苗第一针提醒成年期的狗自动生成每年加强疫苗提醒。这一层是状态驱动的宠物状态变了规则跟着变。第二层时间计算。每条规则计算出下一次触发时间。这里有个细节如果用户错过了提醒比如疫苗应该上周打但没打提醒不应该消失而应该升级优先级变成逾期提醒。第三层聚合与去重。如果同一天有多个提醒合并成一条通知而不是发多条。比如今天有3件事疫苗加强、驱虫、体重记录。interface ReminderCandidate { petId: string; eventType: string; dueDate: Date; priority: low | normal | high | urgent; title: string; body: string; } export function generateReminders( pet: Pet, events: PetEvent[], rules: ReminderRule[], today: Date ): ReminderCandidate[] { const candidates: ReminderCandidate[] []; for (const rule of rules) { if (!rule.isActive) continue; const nextDue calculateNextDue(rule, events, today); if (!nextDue) continue; const daysUntilDue differenceInDays(nextDue, today); // 提前3天开始提醒逾期后升级优先级 if (daysUntilDue 3) { let priority rule.priority; if (daysUntilDue 0) { priority urgent; } else if (daysUntilDue 0) { priority high; } candidates.push({ petId: pet.id, eventType: rule.eventType, dueDate: nextDue, priority, title: generateTitle(rule, daysUntilDue), body: generateBody(rule, pet, daysUntilDue), }); } } // 按优先级排序同一天的合并 return mergeSameDayReminders(candidates); }这里有个我踩过的坑提醒的提前量不能一刀切。疫苗提醒提前3天合适但体重记录提醒提前3天就太早了提前1天甚至当天提醒就行。所以我在规则里加了一个advanceDays字段不同类型的提醒用不同的提前量。4.3 事件时间线如何优雅地展示混合类型数据宠物的事件时间线是这个App使用频率最高的界面。用户打开App第一眼看到的就是我的宠物最近发生了什么。时间线的技术难点在于不同类型的事件展示形式完全不同。疫苗事件要显示疫苗名称、批号、接种机构体重事件要显示数值和变化趋势症状事件要显示描述和严重程度。如果为每种类型写一个组件代码会非常臃肿。我的方案是统一卡片 类型特定的渲染器。每个事件渲染成一个卡片卡片头部是通用信息时间、类型图标、标题卡片主体根据类型调用不同的渲染函数。const EVENT_RENDERERS: Recordstring, (event: PetEvent) React.ReactNode { vaccine: (event) ( View Text疫苗{event.metadata.vaccineName}/Text Text批号{event.metadata.batchNumber}/Text Text机构{event.metadata.clinic}/Text /View ), weight: (event) ( View Text体重{event.metadata.weight} kg/Text {event.metadata.trend ( Text变化{event.metadata.trend 0 ? : }{event.metadata.trend} kg/Text )} /View ), symptom: (event) ( View Text症状{event.metadata.description}/Text Text严重程度{event.metadata.severity}/Text /View ), // ... 其他类型 }; function EventCard({ event }: { event: PetEvent }) { const renderer EVENT_RENDERERS[event.type] || defaultRenderer; return ( Card CardHeader EventIcon type{event.type} / Text{event.title}/Text Text{format(event.occurredAt, yyyy-MM-dd HH:mm)}/Text /CardHeader CardBody{renderer(event)}/CardBody /Card ); }这个设计的好处是新增事件类型只需要加一个渲染函数不用改时间线主逻辑。实测下来从疫苗类型扩展到体重类型只花了不到半小时。5. 数据持久化与同步本地优先还是云端优先5.1 为什么我选了本地优先宠物管理App有一个特殊场景用户可能在宠物医院网络信号不好但需要立即记录疫苗信息。如果App是云端优先网络不好时记录会失败用户体验极差。所以我选了本地优先Local-First的架构所有数据先写本地SQLite然后异步同步到云端。这样即使离线App也能正常使用。// 本地数据库schema使用expo-sqlite const SCHEMA CREATE TABLE IF NOT EXISTS pets ( id TEXT PRIMARY KEY, name TEXT NOT NULL, species TEXT NOT NULL, breed TEXT, birth_date TEXT NOT NULL, life_stage TEXT, reproductive_status TEXT, health_status TEXT, vaccine_status TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, synced_at TEXT ); CREATE TABLE IF NOT EXISTS events ( id TEXT PRIMARY KEY, pet_id TEXT NOT NULL, type TEXT NOT NULL, title TEXT NOT NULL, occurred_at TEXT NOT NULL, notes TEXT, metadata TEXT, created_at TEXT NOT NULL, synced_at TEXT, FOREIGN KEY (pet_id) REFERENCES pets(id) ); CREATE INDEX IF NOT EXISTS idx_events_pet_time ON events(pet_id, occurred_at DESC); ;5.2 同步冲突的处理策略本地优先架构最大的挑战是同步冲突。比如用户在手机上修改了宠物信息同时在平板上也修改了两个修改怎么合并我的策略是字段级最后写入胜出Last-Write-Wins per Field。每条记录记录每个字段的最后修改时间同步时比较时间戳新的覆盖旧的。这个策略简单对宠物管理这种场景足够用。但有一个例外事件记录不做合并只做追加。事件是发生过的事实不应该被覆盖。如果两个设备都记录了事件同步时都保留按时间排序。async function syncEvents(localEvents: PetEvent[], remoteEvents: PetEvent[]) { const localIds new Set(localEvents.map(e e.id)); const remoteIds new Set(remoteEvents.map(e e.id)); // 本地有、远程没有的推送到远程 const toPush localEvents.filter(e !remoteIds.has(e.id)); // 远程有、本地没有的拉取到本地 const toPull remoteEvents.filter(e !localIds.has(e.id)); // 两边都有的比较updatedAt新的胜出 const toMerge localEvents .filter(e remoteIds.has(e.id)) .map(local { const remote remoteEvents.find(r r.id local.id)!; return local.updatedAt remote.updatedAt ? local : remote; }); return { toPush, toPull, toMerge }; }5.3 数据迁移一个被忽视但迟早要面对的问题App上线后数据模型肯定会变。比如我一开始没考虑宠物头像后来想加就需要做数据迁移。我的做法是在本地数据库里维护一个schema版本号每次启动时检查版本执行对应的迁移脚本。const MIGRATIONS: Recordnumber, string { 1: ALTER TABLE pets ADD COLUMN avatar_uri TEXT;, 2: ALTER TABLE events ADD COLUMN tags TEXT;, // ... }; async function runMigrations(db: SQLiteDatabase) { const result await db.getFirstAsync{ user_version: number }(PRAGMA user_version); let currentVersion result?.user_version ?? 0; const targetVersion Object.keys(MIGRATIONS).length; while (currentVersion targetVersion) { currentVersion; const sql MIGRATIONS[currentVersion]; if (sql) { await db.execAsync(sql); } await db.execAsync(PRAGMA user_version ${currentVersion}); } }这个迁移机制我强烈建议在项目初期就加上哪怕当时只有一个版本。因为等到需要迁移时再加用户数据可能已经乱了。6. 实测中的意外情况与排查记录6.1 提醒不触发一个时区导致的诡异BugApp开发完成后我用自己的手机测试发现提醒有时候触发有时候不触发。排查了两天才找到原因时区处理不一致。具体来说我在计算提醒时间时用了new Date()获取当前时间但存储提醒时间时用了UTC。在计算距离提醒还有多少天时我用的是本地时间的日期差但提醒时间本身是UTC。当用户所在时区的UTC偏移导致日期跨越时计算就会出错。修复方案是所有时间计算统一用UTC只在展示时转成本地时间。// 错误做法 const daysUntil differenceInDays(reminderDate, new Date()); // 正确做法 const now new Date(); const daysUntil differenceInDays( startOfDay(reminderDate), startOfDay(now) );这个Bug给我的教训是时间处理一定要在项目初期就定好规范并且写测试覆盖。我后来补了大概15个时区相关的测试用例覆盖了跨日、跨月、跨年、夏令时等情况。6.2 本地数据库性能索引没建对查询慢10倍事件时间线页面一开始加载很慢尤其是事件多了之后。我用EXPLAIN ANALYZE分析了一下发现查询没走索引。原因是我的索引建在了pet_id上但查询条件是pet_id ? ORDER BY occurred_at DESC。PostgreSQL以及SQLite需要复合索引才能同时优化过滤和排序。修复方案建复合索引(pet_id, occurred_at DESC)。建完之后查询时间从800ms降到了80ms。-- 修复前 CREATE INDEX idx_events_pet ON events(pet_id); -- 修复后 CREATE INDEX idx_events_pet_time ON events(pet_id, occurred_at DESC);这个经验适用于所有按某个字段过滤、按另一个字段排序的查询场景。复合索引的字段顺序很重要过滤字段在前排序字段在后。6.3 推送通知在部分设备上收不到前面提到Expo的推送服务在国内Android设备上到达率不稳定。我实测下来大概有20%-30%的设备收不到推送。我的兜底方案是本地提醒为主远程推送为辅。具体来说所有提醒都在本地用expo-notifications注册本地通知不依赖远程推送。远程推送只用于多设备同步场景比如用户在平板上添加了事件手机上收到同步通知。本地通知的可靠性高很多因为它不依赖网络。实测下来本地通知的到达率接近100%。import * as Notifications from expo-notifications; async function scheduleLocalReminder(reminder: ReminderCandidate) { await Notifications.scheduleNotificationAsync({ content: { title: reminder.title, body: reminder.body, data: { petId: reminder.petId, eventType: reminder.eventType }, }, trigger: { date: reminder.dueDate, }, }); }但本地通知也有坑iOS对本地通知的数量有限制最多64条待触发通知。如果提醒规则很多需要做优先级排序只注册最近最重要的64条。7. 从零到跑通我的完整开发节奏与工具链配置7.1 项目初始化与Claude Code的配合方式我用Claude Code的方式不是让它一次性生成整个项目而是按模块逐步推进。每个模块的流程是我先用自然语言描述需求和约束Claude Code生成初版代码我review代码指出问题Claude Code修改我写测试验证跑通后进入下一个模块这个流程比一次性生成慢但代码质量高很多。实测下来一个中等复杂度的模块比如提醒引擎从描述到跑通大概需要2-3轮对话。有一个技巧很实用让Claude Code先写接口定义再写实现。比如提醒引擎我先让它定义ReminderRule、ReminderCandidate这些类型确认类型设计合理后再让它写具体的计算逻辑。这样能避免实现写到一半发现类型不对全部重来的情况。7.2 开发环境配置清单我的开发环境配置如下供参考# Node.js版本管理 nvm install 20 nvm use 20 # 包管理器 npm install -g pnpm # 项目初始化 pnpm create expo-app pet-lifecycle --template blank-typescript cd pet-lifecycle # 核心依赖 pnpm add fastify fastify/cors fastify/jwt pg date-fns zod zustand pnpm add expo-sqlite expo-notifications expo-secure-store # 开发依赖 pnpm add -D typescript types/node types/pg tsx vitest # 数据库本地开发用Docker docker run -d \ --name pet-lifecycle-db \ -e POSTGRES_PASSWORDdevpassword \ -e POSTGRES_DBpet_lifecycle \ -p 5432:5432 \ postgres:167.3 测试策略哪些必须测哪些可以跳过个人项目时间有限不可能所有代码都写测试。我的策略是核心业务逻辑必须测UI和胶水代码可以跳过。必须测的生命阶段计算边界条件多提醒触发时间计算时区、闰年、逾期同步冲突合并逻辑数据一致性关键数据迁移脚本一旦出错用户数据丢失可以跳过的UI组件渲染视觉问题肉眼可见API路由层逻辑简单主要是转发配置加载出错会立即发现实测下来核心逻辑的测试覆盖率大概在85%左右整体覆盖率60%左右。这个比例对个人项目来说够用了。8. 这套方案跑通后的实际效果与后续扩展方向项目从零到跑通我大概花了5天时间其中需求拆解和数据建模占了1天核心功能实现2天调试和修Bug 2天。最终交付的版本支持多宠物管理、生命周期自动计算、事件时间线、智能提醒、本地优先存储、多设备同步。实测下来有几个点超出了我的预期。第一Claude Code在写时间计算相关的代码时准确率比我预期的高尤其是它会自动处理一些边界情况比如闰年和时区。第二本地优先架构的体验确实好离线记录毫无延迟同步在后台默默完成用户完全无感。第三状态机的设计让后续扩展变得很容易我后来加怀孕期管理功能只改了状态定义和几个提醒规则核心逻辑一行没动。也有几个点比我预期的难。第一时区问题比我想的复杂尤其是涉及跨时区旅行场景。第二本地数据库的迁移机制虽然我一开始就加了但测试迁移脚本比测试业务逻辑麻烦得多。第三推送通知的可靠性在国内Android生态下确实是个挑战最终靠本地通知兜底才解决。后续我打算扩展的方向一是加宠物社交功能让用户可以分享宠物动态二是加健康报告功能根据事件记录自动生成健康趋势分析三是加多语言支持因为宠物管理是个全球性需求。这些扩展里健康报告最复杂涉及数据分析和可视化我可能会用Claude Code来辅助做数据聚合逻辑。如果你也想用AI辅助做类似的项目我的建议是把AI当成一个执行力很强但需要明确指令的初级开发者。你给的需求越具体、约束越清晰它生成的代码质量越高。反过来如果你只说帮我做个宠物管理App它生成的东西大概率不能用。需求拆解和架构设计这些思考的工作还是得自己来。