站点只给本人用,云乐坊 SSO 授权、收藏/历史云同步、获客归因和账号切换记账都没有收益,却被登录状态检查和同步失败提示持续打扰。 - 删除 useYunlefunAuth / yunlefunAuth / yunlefunSsoConfig / yunlefunAuth 适配器、useUserDataSync / userDataSync / userData 适配器、三个 client 插件与 /auth/callback 回调页 - 抽出 adapters/cloudbase.ts,让「反馈一下」和匿名筛选信号不再依赖登录态;cook-feedback 云函数保留 - 删除 cook-user-data 云函数与 cook_user_data 权限规则,移除 @yunlefun/sso 依赖 - 「我的」页删掉登录按钮、账号卡、四个统计格和退出登录;「关于」页删掉项目作者、致谢名单和上游宣传链接 - 本地收藏/历史与导出导入保留,删除同步专用的 lastUid 记账 取舍见 docs/decisions/0005-drop-login-and-sync.md
104 lines
7.4 KiB
Markdown
104 lines
7.4 KiB
Markdown
# 菜谱数据
|
||
|
||
## 数据流
|
||
|
||
```
|
||
packages/data/recipe.csv ──pnpm convert──▶ recipe.json / 分片 ──▶ IndexedDB ──▶ 筛选
|
||
▲
|
||
应用内反馈 / Issue / AI PR ┘ CI:pnpm validate 每周:pnpm check:videos
|
||
```
|
||
|
||
`packages/data/recipe.csv` 是构建时实际使用的数据,直接在本地维护。
|
||
|
||
## 数据规则
|
||
|
||
列为 `name,stuff,bv,difficulty,tags,methods,tools,id`。
|
||
|
||
| 字段 | 规则 |
|
||
| ------------- | --------------------------------------------------------------------------------------------- |
|
||
| name | 必填 |
|
||
| stuff | 必填;只能使用 `packages/data/food.json` 里的食材名,别名(如「虾仁」)要写成标准名(「虾」) |
|
||
| bv | B 站 BV 号或 av 号 |
|
||
| difficulty | 简单 / 普通 / 困难,或留空 |
|
||
| methods、tags | 自由填写 |
|
||
| tools | 只能使用 `packages/data/food.json` 里的厨具名 |
|
||
| id | 必填,非负整数且唯一;新菜谱用当前最大 id + 1 |
|
||
|
||
单元格内多个值用顿号「、」分隔,不要用逗号或斜杠。
|
||
|
||
**id 一旦发布就不能修改或复用。** 收藏、用户反馈和筛选信号都按 id 记录(`apps/web/app/utils/db.ts` 用它作 IndexedDB 主键)。可以改菜名、换视频,也可以调整行的顺序;删除一道菜只会让收藏了它的用户丢失这一条,其他菜不受影响。被删掉的 id 不要再给新菜用。
|
||
|
||
## 校验
|
||
|
||
```bash
|
||
pnpm validate # 有错误时退出码为 1,CI 中会在对应行标注
|
||
pnpm validate --json # 输出 JSON,供 AI / 脚本使用
|
||
```
|
||
|
||
错误会让 CI 失败:缺 id 或 id 重复、未知食材或厨具、分隔符错误、难度取值不对、视频号格式不对。
|
||
警告只做提示:同名菜谱、完全重复的行。同时会统计缺难度、缺做法的比例。
|
||
|
||
PR 上 CI 还会运行 `pnpm validate --base <目标分支>`:同一个 id 的菜名和视频都变了(像是把 id 挪给了另一道菜)或复用了已删除的 id 会报错,删除菜谱会给出警告。
|
||
|
||
想用新的食材,先在 `packages/data/food.json` 里加上,再在菜谱里使用。
|
||
|
||
## 反馈闭环
|
||
|
||
1. **用户反馈**:菜谱详情底部点「反馈一下」,选问题类型(视频打不开、食材或厨具不对、难度或做法不对、其他)即可提交,不需要 GitHub,也不强制登录。数据进 CloudBase 的 `cook-feedback` 云函数;提交失败时引导用户去 GitHub Issue 表单(`.github/ISSUE_TEMPLATE/recipe.yml`,已预填菜名和视频)。
|
||
2. **筛选信号**:应用匿名记录两类聚合数据,只有食材组合、厨具、模式和菜谱 id,不含账号:
|
||
- 停在一组食材上却没有任何结果(说明缺这类菜,或别名没对上);
|
||
- 在某组食材下点开了第几个结果(排得太靠后说明排序可以改进)。
|
||
3. **失效巡检**:`Check Videos` workflow 每周一调用 B 站接口检查全部视频,把失效列表写进带 `dead-video` 标签的 issue(已有就更新)。本地可运行 `pnpm check:videos`。
|
||
4. **AI 定期审查**:仓库里的 `recipe-data-review` skill(`skills/recipe-data-review/SKILL.md`)描述了完整流程:拉取应用内反馈和筛选信号、处理 `recipe-data` / `dead-video` issue、补全缺失字段、按评测结果优化筛选,跑校验,最后开一个 PR。它不绑定模型,Codex、Claude Code 或接了 DeepSeek 的 Agent 都能跑,在本地按计划执行即可,见下方「本地定时运行」。
|
||
5. **按主题补充**:`recipe-sourcing` skill(`skills/recipe-sourcing/SKILL.md`)描述了从 B 站、小红书等平台按主题搜罗菜谱的流程:网页搜索找 BV 号、逐个打开视频页核对、按数据规则追加并开 PR。
|
||
6. **合并发布**:维护者审核 PR,合并后照常构建发布,`Closes #n` 自动关闭 issue。
|
||
|
||
### 本地定时运行
|
||
|
||
skill 通过软链接暴露给不同 Agent:`.agents/skills/`(Codex)、`.claude/skills/`(Claude Code)、`.codebuddy/skills/`。需要本机装好并登录 `gh`。
|
||
|
||
```bash
|
||
# Codex
|
||
codex exec --full-auto "使用 recipe-data-review skill 做一次菜谱数据审查"
|
||
|
||
# DeepSeek:用支持自定义 API 地址的 Agent(如 Claude Code 按 DeepSeek 文档配置 ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN)
|
||
claude -p "使用 recipe-data-review skill 做一次菜谱数据审查" --permission-mode acceptEdits
|
||
```
|
||
|
||
每周跑一次即可,例如 crontab(周一 21:00,放在每周视频巡检之后):
|
||
|
||
```cron
|
||
0 21 * * 1 cd ~/repos/cook && codex exec --full-auto "使用 recipe-data-review skill 做一次菜谱数据审查" >> ~/.cook-review.log 2>&1
|
||
```
|
||
|
||
Agent 只开 PR,不合并;没有改动时不开 PR。
|
||
|
||
### 拉取反馈与筛选评测
|
||
|
||
```bash
|
||
pnpm feedback:pull # 汇总到 .cook/feedback/summary.md,并更新 test/fixtures/search-eval.json
|
||
pnpm eval:search # 用真实信号评估当前排序:前 10 命中率、MRR、仍无结果的组合
|
||
```
|
||
|
||
`test/fixtures/search-eval.json` 是匿名聚合后的评测样例,会提交到仓库。AI 修改 `packages/data/aliases.json`(别名)或 `recommend.ts`(排序)时,必须在 PR 中写明修改前后的 `pnpm eval:search --json` 指标,且 `pnpm test` 通过。
|
||
|
||
### Web 和 iOS 共用的推荐用例
|
||
|
||
`packages/data/fixtures/recommend.json` 记录了一组筛选条件和当前推荐逻辑给出的结果(菜谱 id、顺序和缺少的食材)。Web 的 `test/fixtures.test.ts` 和 iOS 的 CookCore 都要和它完全一致。
|
||
|
||
改了 `recipe.csv`、`aliases.json` 或推荐逻辑后运行 `pnpm fixtures` 重新生成,并在 PR 里看结果的变化是否符合预期;忘了运行时 `pnpm test` 会失败。用例的输入在 `scripts/lib/fixtures.ts`。
|
||
|
||
### CloudBase 配置(一次性)
|
||
|
||
1. 在 CloudBase 控制台新建三个集合,权限都设为「仅管理端可读写」:`cook_recipe_feedback`、`cook_search_signals`、`cook_feedback_quota`。
|
||
2. 部署云函数:`tcb fn deploy cook-feedback`(配置见 `cloudbaserc.json`)。
|
||
3. 给 `cook-feedback` 设置环境变量 `COOK_FEEDBACK_EXPORT_TOKEN`(一串足够长的随机字符),并开启 HTTP 访问服务,得到一个访问地址。
|
||
4. 让未登录用户也能调用 `cook-feedback`:在控制台开启匿名登录或允许未登录访问该函数。站点本身没有登录功能,前端也不携带任何账号信息,所以这一项是必需的。
|
||
5. 本机 `.env` 填 `COOK_FEEDBACK_URL`(第 3 步的地址)和 `COOK_FEEDBACK_TOKEN`(同一个口令),之后就能 `pnpm feedback:pull`。
|
||
|
||
云函数对每个设备(或账号)每天最多接受 200 次提交;同一个人对同一道菜的同一类问题每天只记一次。
|
||
|
||
## 性能
|
||
|
||
筛选目前在内存里对全部菜谱逐条计算(`apps/web/app/composables/store/recipe.ts`),600 条约 1ms,上万条之内都不是瓶颈;首次加载在超过 1000 条后自动分片并按 hash 增量更新。数据量明显变大时,优先在 `convert` 阶段生成「食材 → 菜谱 id」倒排索引。
|