This document is the detailed API contract for this branch.
Use this file as the single source of truth for frontend/backend integration details. The READMEs intentionally stay shorter and should defer to this document for endpoint-level behavior.
Server-to-server integration endpoints (IF-01/IF-02, IntegrationGuard) are out of scope here — see the Salesforce repo design docs (interface-design.md BD-09 / module-design.md DD-02) and docs/manual-retry-procedure.md.
Base URL in local development:
http://localhost:3001
Global API prefix:
/v1
- The backend uses HttpOnly cookies for
access_tokenandrefresh_token. - A
csrf_tokencookie is also used for mutation requests when CSRF protection is enabled.
Most successful endpoints use the backend ApiResponseDto envelope:
{
"code": 200,
"message": "Operation succeeded",
"data": {},
"requestId": "req_xxx",
"timestamp": "2026-03-30T00:00:00.000Z"
}Some booking list flows return the list payload directly from the controller/service path rather than being wrapped in data. That is part of the current branch contract and is documented below endpoint-by-endpoint.
List endpoints that paginate use this shape:
{
"items": [],
"total": 0,
"page": 1,
"limit": 10,
"totalPages": 0
}- method:
POST - path:
/v1/auth/login - auth required?:
No - request shape:
{
"phoneNumber": "13800138000",
"verificationCode": "123456"
}- response shape:
{
"code": 200,
"message": "Login succeeded",
"data": {
"accessToken": "jwt",
"refreshToken": "jwt",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "uuid",
"name": "Alice",
"phoneNumber": "13800138000",
"role": "ADMIN",
"status": "ACTIVE"
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
Uses phone number plus verification code.
Also sets
access_token,refresh_token, andcsrf_tokencookies.
- method:
POST - path:
/v1/auth/register - auth required?:
No - request shape:
{
"name": "Alice",
"phoneNumber": "13800138000",
"email": "alice@example.com",
"verificationCode": "123456"
}- response shape:
{
"code": 200,
"message": "Register succeeded",
"data": {
"accessToken": "jwt",
"refreshToken": "jwt",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "uuid",
"name": "Alice",
"phoneNumber": "13800138000",
"role": "CUSTOMER",
"status": "ACTIVE"
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
Registration also sets auth cookies on success.
The submitted
emailmust match (case-insensitively, surrounding whitespace ignored) the address the verification code was issued to byPOST /v1/auth/send-verification-code(type=register); a missing or mismatchingemailreturns400 VERIFICATION_CODE_ERRORwith the message验证码与邮箱不匹配,请重新获取without consuming the code or the attempt counter, so the user can retry with the correct address until the code expires.
- method:
POST - path:
/v1/auth/send-verification-code - auth required?:
No - request shape:
{
"phoneNumber": "13800138000",
"type": "register",
"email": "alice@example.com"
}- response shape:
{
"code": 200,
"message": "Verification code sent",
"data": null,
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
typemust beloginorregister. The 6-digit code is delivered by email and is valid for 5 minutes. The subject line never contains the code.emailis required whentype=register(the code is sent to that address); fortype=loginit is ignored and the code is sent to the email bound to the account. The address the code was issued to is recorded for 5 minutes so thatPOST /v1/auth/registercan require the same address (see that endpoint). Rate limits:429when more than 5 requests per 60 s come from the same IP (endpoint-level throttle) or when the same recipient requests again within the 60 s cooldown. Requesting a new code resets the wrong-code attempt counter for that phone number and type. Errors:400 RECIPIENT_EMAIL_MISSINGwhen no recipient email can be resolved (register withoutemail, or login for an account without a bound email),409 EMAIL_EXISTS(邮箱 <email> 已存在) whentype=registerand the address already belongs to an existing account. The pre-send duplicate check compares addresses case-insensitively (surrounding whitespace ignored); the database unique constraint onemailis itself case-sensitive, so this check is what rejects a request whose address differs from an existing one only in case. The check runs before the code is generated, mailed or stored, so a rejected request sends no email and writes nothing to Redis (no code, cooldown or email binding). While the 60 s cooldown is active,429takes precedence over this409(the cooldown is evaluated first), and502 EXTERNAL_SERVICE_ERRORwhen the email cannot be sent (no code is stored in that case).
- method:
POST - path:
/v1/auth/refresh - auth required?:
No - request shape:
{
"refreshToken": "jwt"
}- response shape:
{
"code": 200,
"message": "Token refreshed",
"data": {
"accessToken": "jwt",
"refreshToken": "jwt",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "uuid",
"name": "Alice",
"phoneNumber": "13800138000",
"role": "ADMIN",
"status": "ACTIVE"
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
The backend prefers the
refresh_tokencookie when present and falls back tobody.refreshToken.
- method:
POST - path:
/v1/auth/logout - auth required?:
Yes - request shape:
{}- response shape:
{
"code": 200,
"message": "Logout succeeded",
"data": null,
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
Clears
access_token,refresh_token, andcsrf_tokencookies.
-
method:
GET -
path:
/v1/auth/profile -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "Profile loaded",
"data": {
"id": "uuid",
"name": "Alice",
"phoneNumber": "13800138000",
"email": "alice@example.com",
"role": "ADMIN",
"status": "ACTIVE",
"remarks": "",
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: Treat this as the canonical "current user" endpoint for this branch.
-
method:
GET -
path:
/v1/auth/verify -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "Token is valid",
"data": {
"userId": "uuid",
"valid": true,
"expiresAt": 1770000000000
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
expiresAtis returned as a millisecond timestamp.
-
method:
GET -
path:
/v1/auth/check-phone -
auth required?:
No -
request shape: Query parameter:
phoneNumber(string) -
response shape:
{
"code": 200,
"message": "检查完成",
"data": {
"exists": true
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
检查手机号是否已注册。返回
exists布尔值。
- method:
POST - path:
/v1/bookings - auth required?:
Yes - request shape:
{
"timeSlotId": "uuid",
"userId": "uuid",
"serviceId": "uuid",
"appointmentDate": "2026-03-30",
"customerName": "Alice",
"customerPhone": "13800138000",
"customerEmail": "alice@example.com",
"customerWechat": "alice_wechat",
"notes": "Window seat if possible",
"serviceName": "Consultation"
}- response shape:
{
"code": 200,
"message": "Booking created",
"data": {
"id": "uuid",
"appointmentNumber": "AP-20260330-0001",
"timeSlotId": "uuid",
"userId": "uuid",
"appointmentDate": "2026-03-30T00:00:00.000Z",
"status": "PENDING",
"customerName": "Alice",
"customerPhone": "13800138000",
"customerEmail": "alice@example.com",
"customerWechat": "alice_wechat",
"notes": "Window seat if possible",
"timeSlot": {
"slotTime": "09:00:00",
"durationMinutes": 30
},
"user": {
"name": "Alice",
"phoneNumber": "13800138000"
},
"service": {
"id": "uuid",
"name": "Consultation",
"durationMinutes": 30
},
"confirmationSent": false,
"reminderSent": false,
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
If
userIdis omitted, the backend fills it fromcurrentUser.id.
-
method:
GET -
path:
/v1/bookings/all -
auth required?:
Yes -
request shape: Query params may include
userId,timeSlotId,status,customerName,customerPhone,startDate,endDate,page,limit, andkeyword. -
response shape:
{
"items": [
{
"id": "uuid",
"appointmentNumber": "AP-20260330-0001",
"timeSlotId": "uuid",
"userId": "uuid",
"appointmentDate": "2026-03-30T00:00:00.000Z",
"status": "PENDING",
"customerName": "Alice",
"customerPhone": "13800138000"
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
}- notes:
/bookings/allis the shared list endpoint for both user and admin clients. Non-admin users are narrowed to the current authenticated user by backend logic even if the incoming query is broader./bookings/meis not introduced in this branch and must not be treated as part of the contract.
- method:
GET - path:
/v1/bookings/by-date - auth required?:
Yes - request shape:
?date=YYYY-MM-DD
- response shape:
{
"items": [
{
"id": "uuid",
"appointmentNumber": "AP-20260330-0001",
"status": "PENDING",
"customerName": "Alice"
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
}- notes: Used for date-specific booking views and date-based availability support. Non-admin users are also filtered to their own records here.
-
method:
GET -
path:
/v1/bookings/:id -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"id": "uuid",
"appointmentNumber": "AP-20260330-0001",
"timeSlotId": "uuid",
"userId": "uuid",
"appointmentDate": "2026-03-30T00:00:00.000Z",
"status": "PENDING",
"customerName": "Alice",
"customerPhone": "13800138000"
}- notes: Returns a single booking object rather than a wrapped paginated payload. Non-admin users can only access their own booking.
- method:
PATCH - path:
/v1/bookings/:id - auth required?:
Yes - request shape:
{
"status": "CONFIRMED",
"appointmentDate": "2026-03-31",
"timeSlotId": "uuid",
"serviceId": "uuid",
"customerName": "Alice",
"customerPhone": "13800138000",
"customerEmail": "alice@example.com",
"customerWechat": "alice_wechat",
"notes": "Updated note"
}- response shape:
{
"code": 200,
"message": "Booking updated",
"data": {
"id": "uuid",
"status": "CONFIRMED"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: Non-admin users can only update their own booking.
- method:
PATCH - path:
/v1/bookings/:id/cancel - auth required?:
Yes - request shape:
{}- response shape:
{
"code": 200,
"message": "Booking cancelled",
"data": null,
"requestId": "req_xxx",
"timestamp": "..."
}- notes: This is the frontend-compatible cancel endpoint for this branch.
-
method:
DELETE -
path:
/v1/bookings/:id -
auth required?:
Yes -
request shape: No request body.
-
response shape: HTTP 204 No Content (no response body).
-
notes: 硬删除预约。管理员可以删除任何预约,普通用户只能删除自己的预约。
-
method:
GET -
path:
/v1/bookings/stats/summary -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "获取预约统计信息成功",
"data": {
"totalAppointments": 100,
"pendingAppointments": 10,
"confirmedAppointments": 70,
"completedAppointments": 15,
"cancelledAppointments": 5,
"todayAppointments": 3,
"thisWeekAppointments": 20,
"thisMonthAppointments": 50
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员专用统计端点。返回预约相关的统计数据。
-
method:
GET -
path:
/v1/services -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "Services loaded",
"data": [
{
"id": "uuid",
"name": "Consultation",
"description": "30 minute consultation",
"durationMinutes": 30,
"price": 199,
"imageUrl": "https://example.com/service.png",
"categoryId": "uuid",
"isActive": true,
"displayOrder": 1,
"category": {
"id": "uuid",
"name": "General"
}
}
],
"requestId": "req_xxx",
"timestamp": "..."
}- notes: Shared service list endpoint used by booking flows.
-
method:
GET -
path:
/v1/services/all -
auth required?:
Yes -
request shape: Query params may include
name,description,durationMinutes,price,imageUrl,categoryId,isActive,displayOrder,page, andlimit. -
response shape:
{
"code": 200,
"message": "Services loaded",
"data": {
"items": [
{
"id": "uuid",
"name": "Consultation",
"durationMinutes": 30,
"isActive": true
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: Admin-oriented service list endpoint with pagination and filtering support.
- method:
POST - path:
/v1/services/admin - auth required?:
Yes(Admin only) - request shape:
{
"name": "深度咨询",
"description": "专业咨询服务",
"durationMinutes": 60,
"price": 299,
"imageUrl": "https://example.com/service.png",
"categoryId": "uuid",
"isActive": true,
"displayOrder": 1
}- response shape:
{
"code": 201,
"message": "创建服务成功",
"data": {
"id": "uuid",
"name": "深度咨询",
"description": "专业咨询服务",
"durationMinutes": 60,
"price": 299,
"imageUrl": "https://example.com/service.png",
"categoryId": "uuid",
"isActive": true,
"displayOrder": 1,
"category": {
"id": "uuid",
"name": "General"
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员创建新服务。
- method:
PATCH - path:
/v1/services/admin/:id - auth required?:
Yes(Admin only) - request shape:
{
"name": "更新后的服务名称",
"description": "更新后的描述",
"durationMinutes": 90,
"price": 399,
"imageUrl": "https://example.com/new-image.png",
"categoryId": "uuid",
"isActive": false,
"displayOrder": 2
}- response shape:
{
"code": 200,
"message": "更新服务成功",
"data": {
"id": "uuid",
"name": "更新后的服务名称",
"description": "更新后的描述",
"durationMinutes": 90,
"price": 399,
"imageUrl": "https://example.com/new-image.png",
"categoryId": "uuid",
"isActive": false,
"displayOrder": 2,
"category": {
"id": "uuid",
"name": "General"
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员更新服务信息。
- method:
PATCH - path:
/v1/services/admin/:id/status - auth required?:
Yes(Admin only) - request shape:
{
"isActive": false
}- response shape:
{
"code": 200,
"message": "服务状态更新成功",
"data": {
"id": "uuid",
"name": "服务名称",
"isActive": false
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员切换服务启用状态。
-
method:
GET -
path:
/v1/time-slots -
auth required?:
No -
request shape: Query params may include
slotTime,isActive,minDuration,maxDuration,page, andlimit. -
response shape:
{
"items": [
{
"id": "uuid",
"slotTime": "09:00:00",
"durationMinutes": 30,
"isActive": true
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
}- notes: General time-slot listing endpoint.
- method:
GET - path:
/v1/time-slots/available-slots - auth required?:
No - request shape:
?date=YYYY-MM-DD
- response shape:
{
"code": 200,
"message": "Operation succeeded",
"data": [
{
"id": "uuid",
"slotTime": "09:00:00",
"durationMinutes": 30,
"bookedCount": 1,
"isAvailable": true,
"availabilityStatus": "AVAILABLE",
"appointments": [
{
"id": "uuid",
"customerName": "Alice",
"status": "PENDING"
}
]
}
],
"requestId": "req_xxx",
"timestamp": "..."
}- notes:
Primary time-slot availability endpoint for this branch.
datemust be passed inYYYY-MM-DDformat.
- method:
POST - path:
/v1/time-slots - auth required?:
Yes(Admin only) - request shape:
{
"slotTime": "09:00:00",
"durationMinutes": 30,
"isActive": true
}- response shape:
{
"code": 201,
"message": "创建时间段成功",
"data": {
"id": "uuid",
"slotTime": "09:00:00",
"durationMinutes": 30,
"isActive": true,
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员创建新时间段。
-
method:
GET -
path:
/v1/time-slots/:id -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "获取时间段详情成功",
"data": {
"id": "uuid",
"slotTime": "09:00:00",
"durationMinutes": 30,
"isActive": true,
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员获取单个时间段详情。
- method:
PATCH - path:
/v1/time-slots/:id - auth required?:
Yes(Admin only) - request shape:
{
"slotTime": "10:00:00",
"durationMinutes": 60,
"isActive": false
}- response shape:
{
"code": 200,
"message": "更新时间段成功",
"data": {
"id": "uuid",
"slotTime": "10:00:00",
"durationMinutes": 60,
"isActive": false,
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T01:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员更新时间段信息。
-
method:
DELETE -
path:
/v1/time-slots/:id -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape: HTTP 204 No Content (no response body).
-
notes: 管理员删除时间段。
- method:
POST - path:
/v1/users - auth required?:
Yes(Admin only) - request shape:
{
"name": "Bob",
"phoneNumber": "13900139000",
"email": "bob@example.com",
"role": "CUSTOMER",
"status": "ACTIVE",
"remarks": "新用户"
}- response shape:
{
"code": 201,
"message": "创建用户成功",
"data": {
"id": "uuid",
"name": "Bob",
"phoneNumber": "13900139000",
"email": "bob@example.com",
"role": "CUSTOMER",
"status": "ACTIVE",
"remarks": "新用户",
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员创建新用户。
-
method:
GET -
path:
/v1/users -
auth required?:
Yes(Admin only) -
request shape: Query params may include
name,phoneNumber,email,role,status,page,limit. -
response shape:
{
"code": 200,
"message": "用户列表获取成功",
"data": {
"items": [
{
"id": "uuid",
"name": "Bob",
"phoneNumber": "13900139000",
"email": "bob@example.com",
"role": "CUSTOMER",
"status": "ACTIVE"
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员获取用户列表。
-
method:
GET -
path:
/v1/users/profile/me -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "获取个人资料成功",
"data": {
"id": "uuid",
"name": "Alice",
"phoneNumber": "13800138000",
"email": "alice@example.com",
"role": "ADMIN",
"status": "ACTIVE",
"remarks": "",
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取当前认证用户的完整个人资料。
-
method:
GET -
path:
/v1/users/statistics -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "用户统计获取成功",
"data": {
"totalUsers": 100,
"activeUsers": 80,
"inactiveUsers": 20,
"adminUsers": 5,
"customerUsers": 95,
"todayRegistrations": 3
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员获取用户统计数据。
-
method:
GET -
path:
/v1/users/:id -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "获取用户详情成功",
"data": {
"id": "uuid",
"name": "Bob",
"phoneNumber": "13900139000",
"email": "bob@example.com",
"role": "CUSTOMER",
"status": "ACTIVE",
"remarks": "",
"createdAt": "2026-03-30T00:00:00.000Z",
"updatedAt": "2026-03-30T00:00:00.000Z"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员获取单个用户详情。
- method:
PUT - path:
/v1/users/:id/status - auth required?:
Yes(Admin only) - request shape:
{
"status": "INACTIVE"
}- response shape:
{
"code": 200,
"message": "用户状态更新成功",
"data": {
"id": "uuid",
"status": "INACTIVE"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员更新用户状态。
- method:
PUT - path:
/v1/users/:id - auth required?:
Yes(Admin only) - request shape:
{
"name": "Bob Updated",
"email": "bob.updated@example.com",
"role": "ADMIN",
"remarks": "更新备注"
}- response shape:
{
"code": 200,
"message": "用户信息更新成功",
"data": {
"id": "uuid",
"name": "Bob Updated",
"email": "bob.updated@example.com",
"role": "ADMIN",
"remarks": "更新备注"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员更新用户信息。
-
method:
DELETE -
path:
/v1/users/:id -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape: HTTP 204 No Content (no response body).
-
notes: 管理员删除用户。
-
method:
GET -
path:
/v1/system/settings -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "系统设置获取成功",
"data": {
"key": "value",
"anotherKey": "anotherValue"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取系统配置设置。
- method:
PATCH - path:
/v1/system/settings/:key - auth required?:
Yes(Admin only) - request shape:
{
"value": "newValue"
}- response shape:
{
"code": 200,
"message": "系统设置更新成功",
"data": {
"key": "updatedKey",
"value": "newValue"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 更新特定系统设置。
-
method:
GET -
path:
/v1/system/reports/statistics -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "系统统计报告获取成功",
"data": {
"totalBookings": 1000,
"totalUsers": 150,
"totalServices": 20,
"totalTimeSlots": 48
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取系统整体统计报告。
-
method:
GET -
path:
/v1/system/reports/user-statistics -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "用户统计报告获取成功",
"data": {
"userActivity": [
{
"date": "2026-03-30",
"activeUsers": 50,
"newRegistrations": 3
}
]
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取用户活动统计报告。
-
method:
POST -
path:
/v1/upload/single -
auth required?:
Yes -
request shape: Multipart form-data with field
file(file upload). -
response shape:
{
"code": 200,
"message": "文件上传成功",
"data": {
"url": "https://example.com/uploads/filename.jpg",
"filename": "filename.jpg",
"size": 12345,
"mimetype": "image/jpeg"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 单文件上传端点。
-
method:
POST -
path:
/v1/upload/multiple -
auth required?:
Yes -
request shape: Multipart form-data with field
files(multiple file upload). -
response shape:
{
"code": 200,
"message": "多文件上传成功",
"data": [
{
"url": "https://example.com/uploads/file1.jpg",
"filename": "file1.jpg",
"size": 12345,
"mimetype": "image/jpeg"
}
],
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 多文件上传端点。
-
method:
POST -
path:
/v1/upload/avatar -
auth required?:
Yes -
request shape: Multipart form-data with field
avatar(image file). -
response shape:
{
"code": 200,
"message": "头像上传成功",
"data": {
"url": "https://example.com/uploads/avatar.jpg",
"filename": "avatar.jpg",
"size": 12345,
"mimetype": "image/jpeg"
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 用户头像上传专用端点。
-
method:
GET -
path:
/v1/upload/stats -
auth required?:
Yes(Admin only) -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "上传统计获取成功",
"data": {
"totalFiles": 100,
"totalSize": 10485760,
"byType": {
"image": 50,
"document": 30,
"other": 20
}
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 管理员获取文件上传统计数据。
-
method:
GET -
path:
/v1/notifications -
auth required?:
Yes -
request shape: Query params may include
type,read,page,limit. -
response shape:
{
"code": 200,
"message": "通知列表获取成功",
"data": {
"items": [
{
"id": "uuid",
"type": "SYSTEM",
"title": "系统通知",
"content": "您的预约已确认",
"read": false,
"createdAt": "2026-03-30T00:00:00.000Z"
}
],
"total": 1,
"page": 1,
"limit": 10,
"totalPages": 1
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取当前用户的通知列表。
-
method:
PUT -
path:
/v1/notifications/:id/read -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "通知标记为已读成功",
"data": {
"id": "uuid",
"read": true
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 将通知标记为已读。
-
method:
PUT -
path:
/v1/notifications/read-all -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "全部通知标记为已读成功",
"data": {
"markedCount": 5
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 将当前用户的所有通知标记为已读。
-
method:
GET -
path:
/v1/notifications/unread-count -
auth required?:
Yes -
request shape: No request body.
-
response shape:
{
"code": 200,
"message": "未读通知数获取成功",
"data": {
"count": 3
},
"requestId": "req_xxx",
"timestamp": "..."
}- notes: 获取当前用户的未读通知数量。
- 连接 URL:
ws://localhost:3001/v1/notifications/ws - 认证: 通过
access_tokencookie 或查询参数token认证 - 消息类型:
notification: 新通知推送booking_update: 预约状态更新system_alert: 系统告警
- notes: 实时通知通过 WebSocket 推送。
-
method:
GET -
path:
/v1/health -
auth required?:
No -
request shape: No request body.
-
response shape:
{
"status": "healthy",
"timestamp": "2026-03-30T00:00:00.000Z",
"services": {
"database": "connected",
"redis": "connected",
"storage": "available"
}
}- notes: 服务健康检查端点。返回数据库、Redis等依赖服务的连接状态。