更新说明
This commit is contained in:
301
README.md
301
README.md
@@ -1,17 +1,160 @@
|
||||
# Simple Todo API (Monolith)
|
||||
# SuperTodo 任务与通知系统
|
||||
|
||||
This project is a single backend service built with Gin.
|
||||
The `iam/` directory is kept as a separate scaffold module and is not part of the monolith build.
|
||||
`SuperTodo` 是一个基于 `Gin + PostgreSQL + Redis + Kafka + Vue` 的任务管理与定时通知系统。
|
||||
当前系统不仅支持基础的任务创建、编辑、完成,还支持通知偏好、通知组、到期提醒、过期提醒、每日摘要、重试与死信队列。
|
||||
|
||||
## Run
|
||||
## 项目概览
|
||||
|
||||
系统当前由以下几部分组成:
|
||||
|
||||
- 后端 API:`Go + Gin`
|
||||
- 前端页面:`Vue 3 + Vite`
|
||||
- 关系型存储:`PostgreSQL`
|
||||
- 会话与缓存:`Redis`
|
||||
- 消息中间件:`Kafka`
|
||||
- 邮件投递:`SMTP`
|
||||
|
||||
核心能力包括:
|
||||
|
||||
- 用户注册、登录、刷新令牌、会话管理
|
||||
- 任务 CRUD
|
||||
- 用户通知偏好管理
|
||||
- 通知组管理
|
||||
- 任务创建、状态变化、即将到期、已过期等事件通知
|
||||
- 定时调度、异步投递、失败重试、DLQ 死信记录
|
||||
|
||||
## 消息中间件说明
|
||||
|
||||
本项目中的消息中间件主要使用 `Kafka`,它不是装饰性组件,而是通知系统可靠性的核心。
|
||||
|
||||
### 为什么要引入消息中间件
|
||||
|
||||
如果任务到期、任务状态变化这类业务事件直接在 HTTP 请求里同步发邮件,会有几个明显问题:
|
||||
|
||||
- 接口响应时间变长,用户操作会被外部邮件服务拖慢
|
||||
- 邮件服务短暂失败时,业务请求容易被连带失败
|
||||
- 突发高峰时,大量通知会集中压垮投递链路
|
||||
- 难以实现统一重试、削峰、幂等和死信补偿
|
||||
|
||||
引入 Kafka 后,系统会把“业务处理”和“通知投递”拆成两个阶段:
|
||||
|
||||
1. 业务接口先落库并生成通知事件 / 通知任务
|
||||
2. 通知任务进入 Kafka topic,由后台 worker 异步消费并发送邮件
|
||||
|
||||
这样做的结果是:
|
||||
|
||||
- API 更快返回
|
||||
- 投递链路与业务链路解耦
|
||||
- 可以按批次消费,避免瞬时洪峰
|
||||
- 可以做失败重试与死信记录
|
||||
- 可以通过幂等键避免重复发送
|
||||
|
||||
### 本项目里的 Kafka 角色
|
||||
|
||||
当前用到的 topic 主要有两个:
|
||||
|
||||
- `todo.tasks`
|
||||
- 用于任务事件输出
|
||||
- `notification.jobs`
|
||||
- 用于通知任务分发
|
||||
|
||||
通知相关链路如下:
|
||||
|
||||
1. 用户创建任务或更新任务
|
||||
2. 系统写入 `notification_events`
|
||||
3. 规则引擎根据事件类型、通知组、用户偏好生成 `notification_jobs`
|
||||
4. dispatcher 将可投递任务写入 `notification.jobs`
|
||||
5. worker 消费消息并发送邮件
|
||||
6. 发送成功写回 `sent`
|
||||
7. 临时失败回到 `pending` 并按指数退避重试
|
||||
8. 超过重试次数或不可重试错误进入 `notification_dlq`
|
||||
|
||||
### 当前可靠性机制
|
||||
|
||||
通知系统当前已经实现:
|
||||
|
||||
- 幂等控制:同一事件不会重复生成相同通知任务
|
||||
- 扫描去重:同一 `task_id + event_type + due_at` 不会被调度器反复重发
|
||||
- 重试机制:失败任务按退避策略重新投递
|
||||
- 死信队列:无法恢复的任务进入 DLQ
|
||||
- 状态可观测:支持查看 `pending / sent / dead`
|
||||
|
||||
## 系统架构
|
||||
|
||||
### 后端模块
|
||||
|
||||
- `cmd/server`
|
||||
- HTTP 服务入口
|
||||
- `internal/iam`
|
||||
- 登录认证、令牌、会话管理
|
||||
- `internal/notification`
|
||||
- 通知偏好、通知组、调度器、Kafka dispatcher、worker、SMTP 发送、DLQ 与指标
|
||||
|
||||
### 前端模块
|
||||
|
||||
- `web/src/views/TodoView.vue`
|
||||
- 任务列表与编辑
|
||||
- `web/src/views/UserSettingsView.vue`
|
||||
- 通知偏好设置
|
||||
- `web/src/views/NotificationGroupsView.vue`
|
||||
- 通知组管理
|
||||
- `web/src/views/NotificationDlqView.vue`
|
||||
- 死信查看
|
||||
|
||||
## 运行方式
|
||||
|
||||
### 方式一:Docker Compose 启动整套系统
|
||||
|
||||
推荐本地联调直接使用容器。
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
启动后默认端口:
|
||||
|
||||
- API:`http://localhost:8080`
|
||||
- Kafka UI:`http://localhost:8081`
|
||||
- PostgreSQL:`localhost:5432`
|
||||
- Redis:`localhost:6379`
|
||||
- Kafka:`localhost:29092`
|
||||
|
||||
健康检查:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/health
|
||||
```
|
||||
|
||||
### 方式二:本机运行后端
|
||||
|
||||
如果你已经单独启动了 PostgreSQL、Redis、Kafka,也可以直接运行后端:
|
||||
|
||||
```bash
|
||||
go run ./cmd/server
|
||||
```
|
||||
|
||||
The server listens on `:8080`.
|
||||
常用环境变量:
|
||||
|
||||
## Frontend
|
||||
```bash
|
||||
DATABASE_URL=postgres://todo:todo@localhost:5432/todo?sslmode=disable
|
||||
REDIS_ADDR=localhost:6379
|
||||
KAFKA_BROKERS=localhost:29092
|
||||
KAFKA_TOPIC=todo.tasks
|
||||
NOTIFY_ENABLED=true
|
||||
NOTIFY_TOPIC=notification.jobs
|
||||
NOTIFY_DISPATCH_BATCH=200
|
||||
NOTIFY_SCHED_TICK_SECONDS=60
|
||||
NOTIFY_MAX_RETRY=5
|
||||
NOTIFY_BACKOFF_BASE_SECONDS=30
|
||||
SMTP_HOST=smtp.qq.com
|
||||
SMTP_PORT=465
|
||||
SMTP_USER=your_mail@example.com
|
||||
SMTP_PASS=your_smtp_password
|
||||
SMTP_FROM=your_mail@example.com
|
||||
SMTP_USE_TLS=true
|
||||
```
|
||||
|
||||
## 前端运行
|
||||
|
||||
```bash
|
||||
cd web
|
||||
@@ -19,32 +162,142 @@ npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The Vue app calls `http://localhost:8080/api/v1` by default.
|
||||
默认访问地址:
|
||||
|
||||
## Quick Demo
|
||||
- 前端开发服务:通常为 `http://localhost:5173`
|
||||
- 前端请求后端 API:`http://localhost:8080/api/v1`
|
||||
|
||||
## 主要数据流
|
||||
|
||||
通知系统的数据流可以概括为:
|
||||
|
||||
1. 业务事件产生
|
||||
- 如任务创建、任务状态变化、任务即将到期、任务已过期
|
||||
2. 事件入库
|
||||
- 写入 `notification_events`
|
||||
3. 规则判断
|
||||
- 判断是否需要通知、通知谁、使用哪个模板
|
||||
4. 偏好过滤
|
||||
- 过滤订阅状态、语言、时区、免打扰时间
|
||||
5. 生成通知任务
|
||||
- 写入 `notification_jobs`
|
||||
6. 分发到 Kafka
|
||||
- 写入 `notification.jobs`
|
||||
7. worker 消费并发送邮件
|
||||
8. 回写状态
|
||||
- `sent / pending / dead`
|
||||
9. 失败补偿
|
||||
- 重试或进入 DLQ
|
||||
|
||||
## 常用接口
|
||||
|
||||
### 认证
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/health
|
||||
|
||||
curl -X POST http://localhost:8080/api/v1/auth/register \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"email":"demo@example.com","password":"secret123"}'
|
||||
-d '{"email":"demo@example.com","password":"secret123","auto_login":true}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/auth/login \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"email":"demo@example.com","password":"secret123"}'
|
||||
|
||||
curl -X POST http://localhost:8080/api/v1/tasks \
|
||||
-H 'Authorization: Bearer demo' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"title":"Learn Gin","priority":1,"tags":["demo"]}'
|
||||
|
||||
curl http://localhost:8080/api/v1/tasks \
|
||||
-H 'Authorization: Bearer demo'
|
||||
```
|
||||
|
||||
## Notes
|
||||
- Tasks and users are stored in PostgreSQL.
|
||||
- Auth uses HMAC-signed bearer tokens with TTL (default 24h).
|
||||
- Redis token cache is optional (`REDIS_ADDR` not set means disabled).
|
||||
- Kafka task event emit is optional (`KAFKA_BROKERS` not set means disabled).
|
||||
### 任务
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/tasks \
|
||||
-H 'Authorization: Bearer <token>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"title":"学习通知系统",
|
||||
"description":"验证 Kafka 通知链路",
|
||||
"status":"todo",
|
||||
"due_at":"2026-03-10T15:30:00Z",
|
||||
"priority":1,
|
||||
"tags":["demo","notify"],
|
||||
"notify_group_ids":[1]
|
||||
}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/tasks \
|
||||
-H 'Authorization: Bearer <token>'
|
||||
```
|
||||
|
||||
### 通知偏好
|
||||
|
||||
```bash
|
||||
curl -X PUT http://localhost:8080/api/v1/notifications/prefs \
|
||||
-H 'Authorization: Bearer <token>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"subscribed":true,
|
||||
"dnd_start":"",
|
||||
"dnd_end":"",
|
||||
"locale":"zh",
|
||||
"timezone":"Asia/Shanghai",
|
||||
"daily_summary_enabled":true,
|
||||
"daily_summary_time":"09:30"
|
||||
}'
|
||||
```
|
||||
|
||||
### 通知组
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/v1/notifications/groups \
|
||||
-H 'Authorization: Bearer <token>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"name":"项目通知组",
|
||||
"emails":["a@example.com","b@example.com"]
|
||||
}'
|
||||
```
|
||||
|
||||
### 通知指标
|
||||
|
||||
```bash
|
||||
curl http://localhost:8080/api/v1/notifications/metrics \
|
||||
-H 'Authorization: Bearer <token>'
|
||||
```
|
||||
|
||||
## 数据表说明
|
||||
|
||||
当前通知系统的关键表包括:
|
||||
|
||||
- `tasks`
|
||||
- 任务主体,包含 `notify_group_ids`
|
||||
- `user_notification_prefs`
|
||||
- 用户通知偏好
|
||||
- `notification_groups`
|
||||
- 通知组
|
||||
- `task_notification_groups`
|
||||
- 任务与通知组关系
|
||||
- `notification_events`
|
||||
- 通知事件日志
|
||||
- `notification_jobs`
|
||||
- 通知任务队列
|
||||
- `notification_attempts`
|
||||
- 每次投递尝试记录
|
||||
- `notification_dlq`
|
||||
- 死信记录
|
||||
|
||||
## 开发说明
|
||||
|
||||
### 关于 `web/dist`
|
||||
|
||||
`web/dist/` 已从 Git 移除,并加入 `.gitignore`。
|
||||
前端构建产物不再直接提交到仓库。
|
||||
|
||||
### 关于通知重复发送
|
||||
|
||||
当前代码已经修复“过期任务在每次扫描中重复重发”的问题。
|
||||
调度器会基于 `task_id + event_type + due_at` 做去重,同一条到期版本只会生成一次对应事件。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [通知系统说明](./doc/notify.md)
|
||||
- [认证模块说明](./doc/iam.md)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user