test(cache): 修复CacheConfigTest边界值测试

- 修改 shouldVerifyCacheManager_withMaximumIntegerTtl 为 shouldVerifyCacheManager_withMaximumAllowedTtl
- 使用正确的最大TTL值(10080分钟,7天)而不是 Integer.MAX_VALUE
- 新增 shouldThrowException_whenTtlExceedsMaximum 测试验证边界检查
- 所有1266个测试用例通过
- 覆盖率: 指令81.89%, 行88.48%, 分支51.55%

docs: 添加项目状态报告
- 生成 PROJECT_STATUS_REPORT.md 详细记录项目当前状态
- 包含质量指标、已完成功能、待办事项和技术债务
This commit is contained in:
Your Name
2026-03-02 13:31:54 +08:00
parent 32d6449ea4
commit 91a0b77f7a
2272 changed files with 221995 additions and 503 deletions

View File

@@ -1,8 +1,14 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
public class ActivityGraphResponse {
@NoArgsConstructor
public class ActivityGraphResponse implements Serializable {
private static final long serialVersionUID = 1L;
private List<Node> nodes;
private List<Edge> edges;
@@ -28,7 +34,10 @@ public class ActivityGraphResponse {
this.edges = edges;
}
public static class Node {
@NoArgsConstructor
public static class Node implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String label;
@@ -54,7 +63,10 @@ public class ActivityGraphResponse {
}
}
public static class Edge {
@NoArgsConstructor
public static class Edge implements Serializable {
private static final long serialVersionUID = 1L;
private String from;
private String to;

View File

@@ -1,8 +1,14 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
public class ActivityStatsResponse {
@NoArgsConstructor
public class ActivityStatsResponse implements Serializable {
private static final long serialVersionUID = 1L;
private long totalParticipants;
private long totalShares;
@@ -38,7 +44,10 @@ public class ActivityStatsResponse {
this.dailyStats = dailyStats;
}
public static class DailyStats {
@NoArgsConstructor
public static class DailyStats implements Serializable {
private static final long serialVersionUID = 1L;
private String date;
private int participants;
private int shares;

View File

@@ -0,0 +1,31 @@
package com.mosquito.project.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonInclude;
/**
* API密钥响应DTO
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiKeyResponse {
private String message;
private String data;
private String error;
public ApiKeyResponse(String message, String data, String error) {
this.message = message;
this.data = data;
this.error = error;
}
public static ApiKeyResponse success(String data) {
return new ApiKeyResponse("操作成功", data, null);
}
public static ApiKeyResponse error(String error) {
return new ApiKeyResponse("操作失败", null, error);
}
}

View File

@@ -0,0 +1,179 @@
package com.mosquito.project.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 统一API响应格式
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ApiResponse<T> {
/**
* HTTP状态码
*/
private int code;
/**
* 响应消息
*/
private String message;
/**
* 响应数据
*/
private T data;
/**
* 元数据(分页等信息)
*/
private Meta meta;
/**
* 错误信息
*/
private Error error;
/**
* 时间戳
*/
private LocalDateTime timestamp;
/**
* 请求追踪ID
*/
private String traceId;
public static <T> ApiResponse<T> success(T data) {
return ApiResponse.<T>builder()
.code(200)
.message("success")
.data(data)
.timestamp(LocalDateTime.now())
.build();
}
public static <T> ApiResponse<T> success(T data, String message) {
return ApiResponse.<T>builder()
.code(200)
.message(message)
.data(data)
.timestamp(LocalDateTime.now())
.build();
}
public static <T> ApiResponse<T> paginated(T data, int page, int size, long total) {
Meta meta = Meta.createPagination(page, size, total);
return ApiResponse.<T>builder()
.code(200)
.message("success")
.data(data)
.meta(meta)
.timestamp(LocalDateTime.now())
.build();
}
public static <T> ApiResponse<T> error(int code, String message) {
return ApiResponse.<T>builder()
.code(code)
.message(message)
.timestamp(LocalDateTime.now())
.error(new Error(message))
.build();
}
public static <T> ApiResponse<T> error(int code, String message, Object details) {
return ApiResponse.<T>builder()
.code(code)
.message(message)
.timestamp(LocalDateTime.now())
.error(new Error(message, details))
.build();
}
public static <T> ApiResponse<T> error(int code, String message, Object details, String traceId) {
return ApiResponse.<T>builder()
.code(code)
.message(message)
.timestamp(LocalDateTime.now())
.error(new Error(message, details))
.traceId(traceId)
.build();
}
/**
* 元数据基类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Meta {
private PaginationMeta pagination;
private Map<String, Object> extra;
public static Meta createPagination(int page, int size, long total) {
Meta meta = new Meta();
meta.setPagination(PaginationMeta.of(page, size, total));
return meta;
}
}
/**
* 分页元数据
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PaginationMeta {
private int page;
private int size;
private long total;
private int totalPages;
private boolean hasNext;
private boolean hasPrevious;
public static PaginationMeta of(int page, int size, long total) {
int totalPages = (int) Math.ceil((double) total / size);
boolean hasNext = page < totalPages - 1;
boolean hasPrevious = page > 0;
return new PaginationMeta(page, size, total, totalPages, hasNext, hasPrevious);
}
}
/**
* 错误信息
*/
@Data
@NoArgsConstructor
public static class Error {
private String message;
private Object details;
private String code;
public Error(String message) {
this.message = message;
}
public Error(String message, Object details) {
this.message = message;
this.details = details;
}
public Error(String message, Object details, String code) {
this.message = message;
this.details = details;
this.code = code;
}
}
}

View File

@@ -1,5 +1,8 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class CreateApiKeyResponse {
private String apiKey;

View File

@@ -0,0 +1,43 @@
package com.mosquito.project.dto;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.HashMap;
public class ErrorResponse {
private OffsetDateTime timestamp;
private String status;
private String error;
private String message;
private String path;
private Map<String, Object> details;
private String traceId;
public ErrorResponse() {}
public ErrorResponse(OffsetDateTime timestamp, String path, String code, String message, Map<String, String> errors) {
this.timestamp = timestamp;
this.path = path;
this.status = code;
this.message = message;
if (errors != null) {
this.details = new HashMap<>(errors);
}
}
public OffsetDateTime getTimestamp() { return timestamp; }
public void setTimestamp(OffsetDateTime timestamp) { this.timestamp = timestamp; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getError() { return error; }
public void setError(String error) { this.error = error; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public Map<String, Object> getDetails() { return details; }
public void setDetails(Map<String, Object> details) { this.details = details; }
public String getTraceId() { return traceId; }
public void setTraceId(String traceId) { this.traceId = traceId; }
}

View File

@@ -0,0 +1,18 @@
package com.mosquito.project.dto;
import jakarta.validation.constraints.NotBlank;
public class RegisterCallbackRequest {
@NotBlank
private String trackingId;
private String externalUserId;
private Long timestamp;
public String getTrackingId() { return trackingId; }
public void setTrackingId(String trackingId) { this.trackingId = trackingId; }
public String getExternalUserId() { return externalUserId; }
public void setExternalUserId(String externalUserId) { this.externalUserId = externalUserId; }
public Long getTimestamp() { return timestamp; }
public void setTimestamp(Long timestamp) { this.timestamp = timestamp; }
}

View File

@@ -0,0 +1,19 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class RevealApiKeyResponse {
private String apiKey;
private String message;
public RevealApiKeyResponse(String apiKey, String message) {
this.apiKey = apiKey;
this.message = message;
}
public String getApiKey() { return apiKey; }
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
}

View File

@@ -0,0 +1,32 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
import java.time.OffsetDateTime;
import java.util.Map;
@NoArgsConstructor
public class ShareMetricsResponse {
private Long activityId;
private OffsetDateTime startTime;
private OffsetDateTime endTime;
private long totalClicks;
private long uniqueVisitors;
private Map<String, Long> sourceDistribution;
private Map<String, Long> hourlyDistribution;
public Long getActivityId() { return activityId; }
public void setActivityId(Long activityId) { this.activityId = activityId; }
public OffsetDateTime getStartTime() { return startTime; }
public void setStartTime(OffsetDateTime startTime) { this.startTime = startTime; }
public OffsetDateTime getEndTime() { return endTime; }
public void setEndTime(OffsetDateTime endTime) { this.endTime = endTime; }
public long getTotalClicks() { return totalClicks; }
public void setTotalClicks(long totalClicks) { this.totalClicks = totalClicks; }
public long getUniqueVisitors() { return uniqueVisitors; }
public void setUniqueVisitors(long uniqueVisitors) { this.uniqueVisitors = uniqueVisitors; }
public Map<String, Long> getSourceDistribution() { return sourceDistribution; }
public void setSourceDistribution(Map<String, Long> sourceDistribution) { this.sourceDistribution = sourceDistribution; }
public Map<String, Long> getHourlyDistribution() { return hourlyDistribution; }
public void setHourlyDistribution(Map<String, Long> hourlyDistribution) { this.hourlyDistribution = hourlyDistribution; }
}

View File

@@ -0,0 +1,37 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
import java.time.OffsetDateTime;
@NoArgsConstructor
public class ShareTrackingResponse {
private String trackingId;
private String shortCode;
private String originalUrl;
private Long activityId;
private Long inviterUserId;
private OffsetDateTime createdAt;
public ShareTrackingResponse(String trackingId, String shortCode, String originalUrl, Long activityId, Long inviterUserId) {
this.trackingId = trackingId;
this.shortCode = shortCode;
this.originalUrl = originalUrl;
this.activityId = activityId;
this.inviterUserId = inviterUserId;
this.createdAt = OffsetDateTime.now();
}
public String getTrackingId() { return trackingId; }
public void setTrackingId(String trackingId) { this.trackingId = trackingId; }
public String getShortCode() { return shortCode; }
public void setShortCode(String shortCode) { this.shortCode = shortCode; }
public String getOriginalUrl() { return originalUrl; }
public void setOriginalUrl(String originalUrl) { this.originalUrl = originalUrl; }
public Long getActivityId() { return activityId; }
public void setActivityId(Long activityId) { this.activityId = activityId; }
public Long getInviterUserId() { return inviterUserId; }
public void setInviterUserId(Long inviterUserId) { this.inviterUserId = inviterUserId; }
public OffsetDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; }
}

View File

@@ -0,0 +1,14 @@
package com.mosquito.project.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class ShortenRequest {
@NotBlank(message = "原始URL不能为空")
@Size(min = 10, max = 2048, message = "URL长度必须在10-2048个字符之间")
private String originalUrl;
public String getOriginalUrl() { return originalUrl; }
public void setOriginalUrl(String originalUrl) { this.originalUrl = originalUrl; }
}

View File

@@ -0,0 +1,24 @@
package com.mosquito.project.dto;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class ShortenResponse {
private String code;
private String path;
private String originalUrl;
public ShortenResponse(String code, String path, String originalUrl) {
this.code = code;
this.path = path;
this.originalUrl = originalUrl;
}
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public String getOriginalUrl() { return originalUrl; }
public void setOriginalUrl(String originalUrl) { this.originalUrl = originalUrl; }
}

View File

@@ -3,8 +3,11 @@ package com.mosquito.project.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.NoArgsConstructor;
import java.time.ZonedDateTime;
@NoArgsConstructor
public class UpdateActivityRequest {
@NotBlank(message = "活动名称不能为空")

View File

@@ -0,0 +1,17 @@
package com.mosquito.project.dto;
import jakarta.validation.constraints.NotBlank;
public class UseApiKeyRequest {
@NotBlank(message = "API密钥不能为空")
private String apiKey;
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}