耗费两千积分做了个家常菜谱 Recipe Hub

家常菜谱 Recipe Hub · 项目速览

Recipe Hub.png

碎碎念

这个项目纯纯靠Workbuddy参考各个开源的菜谱程序,像是现有的开源菜谱程序,很多功能并不适配中文环境,用着总是别扭,这个项目前后靠AI打磨了二十多天,基本上该做的功能都有了,可以自定义每日菜谱推送给机器人,如果有bug或者想增加功能,可以自己克隆源码,也可以在项目页提交相关。
这里主推Docker部署,已经上传Docker Hub,可以直接下载,部署只需要配置端口和存储路径。

演示站点:https://caipu.dawnlife.qzz.io/
项目地址:https://github.com/xyzbz/recipe-hub

当前版本 1.1.3。自托管的中餐菜谱系统:菜谱 → 库存 → 周计划 → 采购清单,一条链闭环。

仓库形态PHP 源码,无构建步骤,拷过去就能跑
官方镜像xyzbz/recipe-hub:1.1.3(也带 latest)
参考线上https://caipu.dawnlife.qzz.io/
详细文档功能细节看 README.md,部署三步看 DEPLOY.md

1. 技术线

层选型说明
后端PHP 8.2+(镜像内 8.3)无框架、无 Composer 依赖,手写路由 + PSR-4 风格自动加载(src/,命名空间 RH\)
数据库SQLite(WAL)单文件 data/recipe.sqlite,无外部数据库服务;结构变更走幂等迁移(PRAGMA user_version,现 v3)
前端原生 ES module + hash 路由无打包器、无 npm install,改完刷新即生效;路由形如 #/recipes/12,部署到任何路径都不用配服务端重写
接口自写 JSON APIpublic/index.php 单入口分发;写请求走 CSRF 双提交(Cookie + X-CSRF-Token)
图片一律转 WebPgd 缩放 + 出缩略图,exif 纠正手机竖拍方向;存在 docroot 之外,经 /uploads/… 由 PHP 带权限流式输出
容器php:8.3-apache单容器,编译进 gd(freetype/jpeg/webp)与 exif,开 rewrite/headers/expires/deflate

2. 功能

模块要点
菜谱库中餐单位(克/斤/两/勺/瓣/把)、份数缩放(模糊量「少许」不参与计算)、中文搜索、公开/私有、回收站、打印贴冰箱、家人留言、下厨记录、随机「今天吃什么」
食材与库存预置食材库带别名(生抽=酱油=豉油)、冷藏/冷冻/常温/干货柜、过期提醒、按现有食材倒推能做什么菜
膳食周计划拖拽排一周三餐、一键换菜、整周模板、指定时段一键转采购清单
采购清单同名食材跨菜谱自动相加、按买菜动线分组、勾选已买、买回一键入库
定时推送企业微信 / PushPlus / Server酱 / WxPusher / 自定义 Webhook(飞书·钉钉·Telegram),到点推「今天吃什么」
权限与安全管理员 / 读写 / 只读三档、可选游客浏览、登录失败锁定、password_hash 加盐、会话在库里、CSRF 双提交
备份恢复只有一个入口:后台「备份」。一键产整站 zip(数据库 + 全部图片),恢复时先体检再铺图换库,换库前自动留 before-restore-* 快照
迁移自家 JSON 导入导出;cli/import-mealie.php 从 Mealie 整站迁移(含图片)
其它深色模式、从 URL 导入未做、只做 Web(手机浏览器移动优先,可添加到主屏幕当 PWA 用)

3. 部署环境要求(两条路线通用)

项目要求
PHP8.2 及以上(8.3 已验证;8.1 未测)
必需扩展pdo_sqlite、sqlite3、mbstring、fileinfo、session、json
图片扩展gd(需 WebP + JPEG + PNG + FreeType)、exif —— 缺了图片功能残废
数据库无(SQLite 自带驱动)
Web 服务Apache(需 mod_rewrite)或 Nginx
目录权限data/、data/uploads/、data/backups/ 必须可写
定时任务可选,只有「膳食计划定时推送」需要(每分钟跑一次)
资源占用极低;镜像约 500 MB,运行内存几十 MB 起步

Web 根目录必须指向 public/ —— src/ 和 data/ 在上一级,绝不能被直接访问。

健康检查:访问 /healthz,正常返回 {"ok":true,"version":"1.1.3","time":"…"}。
版本以 bootstrap.php 里的 RH_VERSION 为准,各处版本号统一从它读取。


4. Docker 部署

最小 compose

services:
  recipe-hub:
    image: xyzbz/recipe-hub:1.1.3
    container_name: recipe-hub
    restart: unless-stopped
    ports:
      - "8080:80"                       # 左宿主 / 右容器(容器内固定 80)
    volumes:
      - ./data:/var/www/html/data       # 全部家当:数据库 + 图片 + 备份
    environment:
      TZ: Asia/Shanghai
      RH_SITE_URL: https://eat.example.com
docker compose up -d          # 起来
docker compose pull && docker compose up -d   # 升级(数据在卷里,不受影响)
docker compose logs -f        # 看日志

浏览器打开 http://服务器IP:8080,走安装向导建管理员账号。

项值为什么
端口容器 80 → 宿主 8080宿主端口随意改
数据卷/var/www/html/data必须挂出来,不挂容器一删数据就没
站点地址RH_SITE_URL不填推送会降级成纯文本(拼不出菜谱链接)
反代传 X-Forwarded-ProtoPHP 靠它判断原始协议,决定 Cookie 是否加 Secure

发表评论