Files
wenzi/docs/api.md
Your Name 0eed01e9eb docs: 完善项目文档并清理过时文件
新增文档:
- API_INTEGRATION_GUIDE.md: API集成指南(快速开始、SDK示例、常见场景)
- DEPLOYMENT_GUIDE.md: 部署指南(环境要求、生产部署、Docker部署)
- CONFIGURATION_GUIDE.md: 配置指南(环境配置、数据库、Redis、安全)
- DEVELOPMENT_GUIDE.md: 开发指南(环境搭建、项目结构、开发规范)

文档更新:
- api.md: 补充8个缺失的API端点(分享跟踪、回调、用户奖励)

文档清理:
- 归档18个过时文档到 docs/archive/2026-03-04-cleanup/
- 删除3个调试文档(ralph-loop-*)

代码清理:
- 删除4个.bak备份文件
- 删除1个.disabled测试文件

文档结构优化:
- 从~40个文档精简到12个核心文档
- 建立清晰的文档导航体系
- 完善文档间的交叉引用
2026-03-04 10:41:38 +08:00

755 lines
18 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"
}
```
## 认证与鉴权
- `/api/**` 需要 `X-API-Key`。
- `/api/v1/me/**`、`/api/v1/activities/**`、`/api/v1/api-keys/**`、`/api/v1/share/**` 需要 `Authorization: Bearer <token>`。
- `/r/**`、`/actuator/**` 不需要认证。
## 错误码
- `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密钥。密钥仅在本次响应中明文返回请立即保存。
- **请求体**: `application/json`
```json
{
"activityId": 1,
"name": "我的第一个密钥"
}
```
- **成功响应 (201 Created)**:
```json
{
"code": 201,
"message": "success",
"data": {
"apiKey": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
},
"timestamp": "2025-03-01T10:00:00"
}
```
- **失败响应**:
- `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
{
"activityId": 1,
"callbackUrl": "https://your-domain.com/webhook",
"events": ["user.registered", "user.invited", "reward.granted"],
"secret": "your-webhook-secret"
}
```
- **成功响应 (200 OK)**:
```json
{
"code": 200,
"message": "success",
"data": {
"callbackId": "cb-123456",
"activityId": 1,
"callbackUrl": "https://your-domain.com/webhook",
"status": "active"
}
}
```
- **回调事件格式**:
```json
{
"eventType": "user.registered",
"eventId": "evt-abc123",
"timestamp": "2025-03-01T10:00:00Z",
"data": {
"activityId": 1,
"userId": 123,
"inviterUserId": 456
},
"signature": "sha256-hash-of-payload"
}
```
## 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
**维护者**: 技术团队