Skip to content

ericze/sprout

Repository files navigation

初长 sprout

Sprout. At your own pace.

让成长,按自己的节奏发生。

初长是一个面向 0-3 岁宝宝家庭的成长记录 App。它服务的是疲惫、缺觉、没有精力和复杂界面周旋的父母:快速记录,低噪音反馈,本地优先保存,不用连续打卡、奖杯或高刺激的成长焦虑来驱动使用。

产品原则

  • 安静、克制、低焦虑。
  • 核心记录流程必须快速完成,不依赖网络或 AI。
  • 默认 local-first,云同步只能增强体验,不能阻塞记录。
  • 视觉上保持极简、温暖、编辑感和 Apple 原生气质。
  • 不做卡通化母婴 App,不使用高饱和颜色、彩色标签、游戏化奖励或庆祝动画。

技术栈

  • 平台:iOS 17.0+
  • UI:SwiftUI
  • 数据持久化:SwiftData
  • 状态观察:Observation
  • 工程:Xcode project
  • 同步能力:Supabase 相关服务与本地同步引擎
  • 订阅能力:StoreKit 相关领域模型与服务封装

功能模块

  • 首页记录:奶、尿布、睡眠、辅食等高频记录入口与时间线展示。
  • 成长:身高、体重、里程碑、趋势图和克制的解释性文案。
  • 珍藏:照片、文字记忆、时间线、月锚点和周信。
  • 多宝宝:通过 BabyRepository 创建 / 切换 active baby,Home / Growth / Treasure 的记录与记忆查询按当前 babyID 隔离。
  • 侧边栏:宝宝资料、设置入口、订阅与状态信息承载。
  • 同步:本地优先的数据迁移、游标、资产同步和删除墓碑。
  • Cloud Sync:SupabaseService 已接入 Supabase Auth、Postgres RPC / 增量查询、Storage 上传下载删除;同步仍保持 local-first,失败不会删除本地数据。
  • 国际化:字符串目录、语言状态、格式化服务和文案模板提供器。

目录结构

sprout/
  DesignSystem/        语义化颜色、排版、形状等设计系统入口
  Domain/              业务模型、仓储、规则、格式化和服务
  Features/            按功能拆分的 SwiftUI 页面、容器、组件和 sheet
  Shared/              跨功能复用的 UI、日志、本地化和工具类型
  Localization/        String Catalog 与本地化资源
  Assets.xcassets/     App 图标、颜色和图片资源

sproutTests/           单元测试与测试支撑
Config/                本地构建配置示例和环境配置
docs/                  PRD、规格、验收、发布与实现计划

核心边界:

  • Features 负责渲染、布局和交互接线,不承载复杂业务逻辑。
  • Domain 放业务规则、数据转换、仓储和副作用边界。
  • Shared 只放真正跨模块复用的轻量能力。
  • DesignSystem 提供语义化 token,业务页面不应散落一次性色值。

本地运行

  1. 使用 Xcode 打开 sprout.xcodeproj
  2. 选择 sprout scheme。
  3. 如需启用 Supabase 相关能力,复制配置模板并填入本地值:
cp Config/Supabase.xcconfig.example Config/Supabase.local.xcconfig

SUPABASE_URL 必须填写项目根地址,例如 https://<project-ref>.supabase.co,不要填写 /rest/v1/ endpoint。

  1. 在 Supabase SQL Editor 执行 supabase/migrations/202604270001_account_cloud_sync.sql,创建账号同步所需的表、RPC、RLS policy 和私有 Storage bucket。

  2. 构建并运行到 iOS 17.0+ 模拟器或真机。

核心记录流程应在没有网络、没有 AI 服务、没有云同步成功的情况下保持可用。

测试

使用 Xcode Test 运行 sproutTests,或通过命令行执行:

xcodebuild test \
  -project sprout.xcodeproj \
  -scheme sprout \
  -destination 'platform=iOS Simulator,name=iPhone 15'

