Subflare 是一个运行在 Cloudflare Workers 上的订阅到期提醒管理应用,基于 Next.js 16, vinext, shadcn-ui和 Drizzle ORM 构建
它用于集中管理各类订阅项目,跟踪到期时间、记录续费历史,并通过可扩展的通知渠道发送到期提醒
(其实我还写了个基于Opennext的版本, 但是它的getCloudflareContext 函数貌似有点问题, 导致cron任务获取DB时会报错, 折腾了好久都不行就暂时把仓库private了, 等后续Opennext修复了再open出来)
| 新增订阅 | 订阅续费历史 |
|---|---|
![]() |
![]() |
适合已经 fork 到自己 GitHub 仓库, 希望在 push 后自动部署到 Cloudflare Workers 的场景
先在 Cloudflare 中创建以下资源, 并记下对应 id:
- D1 数据库 id
- KV Namespace id
- Cloudflare Account ID
- Cloudflare API Token
其中 API Token 需要至少具备 Workers、D1、KV 的相关权限, 用于 GitHub Action 执行部署
推荐在创建API Token时选择worker模板, 然后再在模板中添加权限: D1, 编辑
fork代码后点击仓库顶部的Actions, 选择开启action
打开仓库 Settings -> Secrets and variables -> Actions, 新增以下 Repository secrets:
CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_IDD1_IDKV_ID
.github/workflows/deploy.yml 会在运行时读取这些 secrets, 并调用 scripts/fill-wrangler-placeholders.sh 把它们填充到部署配置里
- 在初次fork仓库后请在action页面下选择
Deploy to Cloudflare, 手动点击Run workflow完成初次部署 (重要!!!) - 后续使用GitHub 的sync fork 后自动部署新代码
部署完成后, 建议到 GitHub Actions 查看日志, 确认 deploy 步骤成功;再到 Cloudflare Dashboard 中检查 Worker 是否已更新
进到worker项目后台添加一下变量
USERNAMEPASSWORD
git clone https://github.com/Merack/subflare-vinext.git
cd subflare
pnpm install
进到Cloudflare 面板中(https://dash.cloudflare.com/), 在左侧菜单中找到KV和D1模块, 新建后记下实例id
(i) wrangler.jsonc主要修改以下字段:
- d1_databases
- kv_namespaces
(ii) 将.env.development.example 改名为 .env.development并按注释完善值
pnpm drizzle-kit push
或
pnpm drizzle-kit migrate
pnpm deploy首次deploy可能要求进行登录验证
找到部署的Cloudflare Worker, 在设置页里设置变量和机密:
- USERNAME
- PASSWORD
- 订阅管理:新增、编辑、删除订阅项目
- 到期提醒:按提前天数和提醒模式发送通知
- 多时段通知:支持按时区配置多个通知时段
- 自动续费处理:订阅到期后可自动推进下一周期并记录历史
- 汇总视图:提供多维度汇总数据, 多国货币汇率自动转换, 年月统计视图切换等
- 通知渠道扩展:通知渠道架构设计为可扩展
- Cloudflare 强力驱动:面向 Cloudflare Workers 运行环境设计
- Next.js 16(App Router)
- React 19
- Vinext
- Cloudflare Workers
- Cloudflare D1
- Cloudflare KV
- Drizzle ORM
- Tailwind CSS v4
- shadcn/ui
src/
├─ app/ # 页面与 API Route
│ ├─ api/ # 登录、订阅、设置、通知渠道等接口
│ ├─ dashboard/ # 仪表盘页面
│ ├─ subscriptions/ # 订阅管理页面
│ ├─ settings/ # 设置页面
│ └─ login/ # 登录页
├─ components/ # 页面客户端组件与通用 UI 组件
├─ db/ # D1 数据库入口与 Drizzle Schema
├─ lib/
│ ├─ notifications/ # 通知策略、注册表、描述符、分发器
│ ├─ cron.ts # 到期提醒定时任务
│ ├─ session.ts # 基于 KV 的会话逻辑
│ ├─ dashboard.ts # 仪表盘统计逻辑
│ └─ subscription-utils.ts# 订阅周期相关工具
├─ worker.ts # Cloudflare Worker 入口
└─ proxy.ts # Middleware
drizzle/ # Drizzle 生成的 SQL 迁移文件
public/ # 静态资源
wrangler.jsonc # Cloudflare Workers 配置
drizzle.config.ts # Drizzle 远程 D1 配置
- Telegram: @botfather
- webhook
- wecombot(企业微信机器人): https://developer.work.weixin.qq.com
- bark: https://bark.day.app
- notifyx: https://www.notifyx.cn/help
- resend: https://resend.com
- smtp
贡献通知渠道: new_channel.md
pnpm install将以下示例文件重命名后再填写内容:
.env.development.example→.env.development.dev.vars.example→.dev.vars
其中:
.env.development主要用于drizzle.config.ts读取 Cloudflare 远程 D1 信息.dev.vars用于本地运行时变量
先按sql文件名前缀数字顺序执行 drizzle/ 目录中的 SQL 文件到本地 D1, 如:
pnpm wrangler d1 execute DB --local --file=drizzle/0000_supreme_mister_fear.sql
pnpm wrangler d1 execute DB --local --file=drizzle/0001_broken_spyke.sql如果后续新增了新的 SQL 文件,也需要继续按文件顺序执行
pnpm dev当你修改 src/db/schema.ts 后,可以先生成新的 SQL:
pnpm drizzle-kit generate这一步只会生成 drizzle/ 下的 SQL 文件,不会自动把变更应用到本地数据库
对本地模拟 D1 生效时,应执行:
pnpm wrangler d1 execute DB --local --file=drizzle/<sql_file_name>.sql例如:
pnpm wrangler d1 execute DB --local --file=drizzle/0002_xxx.sql远程数据库可以使用以下方式之一:
- 使用
pnpm drizzle-kit push或者pnpm drizzle-kit migrate将 schema 变更推送到远程数据库(推荐) - 打开 Cloudflare Dashboard 的 D1 控制台,按顺序执行这些 SQL
- 使用 Wrangler 逐个执行
drizzle/中的 SQL 文件
pnpm drizzle-kit generate:只生成 SQLpnpm drizzle-kit migrate/pnpm drizzle-kit push:不要把它们当成本地 D1 初始化命令- 本地开发数据库变更请使用
pnpm wrangler d1 execute DB --local --file=...
pnpm dev # 本地开发
pnpm build # Next.js 构建
pnpm preview # 构建后在本地以 Cloudflare 运行时预览
pnpm deploy # 构建并部署到 Cloudflare Workers
pnpm upload # 构建并上传
pnpm cf-typegen # 生成 Cloudflare 环境类型示例代码详见: new_channel.md
- 在本地开发环境下smtp无法正常解析smtp host, 还不清楚什么原因, 如果要对smtp进行相关开发, 请部署到worker环境上验证
- 登录会话基于 Cloudflare KV 实现
- 当前项目按单用户场景设计
src/lib/session.ts中将用户固定为单用户上下文处理
- 后端API错误提示
- 农历
- 数据备份
- 订阅排序模式
- ISR缓存优化
- 消息发送历史查询
- 自定义发送信息文本
- 数据库清理(消息发送记录表, 清除过期>一定时间范围的订阅)
Claude, ChatGPT
- OpenNext for Cloudflare: https://opennext.js.org/cloudflare
- Vinext: https://github.com/cloudflare/vinext
- Next.js: https://nextjs.org
- Cloudflare Workers: https://developers.cloudflare.com/workers/
- Cloudflare D1: https://developers.cloudflare.com/d1/
- Drizzle ORM: https://orm.drizzle.team/





