# 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... } } ```