测试覆盖重点包括:

  • 记录校验、时间线格式化和首页 store。
  • 成长数据、图表交互、里程碑和格式化。
  • 珍藏时间线、周信、图片路径和仓储。
  • 同步状态、游标、迁移、启动容器和订阅状态。
  • Supabase 配置校验、Auth 管理、真实服务 smoke 测试门控与真实数据链 smoke。
  • 国际化语言状态、模板和本地化格式。

真实 Supabase smoke 默认跳过外部连接;只有显式设置以下环境变量时才会登录真实后端。当前真实 smoke 覆盖 Auth 登录 / 退出、server_nowbaby_profiles / record_items / memory_entries 的 upsert / fetch / soft delete,以及私有 Storage 上传 / 下载 / 删除:

SPROUT_REAL_SUPABASE_SMOKE=1
SPROUT_SUPABASE_URL=https://<project-ref>.supabase.co
SPROUT_SUPABASE_ANON_KEY=<anon-key>
SPROUT_SUPABASE_TEST_EMAIL=<test-user-email>
SPROUT_SUPABASE_TEST_PASSWORD=<test-user-password>

开发约束

  • 优先使用 Apple 原生能力;未经明确要求,不引入第三方依赖。
  • View 文件保持小而可组合,复杂逻辑下沉到 store、service 或 domain。
  • 应用级和功能级状态优先使用 @Observable
  • View 本地状态按 SwiftUI 习惯使用 @State@Binding@Environment@FocusState@Bindable
  • 应用内语言切换统一通过 AppLanguageManager 持久化并更新 LocalizationService,不要在页面里直接改静态本地化状态。
  • Pro 权益入口统一走 ProCapabilitySubscriptionManager.allows(_:);页面和菜单只声明 requiredCapability,不要散落原始 isPro 判断。
  • Paywall 主承诺统一来自 PaywallContent.promotedCapabilities;未通过发布验收的能力不得出现在可购买权益列表中。
  • Paywall 的 Terms / Privacy 链接维护在 docs/legal 对应文档,禁止使用 example.com 占位链接。
  • 多宝宝数据读取必须以 active baby 为默认边界;新增记录、成长记录、珍藏记忆时应写入当前 active babyID。若要扩展到 WeeklyLetter schema,必须先设计 staged migration,避免重复 version checksum。
  • Cloud Sync 服务层统一通过 SupabaseService 访问真实后端;页面和 store 不直接拼 Supabase REST URL,不直接持有 anon key,不把 /rest/v1/ 当项目 URL 使用。
  • Config/Supabase.local.xcconfig 只保存本机真实 URL / anon key,必须保持 git ignored,不能提交。
  • 公共类和公开函数保持清晰命名,复杂业务决策才添加注释。
  • 不硬编码业务页面颜色,统一走语义化设计 token。
  • 不使用纯黑文本、高饱和提示色或刺眼错误红。
  • 错误与危险状态优先通过文案、层级和确认流程表达,不靠强刺激视觉。
  • 成长解读等解释性文本不使用 emoji 作为前缀或图标,避免缺字、误读和额外视觉噪音。
  • 修改 SwiftData schema 时,staged migration 中每个版本的模型集合必须保持唯一;不要用“删除后再新增同一模型集合”的方式推进版本,否则会触发重复 version checksum。
  • 变更保持最小 diff,避免巨型 ViewModel、God Object 和无关重构。

设计系统基线

基础语义色:

  • background:Light #F7F4EE,Dark #1C1A18
  • cardBackground:Light #FFFFFF,Dark #2A2724
  • primaryText:Light #3A342F,Dark #EFEAE0
  • accent#8FAE9B
  • highlight#D89A7A,仅用于 AI 周报或重要里程碑

派生层级:

  • secondaryText = primaryText.opacity(0.6)
  • tertiaryText = primaryText.opacity(0.4)

默认形状:

RoundedRectangle(cornerRadius: 24, style: .continuous)

默认动效:

.animation(.spring(response: 0.3, dampingFraction: 0.7), value: state)

维护准则

每次实现前优先问:

这是否让疲惫的父母用更少噪音、更低负担完成记录?

如果答案是否定的,应该优先删减复杂度,而不是增加入口、动效、提示或解释。

About

初长 ios端

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors