edit | blame | history | raw

用户目标

  • 阅读 Docs/X-01产品文档/2026-06-25-PRD-免费版与Pro解锁.md
  • 基于当前 src/ 代码结构,产出“Pro 权益与购买链路”落地意见。
  • 重点覆盖 StoreKit 2 权益模型、老付费用户 originalAppVersion / originalPurchaseDate 迁移、离线缓存 / 退款撤销 / Family Sharing / 恢复购买状态机、以及现有接入点与禁止写入位置。
  • 仅做分析,不修改源码。

已完成事项

  • 读取项目入口规则、CODE_GOVERNANCE.md、前置讨论规则、连续推进规则、会话记忆规则。
  • 读取 PRD 全文。
  • 检查当前仓库状态与分支。
  • 扫描 src/Apptag/ 现有结构,确认当前没有任何 StoreKit / 购买代码。
  • 核对关键源码入口:
  • ApptagApp.swift
  • PreferencesView.swift
  • ContentView.swift
  • DataLayer.swift
  • AppDefaults.swift
  • AppGridTheme.swift
  • AppIdentity.swift
  • Diagnostics.swift
  • ProcessSingleton.swift
  • Info.plist
  • 用 Apple 官方文档/视频检索核对以下 API 事实:
  • AppTransaction.shared
  • originalAppVersion
  • originalPurchaseDate
  • Transaction.currentEntitlements
  • Transaction.ownershipType
  • Transaction.revocationDate
  • AppStore.sync()

关键决策

  • 建议把 Pro 权益拆成两条独立来源再合并:
  • 老付费用户来源:AppTransaction.shared -> originalAppVersion 主判定,originalPurchaseDate 仅在生产环境下兜底。
  • IAP 来源:Transaction.currentEntitlements + Transaction.updates + 非消耗型商品。
  • 建议把“权益真值”与“购买/恢复操作态”分离建模,避免 pendingrestore、网络失败覆盖已确认的 Pro 状态。
  • 建议新增独立缓存文件到 ~/Library/Application Support/TagLauncher/,不要把购买状态写入 tags.json
  • 建议把老用户迁移判定做成“可重算、带证据字段”的规则,而不是首次命中后只写一个永久布尔值。
  • 建议把负向撤权做成“仅在有明确已验证信号时生效”;离线或 StoreKit 暂时不可用时保留最近一次已验证 Pro。

文件变更

  • 无源码改动。
  • 新增本轮会话摘要:
  • .codex-sessionhistory/2026-06-26-Pro权益链路.md

未决问题

  • 免费 + Pro 首个版本对应的精确 CFBundleShortVersionString 尚需冻结,不能默认拿当前仓库 8.0.6 直接当阈值。
  • originalPurchaseDate 兜底所用的绝对时间戳(含时区)尚需冻结。
  • Lifetime Pro 的最终 product ID 尚需冻结。
  • Settings 中 Pro 状态区是单独 tab 还是挂在现有 tab 顶部,尚需产品/UI 冻结。

后续建议

  • 下一步先产出一份实现级设计稿:状态枚举、缓存结构、启动流程、恢复流程、负向撤权条件、QA 矩阵。
  • 实施时优先从 ApptagApp.swift 启动链路和 PreferencesView.swift 设置入口落地,再接 ContentView.swift / TagEditor 的功能门禁。