产品官网:https://diarythreads.niuniuhome.cn
App Store:https://apps.apple.com/us/app/diarythreads-personal-timeline/id6795139345
本文包含AI辅助创作
2026 年 7 月 30 日,DiaryThreads: Personal Timeline 0.2.0 在 App Store 上线。

它是一款只属于自己的时间线日记。每条记录像一条私密帖文,最多 140 个字,可以回复过去的自己,也可以引用一条旧帖文继续写。照片、视频和语音都留在本机,没有账号、日记服务器、广告和遥测。
这个项目从一张浅色界面参考图开始,后来有了可操作的网页原型、SwiftUI 原生 App、两类 Widget、分享海报、付费页、双语官网和六支宣传视频。大部分代码、测试和文档都由我与 Codex 协作完成,ImageGen 负责一部分美术素材,Remotion 负责宣传视频。
仓库在 7 月 28 日建立第一份 Git 基线,App Store 公开版在 7 月 30 日上线。7 月 28 日至 30 日属于密集迭代阶段。初始提交已经包含网页原型、原生工程和测试,完整开发时间无法用两次提交日期来代替。
我想借 Diary Threads 讲讲自己反复使用、结果较稳的 Vibe Coding 方法:先把品味写成约束,再让 AI 在清楚的范围里持续执行。
一、产品起点:我总觉得日记要写得“像篇日记”
我经常在一天结束时想起一两件小事。
可能是路上看到一句话,可能是刚才突然冒出的念头,也可能是某张照片让我想起几年前的自己。等我打开传统日记 App,空白页已经摆在那里了:标题是什么?今天发生了什么?有什么感受?
写几行好像太敷衍,认真写又要花不少时间。我往往就关掉了。
我想做一个接近发帖的日记:想到什么就写一条,140 个字也够;过几天想补充,就在下面回复;翻到旧内容,可以引用它,再和当时的自己接着说。
Diary Threads 的产品形态就这样定了。
我把 X 的单列时间线、头像、回复和引用留了下来,也删掉了点赞、粉丝、公开发现、广告和外部账号。它看起来有社交产品的熟悉感,里面只有一个用户。
这一步花的时间很值。只给 AI 一句“帮我做一个 X 风格日记”,模型很容易顺着社交产品继续补功能。产品边界写清以后,后面的每一次生成都有了判断标准。
二、我先写了一份 AI 必须遵守的产品说明
项目根目录里有一份很长的 AGENTS.md。它既是产品决策记录,也是 Codex 每次动手前要读的工作说明。

里面写的内容很具体:
- 底部导航固定为主页、搜索、分析、收藏;
- 每条帖文的操作顺序固定为回复、引用、编辑、收藏、分享;
- 中文界面里的单条内容统一叫“帖文”;
- 照片和视频引用系统 Photos 资源,App 不保存第二份原件;
- App 锁在应用进入后台时重新上锁,系统相册让应用暂时失去活跃状态时继续保持当前会话;
- 分享海报的单图固定为 1080 × 1350 PNG;
- 构建成功、模拟器运行、真机通过和 App Store 审核要分开记录。
- 我还把产品规格、架构、隐私、开发路线图、决策记录和测试验收拆成了几份独立文档。Codex 接到任务后先读这些文件,再查相关代码。
这套做法解决了一个很现实的问题:AI 的上下文会变化,仓库里的事实源可以一直留着。
我曾提出“把收藏放进底部导航”。AI 需要同时知道免费用户看到什么、已有收藏如何处理、操作栏怎样重新排布、Widget 和本地化是否受影响。口头补充很容易漏,文档能让这些条件一起进入任务。
三、先做网页原型,把视觉判断变成能点击的东西

Diary Threads 的第一份视觉事实是 reference.png。我选定了浅色版本,并把它当作布局、密度、颜色、字体和层级的参考。
我先让 Codex 用 React、Vite 和 TypeScript 做出手机原型。原型运行在完整的 iPhone / Pixel 设备框里,保留状态栏、键盘、Home Indicator、滚动和手势。首页、搜索、分析、收藏、设置、编辑器和详情都能点进去。
网页原型可以回答这些问题:
- 标题放在顶部中间会不会太挤?
- 五个操作图标怎样等距排开?
- 浮动羽毛按钮会不会挡住列表末尾的帖文?
- 搜索键盘弹出以后,底部控件应该往哪里走?
- 「最新」和「看点儿…啥?」左右滑动时,纵向滚动位置怎么保存?
- 只看静态图很难判断这些问题。原型能拖、能点、能输入,很多不自然的地方很快就会暴露。
原型还保留了运行时完整性检查。设备边框、状态栏、键盘和滚动组件属于受保护文件,AI 只能改 App 自己的内容。Playwright 负责检查主要交互,截图用于对照参考图和实现结果。
这让我第一次清楚感受到:Vibe Coding 的高效率来自反馈速度。描述、生成、打开、操作、指出具体问题,几分钟就能走完一轮。
四、原型稳定后把产品写成原生 SwiftUI

