Files
wenzi/docs/api.md

816 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API 文档
本文档详细说明了活动管理和API密钥管理相关的API端点。
## 统一响应封装
除图片/HTML/CSV等非 JSON 响应外,所有接口返回 `ApiResponse`
- 成功响应:
```json
{
"code": 200,
"message": "success",
"data": {},
"meta": {
"pagination": {
"page": 0,
"size": 20,
"total": 100,
"totalPages": 5,
"hasNext": true,
"hasPrevious": false
}
},
"timestamp": "2025-09-30T12:34:56",
"traceId": "trace-id"
}
```
- 错误响应:
```json
{
"code": 400,
"message": "请求参数校验失败",
"error": {
"message": "activityId 不能为空",
"details": { "activityId": "must not be null" },
"code": "VALIDATION_ERROR"
},
"timestamp": "2025-09-30T12:34:56",
"traceId": "trace-id"
}
```
## 认证与鉴权
### 认证矩阵
| 路径模式 | 认证方式 | 说明 |
|----------|----------|------|
| `/r/**` | 无需认证 | 短链接跳转 |
| `/actuator/**` | 无需认证 | Spring Boot Actuator |
| `/api/v1/callback/**` | X-API-Key | 第三方回调接口 |
| `/api/v1/share/**` | X-API-Key + Bearer Token | 分享跟踪接口 |
| `/api/v1/me/**` | Bearer Token | 用户中心接口 |
| `/api/v1/activities/**` | Bearer Token | 用户端活动接口 |
| `/api/v1/activities/admin/**` | Bearer Token + 权限校验 | 管理后台活动接口 |
| `/api/v1/rewards/admin/**` | Bearer Token + 权限校验 | 管理后台奖励接口 |
| `/api/v1/roles/**` | Bearer Token + 权限校验 | 角色管理接口 |
| `/api/v1/departments/**` | Bearer Token + 权限校验 | 部门管理接口 |
| `/api/v1/approval/**` | Bearer Token + 权限校验 | 审批中心接口 |
| `/api/v1/users/**` | Bearer Token + 权限校验 | 用户管理接口 |
| `/api/v1/permissions/**` | Bearer Token + 权限校验 | 权限管理接口 |
| `/api/v1/invites/**` | Bearer Token + 权限校验 | 邀请管理接口 |
| `/api/v1/notifications/**` | Bearer Token + 权限校验 | 通知管理接口 |
| `/api/v1/risk/**` | Bearer Token + 权限校验 | 风险管理接口 |
| `/api/v1/audit/**` | Bearer Token + 权限校验 | 审计日志接口 |
| `/api/v1/system/**` | Bearer Token + 权限校验 | 系统管理接口 |
| `/api/v1/dashboard/**` | Bearer Token + 权限校验 | 仪表盘接口 |
| `/api/v1/api-keys/**` | Bearer Token + 权限校验 | API密钥管理接口 |
### 认证示例
**回调接口仅需API Key**
```http
POST /api/v1/callback/register
X-API-Key: a1b2c3d4-e5f6-7890-1234-567890abcdef
Content-Type: application/json
{"trackingId": "track-abc123", "externalUserId": "user456", "timestamp": 1699999999999}
```
**分享跟踪接口需要API Key + Bearer Token**
```http
POST /api/v1/share/track
X-API-Key: a1b2c3d4-e5f6-7890-1234-567890abcdef
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{"activityId": 1, "inviterUserId": "user123", "source": "wechat"}
```
**管理后台接口仅需Bearer Token**
```http
GET /api/v1/activities/admin?page=0&size=20
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
## 错误码
- `VALIDATION_ERROR` → 400请求参数校验失败字段缺失/格式不符)。
- `BAD_REQUEST` → 400业务数据不合法如结束时间早于开始时间、上传文件不支持
- `FORBIDDEN` → 403无权访问资源或操作。
- `NOT_FOUND` → 404资源不存在活动、API密钥等
- `INTERNAL_ERROR` → 500服务器内部错误。
- `INVALID_API_KEY` → 401提供的 API 密钥无效或已吊销。
## 1. 活动管理 (Activities)
### 1.1 创建活动
- **Endpoint**: `POST /api/v1/activities`
- **描述**: 创建一个新的营销活动。
- **请求体**: `application/json`
```json
{
"name": "春季特惠活动",
"startTime": "2025-03-01T10:00:00+08:00",
"endTime": "2025-03-31T23:59:59+08:00"
}
```
- **成功响应 (201 Created)**:
```json
{
"code": 201,
"message": "success",
"data": {
"id": 1,
"name": "春季特惠活动",
"startTime": "2025-03-01T10:00:00+08:00",
"endTime": "2025-03-31T23:59:59+08:00"
},
"timestamp": "2025-03-01T10:00:00"
}
```
- **失败响应**:
- `400 Bad Request`: 如果请求数据无效(例如,名称为空或结束时间早于开始时间)。
### 1.2 更新活动
- **Endpoint**: `PUT /api/v1/activities/{id}`
- **描述**: 更新一个已存在的活动。
- **路径参数**: `id` (long) - 活动的唯一标识符。
- **请求体**: `application/json`
```json
{
"name": "春季特惠活动(升级版)",
"startTime": "2025-03-01T10:00:00+08:00",
"endTime": "2025-04-15T23:59:59+08:00"
}
```
- **成功响应 (200 OK)**: `ApiResponse<Activity>``data` 为更新后的活动对象。
- **失败响应**:
- `400 Bad Request`: 如果请求数据无效。
- `404 Not Found`: 如果指定的 `id` 不存在。
### 1.3 获取活动详情
- **Endpoint**: `GET /api/v1/activities/{id}`
- **描述**: 获取指定ID的活动详情。
- **路径参数**: `id` (long) - 活动的唯一标识符。
- **成功响应 (200 OK)**: `ApiResponse<Activity>``data` 为活动对象。
- **失败响应**:
- `404 Not Found`: 如果指定的 `id` 不存在。
## 2. API密钥管理 (API Keys)
### 2.1 创建API密钥
- **Endpoint**: `POST /api/v1/api-keys`
- **描述**: 为指定的活动创建一个新的API密钥。该操作需要审批密钥创建后会进入审批流程。返回 `pendingId` 用于查询审批状态,`recordId` 用于追踪审批记录。
- **请求体**: `application/json`
```json
{
"activityId": 1,
"name": "我的第一个密钥"
}
```
- **成功响应 (201 Created)**:
```json
{
"code": 201,
"message": "success",
"data": {
"pendingId": 123,
"recordId": 456,
"status": "PENDING",
"activityId": 1,
"name": "我的第一个密钥"
},
"timestamp": "2025-03-01T10:00:00"
}
```
- **响应字段说明**:
- `pendingId`: 待审批的API密钥ID
- `recordId`: 审批记录ID可用于查询审批进度
- `status`: 审批状态 (`PENDING` = 待审批, `APPROVED` = 已通过, `REJECTED` = 已拒绝)
- **失败响应**:
- `400 Bad Request`: 如果请求数据无效(例如,`activityId` 或 `name` 为空)。
- `404 Not Found`: 如果 `activityId` 不存在。
### 2.2 吊销API密钥
- **Endpoint**: `DELETE /api/v1/api-keys/{id}`
- **描述**: 吊销删除一个API密钥。
- **路径参数**: `id` (long) - API密钥的唯一标识符。
- **成功响应 (200 OK)**: `ApiResponse<Void>``data` 为 `null`。
- **失败响应**:
- `404 Not Found`: 如果指定的 `id` 不存在。
### 2.3 使用/校验 API 密钥
- Endpoint: `POST /api/v1/api-keys/{id}/use`
- 描述: 校验提供的明文 API 密钥是否与 `id` 对应的密钥匹配;校验成功将更新 `last_used_at`。
- 请求体: `application/json`
```json
{
"apiKey": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
}
```
- 成功响应 (200 OK): `ApiResponse<Void>``data` 为 `null`。
- 失败响应:
- `401 Unauthorized` + `INVALID_API_KEY`:密钥错误或已吊销。
- `404 Not Found``id` 不存在。
### 2.4 通过前缀校验 API 密钥(无需 ID
- Endpoint: `POST /api/v1/api-keys/validate`
- 描述: 仅凭明文 API 密钥进行校验(服务端使用前缀快速定位候选密钥,再进行哈希校验)。校验成功将更新 `last_used_at`。
- 请求体: `application/json`
```json
{
"apiKey": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
}
```
- 成功响应 (200 OK): `ApiResponse<Void>``data` 为 `null`。
- 失败响应:
- `401 Unauthorized` + `INVALID_API_KEY`:密钥错误或已吊销。
## 3. 缓存管理 (Cache)
### 3.1 清空某类缓存
- Endpoint: `DELETE /api/v1/cache/{cacheName}`
- 描述: 清空指定缓存空间(如 `leaderboards`、`activities`、`activity_stats`、`activity_graph`)。
- 成功响应 (204 No Content)
### 3.2 失效某个缓存键
- Endpoint: `DELETE /api/v1/cache/{cacheName}/{key}`
- 描述: 失效指定缓存空间下的某个键。
- 成功响应 (204 No Content)
## 4. 数据分析 (Analytics)
### 4.1 获取排行榜
- Endpoint: `GET /api/v1/activities/{id}/leaderboard`
- 描述: 返回指定活动的排行榜(已启用缓存 `leaderboards`)。支持分页与 TopN。
- 查询参数:
- `topN` 可选:只取前 N 名(先截断再分页)。
- `page` 可选,默认 `0`:页码(从 0 开始)。
- `size` 可选,默认 `20`:每页条数。
- 成功响应 (200 OK):
```json
{
"code": 200,
"message": "success",
"data": [
{ "userId": 1, "userName": "用户A", "score": 1500 },
{ "userId": 2, "userName": "用户B", "score": 1200 }
],
"meta": {
"pagination": {
"page": 0,
"size": 20,
"total": 2,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false
}
}
}
```
### 4.2 导出排行榜CSV
- Endpoint: `GET /api/v1/activities/{id}/leaderboard/export`
- 描述: 导出排行榜为CSV文件并下载。支持 `topN` 仅导出前 N 名。
- 成功响应 (200 OK): 响应头 `Content-Type: text/csv;charset=UTF-8``Content-Disposition: attachment; filename="leaderboard_{id}.csv"`
- CSV示例:
```csv
userId,userName,score
1,用户A,1500
2,用户B,1200
```
### 4.3 获取裂变网络图
- Endpoint: `GET /api/v1/activities/{id}/graph`
- 描述: 返回指定活动的裂变网络图。支持以某个用户为根、限定层级与结果规模。
- 查询参数:
- `rootUserId` 可选作为根节点的用户ID为空则返回全量图受 `limit` 限制)。
- `maxDepth` 可选,默认 `3`:最大层级深度(从根出发,`1` 表示仅直推)。
- `limit` 可选,默认 `1000`:返回的最大边数(超出将截断)。
- 成功响应 (200 OK):
```json
{
"code": 200,
"message": "success",
"data": {
"nodes": [ { "id": "1", "label": "用户1" } ],
"edges": [ { "from": "1", "to": "2" } ]
}
}
```
### 4.4 获取仪表盘统计
- Endpoint: `GET /api/v1/activities/{id}/stats`
- 描述: 汇总 `daily_activity_stats` 表的数据(已启用缓存 `activity_stats`)。`participants` 对应每日新增注册数聚合。
- 成功响应 (200 OK):
```json
{
"code": 200,
"message": "success",
"data": {
"totalParticipants": 220,
"totalShares": 110,
"dailyStats": [
{ "date": "2025-09-28", "participants": 100, "shares": 50 },
{ "date": "2025-09-29", "participants": 120, "shares": 60 }
]
}
}
```
## 5. 短链接 (Short Links)
### 5.1 生成短链接(内部)
- Endpoint: `POST /api/v1/internal/shorten`
- 描述: 生成短链接记录,仅供内部服务或管理端调用。
- 请求体:
```json
{ "originalUrl": "https://example.com/landing?ref=abc" }
```
- 成功响应 (201 Created):
```json
{
"code": 201,
"message": "success",
"data": { "code": "abc12345", "path": "/r/abc12345", "originalUrl": "https://example.com/landing?ref=abc" }
}
```
### 5.2 短链接重定向(公开)
- Endpoint: `GET /r/{code}`
- 描述: 302 跳转到短链对应的原始地址。
- 成功响应 (302 Found): 响应头 `Location: <originalUrl>`
## 6. 用户端体验 (User Experience)
### 6.1 获取用户专属邀请信息
- Endpoint: `GET /api/v1/me/invitation-info`
- 描述: 返回当前用户的专属短链接(示例以 query 参数的 `activityId`/`userId` 代替鉴权)。
- Query: `activityId`, `userId`
- 成功响应 (200 OK):
```json
{
"code": 200,
"message": "success",
"data": { "code": "inv12345", "path": "/r/inv12345", "originalUrl": "https://example.com/landing?activityId=1&inviter=2" }
}
```
### 6.2 获取邀请好友列表(分页)
- Endpoint: `GET /api/v1/me/invited-friends`
- Query: `activityId`, `userId`, `page`默认0, `size`默认20
- 成功响应 (200 OK):
```json
{
"code": 200,
"message": "success",
"data": [ { "nickname": "用户10", "maskedPhone": "138****0010", "status": "registered" } ],
"meta": {
"pagination": {
"page": 0,
"size": 20,
"total": 1,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false
}
}
}
```
### 6.3 生成海报
- 图片:`GET /api/v1/me/poster/image`
- HTML`GET /api/v1/me/poster/html`
- 配置:`GET /api/v1/me/poster/config`
- Query: `activityId`, `userId`, `template``template` 可选)
- 描述:图片/HTML 端点返回二进制或 HTML配置端点返回 `ApiResponse<PosterConfigDto>``data` 包含 `template`、`imageUrl`、`htmlUrl`。
## 7. 分享跟踪 (Share Tracking)
### 7.1 创建分享跟踪
- **Endpoint**: `POST /api/v1/share/track`
- **描述**: 创建分享跟踪记录,用于追踪用户分享行为
- **请求体**: `application/json`
```json
{
"activityId": 1,
"inviterUserId": 123,
"source": "wechat",
"utm": "campaign-spring"
}
```
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"trackingId": "track-abc123",
"shortCode": "xyz789",
"shareUrl": "https://example.com/r/xyz789",
"activityId": 1,
"inviterUserId": 123
}
}
```
### 7.2 获取分享指标
- **Endpoint**: `GET /api/v1/share/metrics`
- **描述**: 获取指定活动的分享统计指标
- **查询参数**:
- `activityId` (必需): 活动ID
- `startTime` (可选): 开始时间 (ISO 8601格式)
- `endTime` (可选): 结束时间 (ISO 8601格式)
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"activityId": 1,
"totalClicks": 1500,
"uniqueVisitors": 800,
"sourceDistribution": {
"wechat": 600,
"weibo": 400,
"direct": 200
},
"hourlyDistribution": {
"0": 50,
"1": 30,
"2": 20
},
"startTime": "2025-03-01T00:00:00Z",
"endTime": "2025-03-31T23:59:59Z"
}
}
```
### 7.3 获取顶级分享链接
- **Endpoint**: `GET /api/v1/share/top-links`
- **描述**: 获取分享次数最多的链接列表
- **查询参数**:
- `activityId` (必需): 活动ID
- `limit` (可选默认10): 返回数量
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"shortCode": "abc123",
"clickCount": 500,
"inviterUserId": 123
},
{
"shortCode": "def456",
"clickCount": 300,
"inviterUserId": 456
}
]
}
```
### 7.4 获取转化漏斗
- **Endpoint**: `GET /api/v1/share/funnel`
- **描述**: 获取分享转化漏斗数据
- **查询参数**:
- `activityId` (必需): 活动ID
- `startTime` (可选): 开始时间
- `endTime` (可选): 结束时间
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"totalClicks": 1000,
"withReferer": 800,
"withUserAgent": 950,
"refererRate": 0.8,
"topReferers": {
"google.com": 300,
"facebook.com": 200,
"twitter.com": 150
}
}
}
```
### 7.5 获取分享元数据
- **Endpoint**: `GET /api/v1/share/share-meta`
- **描述**: 获取分享相关的元数据配置
- **查询参数**:
- `activityId` (必需): 活动ID
- `userId` (必需): 用户ID
- `template` (可选,默认"default"): 模板名称
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"title": "春季特惠活动",
"description": "邀请好友,赢取大奖",
"imageUrl": "https://example.com/poster.png",
"shareUrl": "https://example.com/r/abc123"
}
}
```
### 7.6 注册分享来源
- **Endpoint**: `POST /api/v1/share/register-source`
- **描述**: 注册用户的分享来源渠道
- **请求体**: `application/json`
```json
{
"activityId": 1,
"userId": 123,
"channel": "wechat",
"params": "utm_source=campaign1"
}
```
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"trackingId": "track-xyz",
"shortCode": "abc789",
"shareUrl": "https://example.com/r/abc789",
"activityId": 1,
"inviterUserId": 123
}
}
```
## 8. 回调管理 (Callbacks)
### 8.1 用户追踪注册
- **Endpoint**: `POST /api/v1/callback/register`
- **描述**: 用户参与活动时进行追踪注册上报,用于记录用户来源和设备信息
- **请求体**: `application/json`
```json
{
"trackingId": "活动创建的追踪ID",
"externalUserId": "外部用户ID可选",
"timestamp": 1699999999999,
"deviceFingerprint": "设备指纹(可选)",
"ip": "客户端IP可选"
}
```
或使用下划线格式:
```json
{
"tracking_id": "活动创建的追踪ID",
"external_user_id": "外部用户ID可选",
"timestamp": 1699999999999,
"device_fingerprint": "设备指纹(可选)",
"ip": "客户端IP可选"
}
```
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"registered": true,
"trackingId": "活动创建的追踪ID",
"activityId": 1,
"rewardStatus": "pending"
}
}
```
- **字段说明**:
- `trackingId` / `tracking_id`: 活动创建的追踪ID必填
- `externalUserId` / `external_user_id`: 外部系统用户ID可选
- `timestamp`: 时间戳(可选)
- `deviceFingerprint` / `device_fingerprint`: 设备指纹(可选,用于风控)
- `ip`: 客户端IP地址可选用于风控
## 9. 用户奖励 (User Rewards)
### 9.1 获取用户奖励列表
- **Endpoint**: `GET /api/v1/me/rewards`
- **描述**: 获取当前用户的奖励记录(分页)
- **查询参数**:
- `activityId` (必需): 活动ID
- `userId` (必需): 用户ID
- `page` (可选默认0): 页码
- `size` (可选默认20): 每页数量
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": [
{
"type": "invite_reward",
"points": 100,
"createdAt": "2025-03-01T10:00:00Z"
},
{
"type": "share_reward",
"points": 50,
"createdAt": "2025-03-02T15:30:00Z"
}
],
"meta": {
"pagination": {
"page": 0,
"size": 20,
"total": 2,
"totalPages": 1,
"hasNext": false,
"hasPrevious": false
}
}
}
```
## 10. 速率限制
所有API端点都受到速率限制保护
- **默认限制**: 每分钟100次请求基于API Key
- **超出限制响应 (429 Too Many Requests)**:
```json
{
"code": 429,
"message": "Rate limit exceeded",
"error": {
"message": "Too many requests, please try again later",
"code": "RATE_LIMIT_EXCEEDED"
}
}
```
- **响应头**:
- `X-RateLimit-Limit`: 速率限制值
- `X-RateLimit-Remaining`: 剩余请求次数
- `Retry-After`: 重试等待秒数
## 11. API版本控制
- **当前版本**: v1
- **版本指定**: 通过URL路径 `/api/v1/...`
- **版本协商**: 可通过 `X-API-Version` 请求头指定版本(可选)
- **响应头**: `X-API-Version` 返回实际使用的API版本
## 12. 最佳实践
### 12.1 错误处理
```javascript
try {
const response = await fetch('/api/v1/activities/1', {
headers: {
'X-API-Key': 'your-api-key',
'Authorization': 'Bearer your-token'
}
});
const result = await response.json();
if (result.code !== 200) {
console.error('API Error:', result.error);
// 处理业务错误
}
} catch (error) {
console.error('Network Error:', error);
// 处理网络错误
}
```
### 12.2 分页处理
```javascript
async function fetchAllPages(activityId) {
let page = 0;
let allData = [];
let hasNext = true;
while (hasNext) {
const response = await fetch(
`/api/v1/activities/${activityId}/leaderboard?page=${page}&size=100`,
{ headers: { 'X-API-Key': 'your-key' } }
);
const result = await response.json();
allData = allData.concat(result.data);
hasNext = result.meta.pagination.hasNext;
page++;
}
return allData;
}
```
### 12.3 速率限制处理
```javascript
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
}
throw new Error('Max retries exceeded');
}
```
---
**文档版本**: 2.0
**最后更新**: 2026-03-04
**维护者**: 技术团队