152 lines
5.8 KiB
Markdown
152 lines
5.8 KiB
Markdown
# 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` -> `sent` 或 `failed`
|
||
|
||
### 触发流程
|
||
1. 用户创建/更新任务 -> 生成 `next_due_at`
|
||
2. 生成通知实例:`trigger_at = due_at - offset`
|
||
3. Worker 扫描 `trigger_at <= now` 且 `status = 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...
|
||
}
|
||
}
|
||
```
|