453 lines
8.0 KiB
Markdown
453 lines
8.0 KiB
Markdown
# MemeStudio API Reference
|
|
|
|
## Base URL
|
|
- Development: `http://localhost:3001/studio`
|
|
- Production: `https://119.91.211.52/studio`
|
|
|
|
## Authentication
|
|
All endpoints except `/api/auth/*` require a valid session cookie:
|
|
- `better-auth.session_token` (HTTP)
|
|
- `__Secure-better-auth.session_token` (HTTPS)
|
|
|
|
Error response if unauthorized: `{ error: 'Unauthorized' }` (401)
|
|
|
|
---
|
|
|
|
## Authentication Endpoints
|
|
|
|
### POST /api/auth/sign-in/email
|
|
Sign in with email and password.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"email": "admin@example.com",
|
|
"password": "password123"
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"user": {
|
|
"id": "uuid",
|
|
"email": "admin@example.com",
|
|
"name": "Admin",
|
|
"emailVerified": true
|
|
},
|
|
"session": {
|
|
"id": "session_id",
|
|
"expiresAt": "2024-04-14T10:00:00Z",
|
|
"token": "session_token"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### POST /api/auth/sign-out
|
|
Sign out and invalidate session.
|
|
|
|
**Response:**
|
|
```json
|
|
{ "success": true }
|
|
```
|
|
|
|
---
|
|
|
|
## Levels API
|
|
|
|
### GET /api/levels
|
|
Get all levels, sorted by sortOrder.
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"imageUrl": "https://bucket.myqcloud.com/mini_game/images/...",
|
|
"answer": "答案文本",
|
|
"hint1": "提示1",
|
|
"hint2": "提示2",
|
|
"hint3": "提示3",
|
|
"sortOrder": 1,
|
|
"createdAt": "2024-04-01T10:00:00Z",
|
|
"updatedAt": "2024-04-01T10:00:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### POST /api/levels
|
|
Create a new level. sortOrder is auto-calculated as max+1.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"imageUrl": "https://bucket.myqcloud.com/mini_game/images/...",
|
|
"answer": "答案",
|
|
"hint1": "提示1",
|
|
"hint2": "提示2",
|
|
"hint3": "提示3"
|
|
}
|
|
```
|
|
|
|
**Response:** Level object (201 Created)
|
|
|
|
**Validation:**
|
|
- `imageUrl` and `answer` are required
|
|
- Returns 400 if missing required fields
|
|
|
|
---
|
|
|
|
### PUT /api/levels
|
|
Update a level.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"imageUrl": "...",
|
|
"answer": "新答案",
|
|
"hint1": "...",
|
|
"hint2": "...",
|
|
"hint3": "..."
|
|
}
|
|
```
|
|
|
|
**Response:** Updated Level object
|
|
|
|
**Validation:**
|
|
- `id` is required
|
|
- Other fields are optional (only provided fields are updated)
|
|
|
|
---
|
|
|
|
### DELETE /api/levels?id=<levelId>
|
|
Delete a level.
|
|
|
|
**Response:**
|
|
```json
|
|
{ "success": true }
|
|
```
|
|
|
|
---
|
|
|
|
## Levels Reorder API
|
|
|
|
### PUT /api/levels/reorder
|
|
Batch update sort order for multiple levels (atomic transaction).
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"orders": [
|
|
{ "id": "uuid1", "sortOrder": 1 },
|
|
{ "id": "uuid2", "sortOrder": 2 },
|
|
{ "id": "uuid3", "sortOrder": 3 }
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{ "success": true }
|
|
```
|
|
|
|
**Validation:**
|
|
- `orders` must be an array of objects with `id` and `sortOrder`
|
|
|
|
---
|
|
|
|
## Admin Users API
|
|
|
|
### GET /api/users
|
|
Get all admin users, sorted by createdAt DESC.
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "uuid",
|
|
"email": "admin@example.com",
|
|
"emailVerified": true,
|
|
"name": "Admin Name",
|
|
"image": null,
|
|
"createdAt": "2024-04-01T10:00:00Z",
|
|
"updatedAt": "2024-04-01T10:00:00Z"
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### POST /api/users
|
|
Create a new admin user.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"email": "newadmin@example.com",
|
|
"password": "securepassword123",
|
|
"name": "New Admin"
|
|
}
|
|
```
|
|
|
|
**Response:** User object (201 Created)
|
|
|
|
**Validation:**
|
|
- `email` and `password` are required
|
|
- `email` must be unique (returns 400 if already exists: "该邮箱已被注册")
|
|
- Password is automatically hashed using Better Auth's hashPassword
|
|
|
|
---
|
|
|
|
### PUT /api/users
|
|
Update a user.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"email": "newemail@example.com",
|
|
"password": "newpassword123",
|
|
"name": "Updated Name"
|
|
}
|
|
```
|
|
|
|
**Response:** Updated User object
|
|
|
|
**Validation:**
|
|
- `id` is required
|
|
- Email must be unique across other users (returns 400 if taken: "该邮箱已被其他用户使用")
|
|
- If `password` is provided, it's hashed and Account record is updated
|
|
|
|
---
|
|
|
|
### DELETE /api/users?id=<userId>
|
|
Delete a user.
|
|
|
|
**Response:**
|
|
```json
|
|
{ "success": true }
|
|
```
|
|
|
|
**Validation:**
|
|
- `id` is required
|
|
- Cannot delete yourself (returns 400: "不能删除自己的账户")
|
|
- Cascading delete removes all sessions and accounts
|
|
|
|
---
|
|
|
|
## WeChat Users API
|
|
|
|
### GET /api/wx-users?search=<text>&page=<1>&limit=<20>
|
|
Get WeChat users with pagination and search.
|
|
|
|
**Query Parameters:**
|
|
- `search` (optional): Search in nickname or openid (contains search)
|
|
- `page` (optional, default 1): Page number
|
|
- `limit` (optional, default 20): Items per page
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"users": [
|
|
{
|
|
"id": "uuid",
|
|
"openid": "oABCDEF123456",
|
|
"nickname": "用户昵称",
|
|
"avatarUrl": "https://...",
|
|
"points": 100,
|
|
"createdAt": "2024-04-01T10:00:00Z",
|
|
"updatedAt": "2024-04-01T10:00:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"total": 150,
|
|
"page": 1,
|
|
"limit": 20,
|
|
"totalPages": 8
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### GET /api/wx-users/<userId>
|
|
Get a specific WeChat user with their level progress.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"openid": "oABCDEF123456",
|
|
"nickname": "用户昵称",
|
|
"avatarUrl": "https://...",
|
|
"points": 100,
|
|
"sessionKey": "...",
|
|
"createdAt": "2024-04-01T10:00:00Z",
|
|
"updatedAt": "2024-04-01T10:00:00Z",
|
|
"levelProgress": [
|
|
{
|
|
"id": "progress_uuid",
|
|
"userId": "uuid",
|
|
"levelId": "uuid",
|
|
"completedAt": "2024-04-02T15:30:00Z",
|
|
"level": {
|
|
"id": "uuid",
|
|
"answer": "答案"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### DELETE /api/wx-users/level-progress
|
|
Delete multiple level progress records (batch).
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"ids": [
|
|
"progress_uuid1",
|
|
"progress_uuid2",
|
|
"progress_uuid3"
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{ "deleted": 3 }
|
|
```
|
|
|
|
**Validation:**
|
|
- `ids` must be a non-empty array of strings
|
|
- Returns 400 if validation fails
|
|
|
|
---
|
|
|
|
## Tencent COS API
|
|
|
|
### GET /api/cos/temp-key
|
|
Get temporary credentials for uploading images to COS.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"credentials": {
|
|
"tmpSecretId": "AKIA...",
|
|
"tmpSecretKey": "...",
|
|
"sessionToken": "..."
|
|
},
|
|
"startTime": 1712000000,
|
|
"expiredTime": 1712001800,
|
|
"bucket": "mybucket-1234567890",
|
|
"region": "ap-guangzhou"
|
|
}
|
|
```
|
|
|
|
**Details:**
|
|
- Credentials are valid for 30 minutes (1800 seconds)
|
|
- Limited to upload to `mini_game/images/*` directory
|
|
- Use returned `bucket` and `region` for upload configuration
|
|
- Browser should upload directly to COS using these credentials (S3-compatible API)
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
### Standard Error Response
|
|
```json
|
|
{
|
|
"error": "Error message"
|
|
}
|
|
```
|
|
|
|
### HTTP Status Codes
|
|
- `200`: Success
|
|
- `201`: Created
|
|
- `400`: Bad Request (validation error)
|
|
- `401`: Unauthorized (no session)
|
|
- `404`: Not Found (resource doesn't exist)
|
|
- `500`: Server Error
|
|
|
|
---
|
|
|
|
## Implementation Notes
|
|
|
|
### Session Validation Pattern
|
|
```typescript
|
|
const session = await auth.api.getSession({ headers: request.headers })
|
|
if (!session) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
}
|
|
```
|
|
|
|
### Pagination Pattern
|
|
- `skip = (page - 1) * limit`
|
|
- `totalPages = Math.ceil(total / limit)`
|
|
|
|
### Transaction Pattern (Multi-step operations)
|
|
```typescript
|
|
await prisma.$transaction(async (tx) => {
|
|
// Multiple database operations in atomic transaction
|
|
})
|
|
```
|
|
|
|
### Error Handling Pattern
|
|
All endpoints log errors to console and return appropriate status codes.
|
|
|
|
---
|
|
|
|
## Testing with cURL
|
|
|
|
### Sign In
|
|
```bash
|
|
curl -X POST http://localhost:3001/studio/api/auth/sign-in/email \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"email":"admin@example.com","password":"admin123456"}' \
|
|
-c cookies.txt
|
|
```
|
|
|
|
### Get Levels (with session cookie)
|
|
```bash
|
|
curl http://localhost:3001/studio/api/levels \
|
|
-b cookies.txt
|
|
```
|
|
|
|
### Create Level
|
|
```bash
|
|
curl -X POST http://localhost:3001/studio/api/levels \
|
|
-H "Content-Type: application/json" \
|
|
-b cookies.txt \
|
|
-d '{
|
|
"imageUrl":"https://bucket.myqcloud.com/mini_game/images/test.jpg",
|
|
"answer":"答案",
|
|
"hint1":"提示1",
|
|
"hint2":"提示2",
|
|
"hint3":"提示3"
|
|
}'
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables Required for API
|
|
|
|
```
|
|
DATABASE_URL=mysql://user:pass@host:port/dbname
|
|
BETTER_AUTH_SECRET=<32+ chars>
|
|
BETTER_AUTH_URL=http://localhost:3001
|
|
NEXT_PUBLIC_APP_URL=http://localhost:3001
|
|
NEXT_PUBLIC_BASE_PATH=/studio
|
|
COS_SECRET_ID=<tencent secret>
|
|
COS_SECRET_KEY=<tencent secret>
|
|
COS_BUCKET=bucket-name
|
|
COS_REGION=ap-guangzhou
|
|
COS_APPID=<tencent app id>
|
|
```
|