Files
notify/docs/spec.md
Michael Dong a98e12f286 first commit
2026-02-05 11:24:40 +08:00

5.8 KiB
Raw Blame History

Notify 产品与技术规格

目标与定位

  • 目标:打造简洁明了、同时适配桌面与移动浏览器的提醒应用。
  • 核心能力Todo 与多用户提醒、周期性规则、提前提醒、网页通知 + Bark 推送。

需求澄清后的产品规格

核心对象

  • Todo:个人待办,支持单次与周期性,配置一个或多个提醒策略。
  • 提醒任务:可指定多个接收者(含自己),支持单次与周期性,提醒策略与触达方式同 Todo。
  • 通知:一次提醒事件在“某接收者”维度的投递记录,支持站内与 Bark 两种渠道。
  • 邀请码:仅邀请码注册,所有用户可生成/管理邀请码。

业务规则与边界条件

  1. 周期性任务的下一次触发时间
    • 使用 用户时区(默认 Asia/Shanghai 可配置)。
    • 规则类型:hourly | daily | weekly | monthly | yearly
    • 计算方式:以“本次 dueAt”为基准按规则添加时间并做 日历对齐
      • hourly: dueAt + n hours
      • daily: dueAt + n days(保持时分)
      • weekly: dueAt + n weeks(保持星期与时分)
      • monthly: 若下月无对应日期,则取 该月最后一天 同时分
      • yearly: 若跨闰年导致日期不存在,取 当年同月最后一天 同时分
  2. 多提醒策略
    • 每个任务可配置多条提前量(如 10 分钟、1 小时)。
    • 对每条提前量生成独立触发点:triggerAt = dueAt - offsetMinutes
  3. 浏览器不在线
    • 服务端仍生成通知记录(状态 pending/queued/sent)。
    • 用户上线后,客户端拉取未读站内通知并展示(通知中心 + 弹窗)。
  4. Bark 推送失败/重试
    • 失败进入重试队列指数退避1m/5m/15m/1h
    • 最多重试 5 次,超出后标记 failed
    • 幂等:同一通知记录仅允许一次成功发送。
  5. 多用户提醒
    • 每个接收者创建独立通知记录(便于去重与投递状态追踪)。
  6. 邀请码策略(默认方案)
    • 每个邀请码 可用次数 = 5
    • 有效期 = 7 天,可撤销。
    • 邀请码可由任意已注册用户生成与管理。

数据模型(关系型)

核心表

  • users: 用户
  • invites: 邀请码
  • todos: 个人待办
  • reminder_tasks: 多用户提醒任务
  • recurrence_rules: 周期规则
  • reminder_offsets: 提前提醒策略
  • notifications: 通知实例(按接收者维度)
  • delivery_logs: 投递日志(站内/Bark

字段示意(详见 schema

  • users(id, username, password_hash, timezone, bark_url, created_at)
  • invites(id, code, creator_id, max_uses, used_count, expires_at, revoked_at)
  • todos(id, owner_id, title, description, due_at, recurrence_rule_id)
  • reminder_tasks(id, creator_id, title, due_at, recurrence_rule_id)
  • reminder_task_recipients(task_id, user_id)
  • recurrence_rules(id, type, interval, by_weekday, by_monthday, timezone)
  • reminder_offsets(id, target_type, target_id, offset_minutes, channel_inapp, channel_bark)
  • notifications(id, recipient_id, target_type, target_id, trigger_at, channel, status)
  • delivery_logs(id, notification_id, attempt_no, channel, status, response_meta)

核心接口设计REST

认证与邀请码

  • POST /api/auth/register { username, password, inviteCode }
  • POST /api/auth/login { username, password } -> JWT
  • POST /api/invites 创建邀请码
  • GET /api/invites 获取邀请码列表
  • POST /api/invites/:id/revoke

Todo

  • GET /api/todos
  • POST /api/todos
  • GET /api/todos/:id
  • PUT /api/todos/:id
  • DELETE /api/todos/:id

多用户提醒任务

  • GET /api/reminder-tasks
  • POST /api/reminder-tasks
  • GET /api/reminder-tasks/:id
  • PUT /api/reminder-tasks/:id
  • DELETE /api/reminder-tasks/:id

用户与设置

  • GET /api/users?query=
  • GET /api/me
  • PUT /api/me/settings { timezone, barkUrl, inappEnabled, barkEnabled }

通知中心

  • GET /api/notifications?status=unread
  • POST /api/notifications/:id/read

Bark 推送设计

调用形式

  • 采用 Bark 官方接口:
    • GET: https://bark.server/push/{title}/{body}?group=notify&icon=...
    • POST: JSON body { title, body, group, icon, url, badge, sound }

发送内容

  • title: 任务标题
  • body: 触发时间 + 备注
  • group: notify
  • 额外参数:url 指向站内通知详情

调度方案(可靠与幂等)

核心思想

  • 通知表 为唯一投递来源(幂等)。
  • 调度器只负责生成通知实例;投递 worker 只发送 pending 通知。

通知状态机

  • pending -> queued -> sentfailed

触发流程

  1. 用户创建/更新任务 -> 生成 next_due_at
  2. 生成通知实例:trigger_at = due_at - offset
  3. Worker 扫描 trigger_at <= nowstatus = pending,锁定并投递
  4. 成功则更新 sent,失败则记录 failed 并按策略重试

关键页面与交互

  1. 登录/注册(邀请码)
    • 注册页要求邀请码与密码确认
  2. Todo 列表
    • 列表 + 新增/编辑弹窗
    • 支持单次/周期选择、提前提醒策略
  3. 提醒任务
    • 支持多接收者选择、搜索用户
  4. 用户列表
    • 全部用户可见,支持搜索
  5. 个人设置
    • Bark 链接、站内通知偏好
  6. 通知中心
    • 未读/历史提醒,点击标记已读

工程结构与实现要点

  • backend/: REST API、调度 worker、Bark 集成
  • frontend/: Next.js UI响应式布局
  • docker-compose.yml: 数据库与服务

示例伪代码

计算下一次触发

function nextDueAt(dueAt, rule) {
  switch (rule.type) {
    case "monthly":
      return addMonthWithClamp(dueAt, rule.interval);
    case "yearly":
      return addYearWithClamp(dueAt, rule.interval);
    // hourly/daily/weekly...
  }
}