网页原型解决视觉和交互,正式 App 使用 Swift 6、SwiftUI、SwiftData、PhotoKit、WidgetKit、StoreKit 2 和 LocalAuthentication。
工程由 XcodeGen 生成,project.yml 统一维护版本、最低系统、设备类型、权限、App Group、Widget 和签名配置。生成后的 Xcode 工程属于构建产物,配置修改都回到 project.yml。
这条规则救过我一次。项目最初准备归档时,XcodeGen 的平台默认值让 Release 产物带上了 iPad 设备族。界面在模拟器里看着正常,App Store 分发包已经偏离“仅 iPhone、仅竖屏”的产品决定。后来我把 TARGETED_DEVICE_FAMILY = 1 固定到 App target,并读取 archive 和 IPA 内的最终值。
同样的情况还出现在启动页。
我想要一段羽毛写出的品牌动画。系统 Launch Screen 先放一个静态 Logo,SwiftUI 再播一次动画,冷启动时会看到 Logo 重复出现。我的处理方式是让系统启动页只画自适应背景,把可见品牌完全交给 SwiftUI。普通模式播放约 1.9 秒,Reduce Motion 使用短暂停留和透明度变化。
这些细节很难靠一句 Prompt 提前说全。我的处理方式是把每次发现的问题写回文档,后续任务自动继承。
五、工具怎样分工
| 工具 | 在项目里负责什么 | 我怎样验收 |
|---|---|---|
| Codex | 读项目、修改代码、补测试、更新文档、执行构建与排查 | 查看 diff、原始命令输出、截图和最终产物 |
| React + Vite | 快速做出能操作的手机原型 | Playwright 交互检查、参考图对比、手动操作 |
| SwiftUI + XcodeGen | 构建原生 iPhone App,XcodeGen 根据同一份文件生成工程配置 | xcodebuild、archive、IPA 配置检查 |
| XCTest + XCUITest | 检查文字规则、媒体生命周期、权限状态、路由和界面行为 | 分开记录单元测试、UI 测试、模拟器与真机结果 |
| ImageGen | 生成羽毛、分享海报、Premium 和 Widget 的固定美术背景 | 检查尺寸、文字安全区、深浅色和最终截图 |
| Remotion | 用代码生成中英文横版、竖版和 App Store 宣传视频 | 帧级截图、时长、音频署名、输出文件校验 |
我对 ImageGen 的使用方式也调整过。
早期我会让生成图承担很多内容,后来发现固定文字、动态数字和用户照片很容易互相打架。Diary Threads 的分享海报改成两层:ImageGen 只画纸张、水彩、羽毛和光线,SwiftUI 负责头像、昵称、日期、正文和真实照片。
固定美术和动态内容分开以后,视觉保持统一,动态内容也能测试。长海报接近 ImageIO 稳定编码高度时,程序会按完整卡片分页;照片高度会提前算进去,图片不会被切到下一页外面。验收以最终导出的 PNG 为准。
六、我给 Codex 的任务,很少只有一句话
一次相对完整的任务通常包含这些字段:
工作目录:
项目仓库根目录
启动前阅读:
- AGENTS.md
- 项目/产品规格.md
- 项目/架构与数据.md
- 项目/测试与验收.md
已确认事实:
- 当前操作栏有五个等宽槽位
- 照片根帖文可以分享
- 回复、视频和语音保留空分享槽位
本次目标:
- 让 1 至 4 张照片按附件顺序进入分享海报
- 缺失资源显示占位
- 长图分页提前计算媒体高度
禁止修改:
- 不改 SwiftData schema
- 不复制 Photos 原件
- 不改变回复、视频和语音的分享资格
验收:
- 单图仍为 1080 × 1350 PNG
- 长图在完整卡片边界分页
- 单元测试通过
- 最终 PNG 无裁切、溢出和异常留白
最终回报:
- 修改文件
- 测试结果
- 已验证与待真机验证的项目
这里最有用的是“已确认事实”“禁止修改”和“验收”。它们让 AI 知道任务的边缘,也让我能快速判断结果。
我不会把“看起来改好了”当成完成。Codex 需要跑测试、打开模拟器、导出文件,或明确告诉我哪一步必须留给真机和外部平台。
Diary Threads 的一次完整回归包含 35 项单元测试和 22 项 UI 测试,共 57 项全部通过。相机实拍、真实麦克风、有限相册权限、iCloud Photos 离线和设备所有者认证仍然单独列在真机 QA 里。
七、几次具体的坑,让我重新理解“可靠”
1. 媒体保存不能只看界面
用户从相册选一张照片,时间线能显示出来,表面上已经完成。
项目还要回答很多后续问题:App 有没有复制原件?用户删掉系统照片后显示什么?重新关联会不会新建附件?相机拍摄后取消编辑,刚创建的 Photos 资源由谁清理?发布以后还能不能误删?
我的处理方式是把相册选择、相机创建、编辑会话所有权、发布提交和取消清理分开设计。SwiftData 只保存 Photos 标识,相机新建的资源在发布前归当前编辑会话管理。
2. .inactive 和 .background 的差别会影响 App 锁
相册、权限弹窗和 Face ID 都可能让 App 暂时进入 .inactive。每次 .inactive 都上锁,用户刚选完头像就会立刻看到认证页面。
最终规则只在场景进入 .background 时重新上锁。这个改动很小,背后需要先弄清系统生命周期和用户动作。
3. 测试通过以后还要看最终产物
分享海报曾经在 SwiftUI 预览里正常,导出的 1080px 长图出现顶部留白和正文宽度异常。构建不会替我发现视觉问题,单元测试也很难判断一张图看起来是否舒服。
所以我把最终 PNG、模拟器截图、archive、IPA 和线上页面都当成独立证据。它们分别回答不同的问题。
4. 文案同样需要自动检查
Diary Threads 中英文资源里有一条严格规则:简体中文的单条内容只能叫“帖文”。“日记”“推文”“发推”和错字“贴文”都会让本地化脚本失败。
这个门禁看起来有些执拗,它保护了产品语气。AI 同时改几十个页面时,统一术语不能依赖记忆。
八、Vibe Coding 里的“品”从哪里来
AI 可以快速给出十种界面、二十个功能和一堆看起来合理的建议。哪些内容进入正式产品,仍然需要人来决定。
Diary Threads 的许多选择都很小:
- 删除点赞,让记录不用等待反馈;
- 保留回复和引用,让过去的内容能继续生长;
- 让搜索、日历和首页进入统一的帖文详情;
- 分享海报底部留白,拿掉口号和锁图标;
- 系统语言交给 iOS,设置里不再增加重复的语言开关;
- 照片继续由 Photos 管理,App 不悄悄保存副本;
- Reduce Motion 保留信息顺序,收掉大幅位移。
- 这些选择散在代码、文案、动画、数据和权限里。它们需要反复判断,也需要把判断写进项目,让下一轮 AI 继续遵守。
我现在再打开仓库,最有成就感的是那些已经被写进规则的细节:中文只能叫“帖文”,五个操作图标必须等距,打开系统相册后继续保持前台会话,分享海报要看最终 PNG。
它们让 Diary Threads 有了稳定的性格。
九、我会怎样开始下一个 Vibe Coding 项目
我会继续沿用下面的顺序:
- 先写一页产品判断,明确用户、主要动作、数据边界和首版删除项。
- 选一张视觉参考,说明哪些布局、密度和气质需要保留。
- 做一个能点击的原型,尽早在真实操作里发现问题。
- 把长期约束写进 AGENTS.md,把产品、架构、隐私和验收分别保存。
- 每个任务都写清事实、目标、禁止项、验收和回报格式。
- 让 AI 执行构建、测试和截图,把人工判断留给产品取舍与最终体验。
- 每次踩坑后更新事实源,避免同一个问题在后续任务里重新出现。
Vibe Coding 给我的最大变化,是很多以前排队等时间的想法,现在可以很快做出第一版。我也比以前更忙着做判断:这个功能该不该有,数据应该放在哪里,用户按下按钮以后会发生什么,最终文件能不能交给真实用户。
Diary Threads 已经上线,我还在继续改它。下一次打开编辑器时,我依然会先写几句很具体的话,再把任务交给 AI。
