
1. 项目缘起与整体设计思路1.1 为什么选宠物生命周期管理这个方向宠物生命周期管理这个选题乍看像是个小众赛道但实际拆开来看它覆盖的需求链条非常长。从宠物入家门的建档、疫苗提醒、驱虫周期、体重曲线、就诊记录到中后期的慢性病管理、用药追踪再到临终关怀和纪念留存每一个环节都是独立的功能模块又彼此关联。这种“长周期、多状态、强提醒”的业务特征恰好是检验一套AI辅助开发流程是否靠谱的绝佳试金石。我选择用Claude Code从零搭建这个项目核心考量有三点。第一宠物管理类App的数据模型相对清晰实体关系不复杂适合快速验证AI生成代码的准确率。第二这类App对交互细节要求高比如提醒时间的自然语言解析、体重趋势的可视化这些恰好能测试AI在UI逻辑和数据处理上的表现。第三整个项目规模适中一个人用AI辅助可以在合理时间内跑通全流程不会因为体量过大而中途失控。提示选项目练手时优先选业务边界清晰、但功能点足够密集的方向。太简单的增删改查体现不出AI辅助的价值太复杂的分布式系统又容易在调试环节卡死。1.2 技术栈选型与背后的取舍逻辑技术栈这块我最终定的是Flutter SQLite Riverpod的组合。为什么这么选逐个说。Flutter负责跨平台UI一套代码同时出Android和iOS省掉重复劳动。宠物管理类App的界面以表单、列表、图表为主Flutter的Widget体系应付这些绰绰有余而且热重载在调试提醒逻辑时特别顺手。SQLite做本地存储宠物的疫苗记录、体重数据、就诊历史这些天然适合关系型结构查询和聚合都方便不需要上云就能保证离线可用。Riverpod管状态相比Provider它的编译期安全检查和依赖注入更清晰AI生成代码时不容易出现Provider嵌套地狱。这里有个关键决策点要不要上后端。我一开始想过用云数据库做多设备同步但后来砍掉了。原因很简单宠物数据涉及个人隐私本地存储反而更容易通过合规审查而且AI生成后端接口代码时鉴权、并发、数据一致性这些坑太多容易把项目拖进无底洞。先跑通本地闭环后续再考虑同步方案这是更务实的路径。技术层选型替代方案最终选择理由跨端框架FlutterReact NativeWidget一致性更好图表库成熟本地存储SQLiteHive / Isar关系型查询强AI生成SQL准确率高状态管理RiverpodProvider / Bloc编译期安全依赖注入清晰图表fl_chartsyncfusion轻量免费API直观提醒flutter_local_notifications系统日历API无需额外权限本地触发稳定1.3 AI辅助开发的边界在哪里用Claude Code搭项目最忌讳的是把它当“全自动代码生成器”。我的经验是AI负责写具体实现人负责定架构和验收。比如数据表结构、模块划分、状态流转这些顶层设计必须自己先想清楚然后用自然语言描述给AI让它生成对应的代码骨架。如果一上来就让AI“帮我做个宠物App”出来的东西大概率是一堆看似完整但逻辑断裂的碎片。具体到操作层面我会把任务拆成三种粒度架构级比如“设计宠物实体的数据模型包含哪些字段和关系”、模块级比如“实现疫苗提醒的增删改查页面”、函数级比如“写一个根据出生日期计算下次疫苗时间的函数”。架构级自己定模块级让AI出初稿再改函数级直接让AI写然后跑测试。这个分工跑下来效率最高返工最少。2. 核心数据模型与业务逻辑拆解2.1 宠物生命周期的时间轴建模宠物生命周期管理的核心是把一只宠物的生命过程抽象成一条时间轴上面挂着各种事件节点。我在设计数据模型时用了Pet、Event、Reminder、Record四个核心实体。Pet是主体存基本信息名字、物种、品种、出生日期、性别、绝育状态、头像路径。Event是时间轴上的节点比如“接种狂犬疫苗”“体内驱虫”“体重测量”“就诊”每个Event有类型、时间、备注。Reminder是从Event派生出来的待办比如“下次疫苗还有7天”它关联到具体的Event类型和周期规则。Record是更细粒度的数据记录比如每次体重的具体数值、每次就诊的诊断结果。这里的关键设计是Event和Reminder分离。Event是已经发生的事实Reminder是未来要做的事。很多同类App把两者混在一起导致“记录历史”和“设置提醒”的逻辑纠缠不清。分开之后查询历史用Event表生成待办用Reminder表各自独立AI生成代码时也不会混淆。-- 宠物主表 CREATE TABLE pets ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, species TEXT NOT NULL, breed TEXT, birth_date TEXT, gender TEXT, neutered INTEGER DEFAULT 0, avatar_path TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ); -- 事件表已发生的事实 CREATE TABLE events ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL, event_type TEXT NOT NULL, event_date TEXT NOT NULL, note TEXT, FOREIGN KEY (pet_id) REFERENCES pets(id) ON DELETE CASCADE ); -- 提醒表未来待办 CREATE TABLE reminders ( id INTEGER PRIMARY KEY AUTOINCREMENT, pet_id INTEGER NOT NULL, reminder_type TEXT NOT NULL, next_date TEXT NOT NULL, interval_days INTEGER, enabled INTEGER DEFAULT 1, FOREIGN KEY (pet_id) REFERENCES pets(id) ON DELETE CASCADE );2.2 疫苗与驱虫周期的计算逻辑疫苗和驱虫是宠物管理里最刚需的两个提醒场景它们的周期计算规则不一样需要分别处理。疫苗这块幼犬幼猫有固定的接种程序比如幼犬通常在6到8周龄打第一针之后每隔2到4周打一针总共三针最后加一针狂犬。成年后每年加强一次。这个逻辑用代码表达就是根据出生日期推算首针时间然后按间隔递推。我让AI写了一个calculateVaccineSchedule函数输入出生日期和疫苗类型输出一个日期数组。驱虫的周期更灵活体内驱虫通常每月一次体外驱虫也是每月一次但有些药物是三个月一次。所以驱虫提醒需要支持自定义间隔。我在Reminder表里加了interval_days字段用户设置时可以选择预设周期或手动输入天数。注意疫苗计算里有个坑闰年和月份天数不一致会导致日期偏移。我一开始用简单的“加30天”来算结果跨月时提醒日期对不上。后来改成用日期库的addMonths方法按自然月推算才解决这个问题。2.3 体重曲线的数据聚合与展示体重记录是宠物健康管理的重要指标尤其是对幼年期和老年期。数据存储上每次测量就是一条Record包含日期和体重值。展示时需要把离散的点连成曲线并且按周或月做聚合避免点太密看不清趋势。聚合逻辑我让AI写了一个函数输入原始记录列表和聚合粒度日/周/月输出聚合后的数据点。周聚合取每周的平均值月聚合取每月最后一条记录。这样在图表上用户可以切换粒度看短期波动或长期趋势。ListWeightPoint aggregateWeights( ListWeightRecord records, AggregationType type, ) { if (type AggregationType.day) { return records.map((r) WeightPoint(r.date, r.weight)).toList(); } final grouped String, ListWeightRecord{}; for (final r in records) { final key type AggregationType.week ? weekKey(r.date) : monthKey(r.date); grouped.putIfAbsent(key, () []).add(r); } return grouped.entries.map((e) { final avg e.value.map((r) r.weight).reduce((a, b) a b) / e.value.length; return WeightPoint(parseKey(e.key), avg); }).toList(); }3. 实操过程与核心环节实现3.1 项目初始化与依赖配置第一步是创建Flutter项目然后配置依赖。我在pubspec.yaml里加了几个关键包sqflite做本地数据库path_provider拿文件路径riverpod管状态fl_chart画图表flutter_local_notifications做本地提醒。dependencies: flutter: sdk: flutter sqflite: ^2.3.0 path_provider: ^2.1.1 flutter_riverpod: ^2.4.0 fl_chart: ^0.66.0 flutter_local_notifications: ^16.0.0 intl: ^0.19.0配置完依赖后我让Claude Code生成了数据库帮助类DatabaseHelper负责建表和版本管理。这里有个细节SQLite的onCreate只在首次安装时调用后续加表要改onUpgrade。我一开始没注意加了新表后旧设备上跑不起来后来补了版本迁移逻辑才解决。3.2 宠物建档页面的表单实现建档页面是整个App的入口字段多校验规则也多。我用Flutter的Form和TextFormField搭基础结构然后让AI补充校验逻辑。比如名字不能为空出生日期不能晚于今天体重必须是正数。TextFormField( controller: nameController, decoration: InputDecoration(labelText: 宠物名字), validator: (value) { if (value null || value.trim().isEmpty) { return 请输入宠物名字; } return null; }, ),日期选择用showDatePicker限制最大日期为今天。物种和品种用下拉框品种根据物种联动。这块AI生成得很快但联动逻辑需要自己调因为AI默认会写死选项实际需要根据物种动态加载品种列表。实操心得表单校验里日期字段最容易出问题。showDatePicker返回的是UTC时间直接存本地会差几个小时。我统一在存储前转成本地时间字符串格式用yyyy-MM-dd避免时区混乱。3.3 提醒通知的本地触发机制提醒功能是宠物管理App的核心价值点。我用flutter_local_notifications做本地通知不需要服务器推送离线也能触发。配置流程分三步。第一步初始化通知插件设置Android和iOS的权限。第二步创建通知渠道Android 8.0以上必须指定渠道。第三步用zonedSchedule安排定时通知指定触发时间。final plugin FlutterLocalNotificationsPlugin(); await plugin.initialize( const InitializationSettings( android: AndroidInitializationSettings(mipmap/ic_launcher), iOS: DarwinInitializationSettings(), ), ); await plugin.zonedSchedule( notificationId, 疫苗提醒, ${pet.name}的狂犬疫苗还有3天到期, tz.TZDateTime.from(nextDate, tz.local), const NotificationDetails( android: AndroidNotificationDetails( pet_reminder, 宠物提醒, importance: Importance.high, ), ), androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, );这里有个大坑Android 12以上精确闹钟需要SCHEDULE_EXACT_ALARM权限而且用户可能手动关闭。我一开始没申请通知延迟了好几个小时。后来在AndroidManifest.xml里加了权限声明并且在App启动时引导用户开启。3.4 体重图表的交互实现图表用fl_chart的LineChart数据源是聚合后的体重点。交互上我加了触摸显示具体数值的功能用户点某个点弹出该日期的体重。LineChart( LineChartData( lineBarsData: [ LineChartBarData( spots: weightPoints .map((p) FlSpot(p.date.millisecondsSinceEpoch.toDouble(), p.weight)) .toList(), isCurved: true, dotData: FlDotData(show: true), ), ], lineTouchData: LineTouchData( touchTooltipData: LineTouchTooltipData( getTooltipItems: (spots) spots.map((s) { final date DateTime.fromMillisecondsSinceEpoch(s.x.toInt()); return LineTooltipItem( ${DateFormat(MM-dd).format(date)}: ${s.y}kg, const TextStyle(color: Colors.white), ); }).toList(), ), ), ), )图表这块AI生成的代码基本能用但坐标轴的范围需要手动调。默认范围会从0开始导致曲线挤在上面。我改成根据数据的最小值和最大值动态计算留出10%的边距视觉效果才好。4. 常见问题与排查技巧实录4.1 AI生成代码的典型错误模式用Claude Code写Flutter代码我总结了几类高频错误。第一类是空安全处理不到位AI经常忘记加?或!导致编译报错。第二类是异步上下文问题在async函数里用BuildContext没检查mounted运行时报错。第三类是状态更新时机错误在build方法里调setState导致死循环。针对这些我的做法是每次AI生成代码后先跑flutter analyze把警告和错误清干净再继续。对于异步上下文统一在await之后加if (!mounted) return;。状态更新则尽量用Riverpod的ref.read在事件回调里触发避免在构建期改状态。错误类型典型表现解决方式空安全编译报错null check operator补?或!或用??给默认值异步上下文运行时Context across async gapawait后加mounted检查状态更新死循环或UI不刷新用Riverpod在回调里更新数据库迁移旧设备崩溃改onUpgrade加版本判断通知延迟提醒不准时申请精确闹钟权限4.2 数据库查询性能的优化过程宠物数据量不大但查询频繁。我一开始每次进详情页都全表查Event数据多了之后明显卡顿。后来加了索引在pet_id和event_date上建了复合索引查询速度提升明显。CREATE INDEX idx_events_pet_date ON events(pet_id, event_date DESC);另外列表页的查询我改成了分页加载每次只取20条滚动到底再加载更多。这样即使一只宠物有几百条记录首屏也能秒开。提示SQLite的索引不是越多越好每个索引都会增加写入开销。宠物管理类App的写入频率低读多写少所以适当加索引是划算的。4.3 跨平台UI适配的踩坑记录Flutter虽然跨平台但Android和iOS的UI细节还是有差异。我遇到几个典型问题。第一AppBar在iOS上默认有毛玻璃效果Android没有需要手动统一。第二CupertinoDatePicker和MaterialDatePicker的交互不一样我统一用了Material风格保证一致性。第三状态栏高度在刘海屏上不一致用SafeArea包裹后解决。还有一个坑是字体。iOS默认用San FranciscoAndroid用Roboto中文显示上iOS的苹方和Android的思源黑体也有差异。我最后统一指定了字体族虽然增加了包体积但视觉一致性好了很多。4.4 提醒逻辑的边界情况处理提醒功能有几个边界情况必须处理。第一宠物已经去世的情况所有提醒应该自动停止。我在Pet表加了status字段去世后设为archived查询提醒时过滤掉。第二提醒日期已过的情况比如用户一周没打开App积压的提醒怎么处理。我的做法是启动时检查所有过期提醒合并成一条“有N条过期提醒”的通知避免轰炸。第三用户修改了疫苗周期已有的提醒需要重新计算。这块我在保存设置时触发重算删除旧提醒生成新提醒。Futurevoid rescheduleReminders(int petId) async { final pet await db.getPet(petId); if (pet.status archived) { await cancelAllReminders(petId); return; } await cancelAllReminders(petId); final reminders await generateReminders(pet); for (final r in reminders) { await scheduleNotification(r); } }5. 项目扩展与个人经验沉淀5.1 后续可以叠加的功能模块这个项目跑通之后有几个方向可以继续扩展。第一是多宠物家庭管理现在只支持单宠物改成多宠物只需要在查询时加pet_id过滤UI上加个切换器。第二是就诊记录的结构化现在就诊只是Event加备注可以扩展成独立的表存诊断、用药、费用甚至支持上传化验单照片。第三是数据导出与备份把SQLite数据导出成JSON或CSV方便用户迁移或打印。还有一个有意思的方向是健康预警。根据体重曲线的变化趋势如果短期内下降超过一定比例自动提示用户关注。这个逻辑用简单的线性回归就能实现不需要复杂的模型。5.2 用AI辅助开发的真实体会跑了这个项目之后我对AI辅助开发的理解更深了一层。Claude Code在生成样板代码、补全函数实现、写测试用例这些方面确实快能省掉大量重复劳动。但它在架构设计和业务逻辑的连贯性上还是需要人来把控。我试过让它一次性生成整个模块结果出来的代码虽然能跑但模块之间的接口对不上改起来比自己写还费劲。后来我调整了策略每次只让AI处理一个明确的、边界清晰的任务比如“写一个函数输入宠物出生日期和疫苗类型输出接种日期列表”。这样生成的代码质量高集成也顺畅。另外AI生成的代码一定要跑测试尤其是涉及日期计算、金额计算这些容易出边界错误的地方。实操心得给AI写提示词时把输入输出的格式、边界条件、异常情况都描述清楚比笼统地说“帮我实现这个功能”效果好得多。比如“输入是yyyy-MM-dd格式的字符串如果解析失败返回null如果日期在未来返回空列表”这样AI生成的代码基本不用大改。5.3 给后来者的几点实用建议如果你也想用AI从零搭一个App我的建议是先把数据模型想清楚画个简单的ER图再开始写代码。数据模型是地基地基不稳后面AI生成的代码越多返工越痛苦。其次尽早跑通一个最小闭环比如先实现“建档-记录-提醒”这条主线再逐步加功能。不要一上来就追求大而全容易烂尾。工具方面Claude Code配合Flutter的调试工具已经够用。遇到AI反复改不对的问题别死磕自己上手写反而更快。AI是助手不是替代品这个定位摆正了效率才能真正提上来。最后分享一个小技巧把常用的提示词模板存下来比如“生成一个Riverpod Provider管理XX状态包含加载、成功、失败三种状态”下次直接套用省去重复描述的时间。这个习惯坚持下来开发速度会越来越快。