feat: 配置列表分页与钉钉机器人分钟级排队限流

统一 sources/templates/channels/rules 列表为分页响应,避免配置增多时全量返回;按钉钉 access_token 限制每分钟发送并在超限时等待下一分钟,降低触发官方封禁风险。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-10 00:34:26 +08:00
parent 009694fee7
commit 39f3774940
27 changed files with 1447 additions and 60 deletions
@@ -0,0 +1,119 @@
# Remote E2E Notify Flow Test Design
**Date:** 2026-08-01
**Status:** Approved (pending final user review of this doc)
## Goal
Add a Go end-to-end test that hits a **deployed** notification service over HTTP and exercises the full configuration → send path:
`source → channel(s) → template → rule → POST /notify`
Channels under test: **DingTalk**, **Bark**, **Email**. Real notifications are sent.
## Non-goals
- Local `httptest` / in-process server tests
- Mocking `ChannelSender`
- CI by default (opt-in via build tag + env vars)
- Committing secrets to the repo
## Placement
| Item | Path |
|------|------|
| Test | `test/e2e/notify_flow_test.go` |
| Build tag | `//go:build e2e` |
| Make target | `test-e2e` (optional helper) |
Default `make test` / `go test ./internal/...` must **not** run this suite.
## Target environment
| Setting | Default / source |
|---------|------------------|
| Base URL | `E2E_BASE_URL` → default `http://82.157.251.93:8080` |
| Admin auth | `E2E_ADMIN_KEY` → default `admin-sk-change-me` |
## Required env vars (channels)
If any of these are missing, the test **Skips** (does not fail):
| Variable | Purpose |
|----------|---------|
| `E2E_DINGTALK_WEBHOOK` | DingTalk robot webhook URL |
| `E2E_DINGTALK_SECRET` | DingTalk sign secret |
| `E2E_BARK_URL` | Bark base URL, e.g. `https://api.day.app/<device_key>` |
| `E2E_EMAIL_TO` | Email recipient |
Secrets live only in the runner environment / local shell, never in source or this spec.
## Flow
Resource names use a unique suffix (unix timestamp or random) to avoid collisions, e.g. `e2e-src-<suffix>`.
1. **Create Source**`POST /api/v1/sources`
- `parse_mode: json`, `status: 1`
- Capture `id`, `api_key`, `name`
2. **Create Channels**`POST /api/v1/channels` ×3
- DingTalk: `type=dingtalk`, config `{webhook_url, secret}`
- Bark: `type=bark`, config `{url}`
- Email: `type=email`, config `{to: [E2E_EMAIL_TO]}`
- All `status: 1`
3. **Create Template**`POST /api/v1/templates`
- Content includes `{{.symbol}}` and `{{.price}}`
4. **Create Rule**`POST /api/v1/rules`
- `source_name` / `template_name` / `channels` by name
- `event: trade.open`
- `enabled: 1`
- Conditions: `symbol` exists AND `price` gt `0`
5. **Notify**`POST /api/v1/notify`
- `Authorization: Bearer <source.api_key>`
- Body: `{"event":"trade.open","data":{"symbol":"BTC","price":65000}}`
6. **Assert notify response**
- `matched == true`
- `accepted == true`
- `channels` length == 3
7. **Message-log check**
- Poll `GET /api/v1/message-logs?source=...&event=trade.open` for up to ~15s
- Assert at least one log entry appears (fail if none within timeout)
8. **Cleanup** via `t.Cleanup` (reverse order)
- Delete rule → template → channels → source
- Cleanup errors: log only, do not fail the test after a successful assertion path
## Run command
```bash
E2E_DINGTALK_WEBHOOK='...' \
E2E_DINGTALK_SECRET='...' \
E2E_BARK_URL='https://api.day.app/<device_key>' \
E2E_EMAIL_TO='149516886@qq.com' \
go test -tags e2e ./test/e2e/ -v -count=1 -timeout 2m
```
Optional Makefile:
```make
test-e2e:
go test -tags e2e ./test/e2e/ -v -count=1 -timeout 2m
```
## Implementation notes
- Use `net/http` + `encoding/json` (stdlib); no new test deps required.
- Helper for admin JSON requests and source-authed notify.
- Failures must include HTTP status + response body for debugging.
- Do not hardcode channel secrets in the test file.
## Success criteria
- With env vars set and remote healthy: test passes; DingTalk, Bark, and Email receive a message.
- Without channel env vars: test skips cleanly.
- Without `-tags e2e`: suite is not compiled/run.