chore: 导入清理前的完整工程状态(含 Capacitor 原生壳,作为回滚备份点)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# 0001 菜谱数据的来源、质量与反馈闭环
|
||||
|
||||
- 状态:已实施(数据源为仓库 CSV,飞书已下线)
|
||||
- 日期:2026-10-18
|
||||
|
||||
## 背景
|
||||
|
||||
菜谱维护在飞书电子表格里,维护者手动执行 `pnpm fetch` 导出为 `app/data/recipe.csv`。主要问题:
|
||||
|
||||
- 没有内容校验。首次校验发现 21 处错误:错别字(「葫芦卜」「方面」)、逗号代替顿号、不在词典里的食材(「肉」「虾仁」「木耳」)、不存在的难度「复杂」。食材写错的菜谱永远筛选不到。
|
||||
- 失效视频只能等用户提 issue(#63、#83、#50、#47、#38)。
|
||||
- 外部贡献者要先被拉进飞书才能改数据。
|
||||
- 597 条中约 29% 缺难度、37% 缺做法。
|
||||
|
||||
## 方案对比
|
||||
|
||||
| 方案 | 贡献门槛 | 运营成本 | 质量保障 |
|
||||
| ------------------------------------------------ | --------------- | ------------------- | ---------------------- |
|
||||
| 继续飞书表格 | 需进飞书 | 手动 fetch 提交 | 无 |
|
||||
| 飞书多维表格 + 表单 | 低 | 审核表单 + 定时同步 | 字段级校验 |
|
||||
| 仓库 CSV 为唯一数据源,Issue / PR 贡献 + CI 校验 | Issue 表单或 PR | 只需审 PR | schema 校验 + 定期巡检 |
|
||||
| 自建数据库后台 | 低 | 运维、鉴权、防灌水 | 自己写 |
|
||||
|
||||
## 决定
|
||||
|
||||
已实施(与数据源放在哪里无关,两条路线都需要):
|
||||
|
||||
- `pnpm validate` 在 CI 中校验食材、厨具词典、取值和视频号格式。
|
||||
- 每周巡检 B 站视频,失效列表汇总到一个 issue。
|
||||
- 详情页反馈入口和菜谱 Issue 表单。
|
||||
- AI 审查做成仓库内的 `recipe-data-review` skill,由维护者在本地用 Codex / DeepSeek 等定期运行,只开 PR。不放在 GitHub Actions 里,避免 API Key 进仓库 Secrets,也不绑定某一家模型。
|
||||
|
||||
待定:数据源是否从飞书迁回仓库。倾向迁回仓库,不新开飞书表格(多一份数据只会多一处冲突)。
|
||||
|
||||
**结论:已迁回仓库。** `packages/data/recipe.csv` 是唯一数据源,`pnpm fetch` 与飞书依赖已移除;需要批量编辑时用飞书 / Excel 打开 `recipe.csv`,改完提 PR,CI 校验。
|
||||
|
||||
## 影响
|
||||
|
||||
- ~~收藏以行号为 id,因此不能删除或重排已有行。~~ 已由 [0002](./0002-feedback-and-ids) 引入固定 `id` 列解决;重复行(如「电饭煲版红烧肉」第 12/24 行)仍保留为警告,由维护者决定是否删除。
|
||||
- 反馈入口用 GitHub Issue,没有 GitHub 账号的用户仍走原来的兔小巢 / 投稿表单。
|
||||
- AI 只起草、不合并;不允许编造视频号。
|
||||
@@ -0,0 +1,39 @@
|
||||
# 0002 菜谱固定 id、应用内反馈与筛选信号
|
||||
|
||||
- 状态:已采纳
|
||||
- 日期:2026-10-18
|
||||
|
||||
## 背景
|
||||
|
||||
- 收藏按菜谱在数据里的位置记录,删一行会让后面所有菜的收藏错位,数据因此不敢清理;[#98](https://github.com/YunYouJun/cook/issues/98) 计划把收藏同步到云端,位置 id 一同步就会出错。
|
||||
- 普通用户大多不用 GitHub,Issue 表单收不到他们的反馈。
|
||||
- 想让 AI 定期优化筛选,需要真实的使用数据和一个能对比前后效果的评测。
|
||||
|
||||
## 方案对比
|
||||
|
||||
| 问题 | 方案 | 取舍 |
|
||||
| ------------ | ------------------------------------------- | ------------------------------------------------------------ |
|
||||
| 菜谱 id | 用位置(现状) | 不能删、不能重排 |
|
||||
| | 按菜名 + 视频算哈希 | 改菜名或换视频就变成另一道菜 |
|
||||
| | **CSV 新增 `id` 列,取值等于现在的位置** | 已有收藏无需迁移,老版本客户端也兼容;需要校验防止改动或复用 |
|
||||
| 反馈渠道 | GitHub Issue | 普通用户不用 |
|
||||
| | 第三方表单(兔小巢、腾讯问卷) | 零开发,但要跳出应用、不带菜谱信息、难以自动汇总 |
|
||||
| | 自建后台 | 要维护服务、登录、页面 |
|
||||
| | **CloudBase 云函数 + 集合** | 复用现有 CloudBase,没有新服务;未登录也能提交 |
|
||||
| 是否强制登录 | 强制 | 门槛太高,大部分人会放弃 |
|
||||
| | **不强制,登录后带上账号** | 匿名提交按设备限频;登录用户的反馈权重更高,也能回访 |
|
||||
| 管理后台 | 先做 `/admin` | 现阶段反馈量小,不划算 |
|
||||
| | **skill 汇总 + PR 审核 + CloudBase 控制台** | 反馈量大到需要非开发者帮忙审核时再做只读看板 |
|
||||
|
||||
## 决定
|
||||
|
||||
- `recipe.csv` 新增 `id` 列。已发布的 id 不能修改或复用,新菜谱用最大 id + 1;CI 用 `pnpm validate --base` 对比目标分支。
|
||||
- 菜谱详情页一键反馈,写入 `cook-feedback` 云函数;提交失败时退回 GitHub Issue 表单。
|
||||
- 应用匿名记录「无结果的食材组合」和「点开了第几个结果」两类聚合信号,不含账号信息。
|
||||
- `pnpm feedback:pull` 汇总反馈并生成评测样例 `test/fixtures/search-eval.json`,`pnpm eval:search` 评估排序。`recipe-data-review` skill 据此改数据、别名和排序,修改前后的评测指标写进 PR。
|
||||
- 反馈功能是普通网页代码,浏览器和云乐坊容器里都能用,不依赖 Capacitor,与 #98 下线独立 App 的计划一致。
|
||||
|
||||
## 影响
|
||||
|
||||
- 需要在 CloudBase 控制台建集合、部署函数、配置导出口令和 HTTP 访问,并允许未登录用户调用该函数(步骤见 [菜谱数据](/dev/data#cloudbase-配置一次性))。在此之前,提交会失败并引导用户去 GitHub。
|
||||
- 删除菜谱现在是安全的,只影响收藏了这道菜的用户;是否删除由维护者决定,skill 不会自动删除。
|
||||
@@ -0,0 +1,71 @@
|
||||
# 0003 原生 iOS App 与 monorepo 结构
|
||||
|
||||
- 状态:已采纳
|
||||
- 日期:2026-10-18
|
||||
- 关联:调整 [#98](https://github.com/YunYouJun/cook/issues/98) 的阶段 4
|
||||
|
||||
## 背景
|
||||
|
||||
- 目标从「只维护一套网页」变成「打磨一个能上架收费的 iOS App」,Web 保留并继续服务浏览器和云乐坊容器。
|
||||
- 现在的独立 App 是 Capacitor 壳,界面是 Ionic 画的网页:拿不到 iOS 26 的 Liquid Glass、Widget、App Intents、Spotlight,CloudKit 同步也要自己写插件,作为付费 App 说服力和过审把握都不够。
|
||||
- 仓库已经半个 monorepo:根目录是 Nuxt 应用,`packages/cook` 里有类型、CSV 转换、推荐(`recommend.ts`)和搜索(`search.ts`),核心匹配逻辑不到 200 行。
|
||||
|
||||
## 方案对比
|
||||
|
||||
| 问题 | 方案 | 取舍 |
|
||||
| ------------ | -------------------------------------------------- | ---------------------------------------------------------- |
|
||||
| iOS 客户端 | Capacitor 壳(现状) | 一套代码;体验上限低,系统能力要逐个写插件 |
|
||||
| | **SwiftUI 原生** | 体验和系统能力最好;核心逻辑要用 Swift 再写一份 |
|
||||
| 逻辑如何共享 | iOS 内嵌 JavaScriptCore 跑 TS 核心 | 零重复;跨语言调试、类型和并发都别扭 |
|
||||
| | **共享数据 + 共享测试用例,Swift 移植核心** | 要写两份,但核心很小;同一套用例保证两端推荐结果一致 |
|
||||
| 仓库结构 | 原生单独开仓库 | 数据和用例要跨仓库同步,容易漂移 |
|
||||
| | **参考 starter-monorepo:`apps/*` + `packages/*`** | Web、iOS、数据、核心在一个仓库,一个 PR 能同时改数据和两端 |
|
||||
| 同步 | 只用 CloudBase | 三端通用,但要登录,服务器有成本 |
|
||||
| | **CloudKit 免费 + CloudBase 会员跨平台** | 免费用户零成本零登录;会员费覆盖服务器成本 |
|
||||
|
||||
## 决定
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
apps/
|
||||
web/ Nuxt 应用(现在根目录的 app/、public/、nuxt.config.ts 等)
|
||||
ios/ SwiftUI 工程(替换现在 Capacitor 的 ios/)
|
||||
packages/
|
||||
data/ recipe.csv、incompatible-foods.csv、生成的 JSON、JSON Schema、dataVersion
|
||||
core/ 纯 TS:类型、推荐、搜索、别名、相克判断,不依赖 Vue / Node
|
||||
cook/ CLI(convert / fetch / validate / eval),沿用 @yunyoujun/cook 包名
|
||||
fixtures/ 两端共用的测试用例:输入食材 → 期望的菜谱 id 顺序
|
||||
cloudfunctions/ 不变
|
||||
docs/ 不变
|
||||
```
|
||||
|
||||
- 搬迁只做 `git mv` 和路径修改,不改逻辑;搬完 `pnpm lint`、`typecheck`、`test`、`build` 全绿再合并。
|
||||
- `packages/core` 从 `packages/cook` 里拆出;`@yunyoujun/cook/recommend` 保留重新导出,已有用法不受影响。
|
||||
- iOS 侧有一个 Swift Package(`CookCore`),读同一份 JSON、跑同一份 `packages/fixtures`。推荐逻辑改动必须同时改两端,CI 里两边都跑用例。
|
||||
|
||||
> **实施时的调整(2026-10-19)**:`packages/cook` 的推荐逻辑本来就不依赖 Vue / Node,并已通过 `@yunyoujun/cook/recommend` 单独导出,所以不再拆 `packages/core`;共享用例放在 `packages/data/fixtures/`,不单独建 `packages/fixtures`。食材词典、常备调料和别名也改成 `packages/data` 里的 JSON,Web 和 iOS 读同一份。
|
||||
|
||||
### 数据
|
||||
|
||||
- JSON 加 `schemaVersion`(结构)和 `dataVersion`(内容)。App 内置一份,启动后可从 CDN 拉更新的 `dataVersion`,改菜谱不用发版。
|
||||
- 菜谱 `id` 规则不变(见 [0002](./0002-feedback-and-ids)):收藏、历史、同步都以 id 为主键。
|
||||
|
||||
### 同步与收费
|
||||
|
||||
- 本地数据库是唯一数据源:iOS 用 SwiftData,CloudKit 同步本地数据。
|
||||
- 会员开启 CloudBase 作为第二个同步通道,与 Web 共用账号;两个云之间不直接同步。每条记录带 `updatedAt` 和软删除标记,冲突时取最新。
|
||||
- iOS 里的会员走 StoreKit 内购;Web 购买的会员登录后可在 iOS 解锁(App Store 审核指南 3.1.3(b))。
|
||||
- App 免费下载 + 会员,不做付费下载,方便沿用现有商店条目和用户。
|
||||
|
||||
### 与 #98 的关系
|
||||
|
||||
- 阶段 1~3(云乐坊容器、数据同步)照常进行,Web 仍是浏览器和云乐坊的唯一代码。
|
||||
- 阶段 4 改为:独立 App 不下架,而是用 SwiftUI 版本替换 Capacitor 版本,沿用 `cn.yunyoujun.cook`,老用户直接收到更新。Capacitor 相关代码在 SwiftUI 版上架后移除;`android/` 是否保留另行决定。
|
||||
|
||||
## 影响
|
||||
|
||||
- iOS 开发、构建和 UI 调试需要 macOS + Xcode 26,云端环境只能写代码和跑纯 Swift / TS 测试。
|
||||
- 推荐逻辑的改动成本变成两份,靠共享用例兜底;核心逻辑应尽量保持小而纯。
|
||||
- 搬迁会和进行中的 PR 冲突,需要等它们合并后再开始,且搬迁 PR 要尽快合并。
|
||||
- 打磨计划和验收标准见 [iOS App 打磨目标](/dev/ios-roadmap)。
|
||||
@@ -0,0 +1,17 @@
|
||||
# 方案记录
|
||||
|
||||
记录项目里做过的重要决定:当时的问题、考虑过的方案、选了什么、为什么。之后想改方向时,先看这里,避免重复讨论。
|
||||
|
||||
## 怎么写
|
||||
|
||||
- 每个决定一个文件:`docs/decisions/NNNN-简短英文名.md`,编号递增。
|
||||
- 状态:提议中 / 已采纳 / 已废弃 / 被 NNNN 取代。改变决定时新写一篇并更新旧篇状态,不要直接改写旧结论。
|
||||
- 结构:背景、方案对比、决定、影响,写清楚取舍即可,不用长。
|
||||
|
||||
## 列表
|
||||
|
||||
| 编号 | 标题 | 状态 |
|
||||
| ---------------------------------- | --------------------------------- | ------ |
|
||||
| [0001](./0001-recipe-data) | 菜谱数据的来源、质量与反馈闭环 | 提议中 |
|
||||
| [0002](./0002-feedback-and-ids) | 菜谱固定 id、应用内反馈与筛选信号 | 已采纳 |
|
||||
| [0003](./0003-native-ios-monorepo) | 原生 iOS App 与 monorepo 结构 | 已采纳 |
|
||||
Reference in New Issue
Block a user