# 🛠️ 开发指南

> 版本: 1.0
> 更新时间: 2026-03-04

## 📋 目录

1. [开发环境搭建](#开发环境搭建)
2. [项目结构](#项目结构)
3. [开发规范](#开发规范)
4. [测试指南](#测试指南)
5. [调试技巧](#调试技巧)
6. [贡献指南](#贡献指南)
7. [常见问题](#常见问题)

## 🚀 开发环境搭建

### 前置要求

| 工具 | 版本 | 说明 |
|------|------|------|
| JDK | 17+ | 推荐使用OpenJDK 17或21 |
| Maven | 3.8+ | 构建工具 |
| PostgreSQL | 12+ | 数据库 |
| Redis | 6.0+ | 缓存（可选，开发环境可用内存模式） |
| Git | 2.30+ | 版本控制 |
| IDE | - | 推荐IntelliJ IDEA或VS Code |

### 1. 克隆项目

```bash
git clone https://github.com/your-org/mosquito.git
cd mosquito
```

### 2. 安装依赖

```bash
# 安装PostgreSQL（Ubuntu/Debian）
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

# 安装Redis（可选）
sudo apt-get install redis-server

# 或使用Docker
docker run -d --name mosquito-postgres -e POSTGRES_PASSWORD=dev_password -p 5432:5432 postgres:15
docker run -d --name mosquito-redis -p 6379:6379 redis:7-alpine
```

### 3. 配置数据库

```bash
# 创建数据库
sudo -u postgres psql -c "CREATE DATABASE mosquito_dev;"
sudo -u postgres psql -c "CREATE USER mosquito WITH PASSWORD 'dev_password';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE mosquito_dev TO mosquito;"
```

### 4. 配置开发环境

复制配置模板：

```bash
cp src/main/resources/application-dev.yml.example src/main/resources/application-dev.yml
```

编辑 `application-dev.yml`：

```yaml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mosquito_dev
    username: mosquito
    password: dev_password

  data:
    redis:
      host: localhost
      port: 6379

app:
  api-key:
    encryption-key: dev_32_char_encryption_key_12
```

### 5. 构建项目

```bash
# 编译项目
mvn clean compile

# 运行测试
mvn test

# 打包
mvn package
```

### 6. 启动应用

```bash
# 使用Maven
mvn spring-boot:run -Dspring-boot.run.profiles=dev

# 或使用JAR
java -jar target/mosquito-1.0.0.jar --spring.profiles.active=dev
```

访问 `http://localhost:8080/actuator/health` 验证启动成功。

### 7. 工作区定期清理

为避免构建产物和测试产物污染仓库，建议在本地定期执行以下命令：

```bash
# 只检查（发现 target/frontend/*/dist 或测试产物即返回非零）
npm run clean:workspace:check

# 归档清理（将产物移动到 /tmp/mosquito-archives/<tag>）
npm run clean:workspace:apply

# 历史日志归档（保留最近 1 天）
npm run logs:health:check
npm run logs:archive:check
npm run logs:archive:apply
npm run logs:archive:index
```

说明：
- `clean:workspace:check` 对应 `scripts/ci/clean-artifacts.sh --include-build-outputs --fail-on-found`。
- `clean:workspace:apply` 默认使用归档模式，不直接删除文件，便于回溯。
- `logs:health:check` 对应 `scripts/ci/logs-health-check.sh`，用于输出日志体积和历史候选文件数量（仅告警，不阻断）。
- `logs:archive:*` 对应 `scripts/ci/archive-logs.sh`，将按时间戳命名的历史运行日志移动到 `logs/archive/<tag>/`。
- `logs:archive:index` 对应 `scripts/ci/update-log-archive-index.sh`，用于刷新 `logs/archive/README.md` 索引。
- 若本地正在运行 `spring-boot:run`、`vite` 或 `scripts/e2e_continuous_runner.sh`，`target` 与 `frontend/e2e/*` 可能被立即重建。建议先停止后台进程再执行清理。

### 8. IDE配置

**IntelliJ IDEA：**

1. 导入项目：`File > Open` 选择项目根目录
2. 配置JDK：`File > Project Structure > Project SDK` 选择JDK 17
3. 启用注解处理：`Settings > Build > Compiler > Annotation Processors` 勾选 `Enable annotation processing`
4. 配置运行配置：
   - `Run > Edit Configurations`
   - 添加 `Spring Boot` 配置
   - Main class: `com.mosquito.project.MosquitoApplication`
   - Active profiles: `dev`

**VS Code：**

安装扩展：
- Extension Pack for Java
- Spring Boot Extension Pack
- Lombok Annotations Support

配置 `.vscode/launch.json`：

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "java",
      "name": "Spring Boot-MosquitoApplication",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "mainClass": "com.mosquito.project.MosquitoApplication",
      "projectName": "mosquito",
      "args": "--spring.profiles.active=dev",
      "envFile": "${workspaceFolder}/.env"
    }
  ]
}
```

## 📁 项目结构

```
mosquito/
├── src/
│   ├── main/
│   │   ├── java/com/mosquito/project/
│   │   │   ├── config/              # 配置类
│   │   │   │   ├── CacheConfig.java
│   │   │   │   ├── OpenApiConfig.java
│   │   │   │   └── WebMvcConfig.java
│   │   │   ├── controller/          # REST控制器
│   │   │   │   ├── ActivityController.java
│   │   │   │   ├── ApiKeyController.java
│   │   │   │   ├── ShareTrackingController.java
│   │   │   │   └── UserExperienceController.java
│   │   │   ├── dto/                 # 数据传输对象
│   │   │   │   ├── ApiResponse.java
│   │   │   │   ├── CreateActivityRequest.java
│   │   │   │   └── ActivityStatsResponse.java
│   │   │   ├── exception/           # 异常处理
│   │   │   │   ├── GlobalExceptionHandler.java
│   │   │   │   ├── BusinessException.java
│   │   │   │   └── ResourceNotFoundException.java
│   │   │   ├── persistence/         # 持久层
│   │   │   │   ├── entity/          # JPA实体
│   │   │   │   └── repository/      # JPA仓库
│   │   │   ├── service/             # 业务逻辑
│   │   │   │   ├── ActivityService.java
│   │   │   │   ├── ShortLinkService.java
│   │   │   │   └── ShareTrackingService.java
│   │   │   ├── security/            # 安全相关
│   │   │   │   └── UserIntrospectionService.java
│   │   │   ├── web/                 # Web层（拦截器等）
│   │   │   │   ├── ApiKeyAuthInterceptor.java
│   │   │   │   └── RateLimitInterceptor.java
│   │   │   └── MosquitoApplication.java
│   │   └── resources/
│   │       ├── db/migration/        # Flyway迁移脚本
│   │       ├── application.properties
│   │       ├── application-dev.yml
│   │       └── logback-spring.xml
│   └── test/
│       └── java/com/mosquito/project/
│           ├── controller/          # 控制器测试
│           ├── service/             # 服务测试
│           ├── integration/         # 集成测试
│           └── config/              # 测试配置
├── docs/                            # 文档
│   ├── api.md
│   ├── PRD.md
│   └── data-model.md
├── pom.xml
└── README.md
```

### 分层架构

```
┌─────────────────────────────────────┐
│         Controller Layer            │  REST API端点
│  (ActivityController, etc.)         │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│          Service Layer               │  业务逻辑
│  (ActivityService, etc.)             │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│       Repository Layer               │  数据访问
│  (JPA Repositories)                  │
└─────────────┬───────────────────────┘
              │
┌─────────────▼───────────────────────┐
│         Database Layer               │  PostgreSQL + Redis
└──────────────────────────────────────┘
```

## 📝 开发规范

### 代码风格

**Java代码规范：**

- 遵循Google Java Style Guide
- 使用4个空格缩进
- 类名使用PascalCase
- 方法名和变量名使用camelCase
- 常量使用UPPER_SNAKE_CASE

**示例：**

```java
public class ActivityService {
    private static final int DEFAULT_PAGE_SIZE = 20;

    private final ActivityRepository activityRepository;

    public ActivityService(ActivityRepository activityRepository) {
        this.activityRepository = activityRepository;
    }

    public Activity createActivity(CreateActivityRequest request) {
        // 实现逻辑
    }
}
```

### 命名规范

**Controller：**
- 类名：`XxxController`
- 方法名：动词开头，如 `createActivity`, `getActivity`, `updateActivity`

**Service：**
- 类名：`XxxService`
- 方法名：业务动作，如 `create`, `findById`, `update`, `delete`

**Repository：**
- 类名：`XxxRepository`
- 方法名：遵循Spring Data JPA规范，如 `findByActivityId`, `existsByCode`

**DTO：**
- 请求：`XxxRequest`
- 响应：`XxxResponse`
- 通用：`XxxDto`

### 注释规范

**类注释：**

```java
/**
 * 活动管理服务
 *
 * 提供活动的创建、查询、更新和删除功能
 *
 * @author Your Name
 * @since 1.0.0
 */
public class ActivityService {
}
```

**方法注释：**

```java
/**
 * 创建新活动
 *
 * @param request 活动创建请求
 * @return 创建的活动实体
 * @throws BusinessException 当活动名称重复时
 */
public Activity createActivity(CreateActivityRequest request) {
}
```

### Git提交规范

遵循Conventional Commits规范：

```
<type>(<scope>): <subject>

<body>

<footer>
```

**类型（type）：**
- `feat`: 新功能
- `fix`: 修复bug
- `docs`: 文档更新
- `style`: 代码格式调整
- `refactor`: 重构
- `test`: 测试相关
- `chore`: 构建/工具相关

**示例：**

```bash
feat(activity): add activity leaderboard endpoint

- Implement leaderboard query with pagination
- Add caching for leaderboard results
- Add integration tests

Closes #123
```

### API设计规范

**RESTful风格：**

```
GET    /api/v1/activities          # 获取活动列表
POST   /api/v1/activities          # 创建活动
GET    /api/v1/activities/{id}     # 获取单个活动
PUT    /api/v1/activities/{id}     # 更新活动
DELETE /api/v1/activities/{id}     # 删除活动
```

**统一响应格式：**

```json
{
  "code": 200,
  "message": "Success",
  "data": { ... },
  "timestamp": "2026-03-04T10:00:00Z"
}
```

**错误响应：**

```json
{
  "code": 400,
  "message": "Invalid request",
  "error": {
    "code": "VALIDATION_ERROR",
    "details": {
      "name": "Activity name is required"
    }
  },
  "timestamp": "2026-03-04T10:00:00Z"
}
```

## 🧪 测试指南

### 测试分层

```
测试金字塔：
    ┌─────────┐
    │   E2E   │  10% - 端到端测试
    ├─────────┤
    │  集成测试 │  30% - 集成测试
    ├─────────┤
    │  单元测试 │  60% - 单元测试
    └─────────┘
```

### 单元测试

**Service层测试：**

```java
@ExtendWith(MockitoExtension.class)
class ActivityServiceTest {

    @Mock
    private ActivityRepository activityRepository;

    @InjectMocks
    private ActivityService activityService;

    @Test
    @DisplayName("应成功创建活动")
    void shouldCreateActivity_whenValidRequest() {
        // Given
        CreateActivityRequest request = new CreateActivityRequest();
        request.setName("春季活动");

        ActivityEntity entity = new ActivityEntity();
        entity.setId(1L);
        entity.setName("春季活动");

        when(activityRepository.save(any())).thenReturn(entity);

        // When
        Activity result = activityService.create(request);

        // Then
        assertThat(result.getId()).isEqualTo(1L);
        assertThat(result.getName()).isEqualTo("春季活动");
        verify(activityRepository).save(any());
    }
}
```

### 集成测试

**Controller集成测试：**

```java
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class ActivityControllerIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ActivityRepository activityRepository;

    @BeforeEach
    void setUp() {
        activityRepository.deleteAll();
    }

    @Test
    @DisplayName("应成功创建活动并返回201")
    void shouldCreateActivity() throws Exception {
        String requestBody = """
            {
              "name": "春季活动",
              "startTime": "2025-03-01T10:00:00+08:00",
              "endTime": "2025-03-31T23:59:59+08:00"
            }
            """;

        mockMvc.perform(post("/api/v1/activities")
                .contentType(MediaType.APPLICATION_JSON)
                .header("X-API-Key", "test-key")
                .content(requestBody))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.code").value(201))
            .andExpect(jsonPath("$.data.name").value("春季活动"));
    }
}
```

### 运行测试

```bash
# 运行所有测试
mvn test

# 运行单个测试类
mvn test -Dtest=ActivityServiceTest

# 运行单个测试方法
mvn test -Dtest=ActivityServiceTest#shouldCreateActivity_whenValidRequest

# 生成覆盖率报告
mvn clean test jacoco:report

# 查看覆盖率报告
open target/site/jacoco/index.html
```

### 测试覆盖率目标

| 指标 | 目标 | 当前 |
|------|------|------|
| 指令覆盖率 | ≥80% | 87% ✅ |
| 分支覆盖率 | ≥70% | 66% 🟡 |
| 行覆盖率 | ≥90% | 93% ✅ |

## 🐛 调试技巧

### 日志调试

**启用调试日志：**

```yaml
logging:
  level:
    com.mosquito.project: DEBUG
    org.springframework.web: DEBUG
    org.hibernate.SQL: DEBUG
```

**使用SLF4J日志：**

```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ActivityService {
    private static final Logger log = LoggerFactory.getLogger(ActivityService.class);

    public Activity create(CreateActivityRequest request) {
        log.debug("Creating activity: {}", request.getName());
        // ...
        log.info("Activity created: id={}", activity.getId());
        return activity;
    }
}
```

### 远程调试

**启动应用时启用远程调试：**

```bash
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 \
  -jar target/mosquito-1.0.0.jar
```

**IntelliJ IDEA配置：**
1. `Run > Edit Configurations`
2. 添加 `Remote JVM Debug`
3. Host: `localhost`, Port: `5005`
4. 点击Debug按钮连接

### 数据库调试

**查看SQL语句：**

```yaml
spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
```

**使用H2 Console（测试环境）：**

```yaml
spring:
  h2:
    console:
      enabled: true
      path: /h2-console
```

访问 `http://localhost:8080/h2-console`

### Redis调试

**使用Redis CLI：**

```bash
# 连接Redis
redis-cli

# 查看所有键
KEYS *

# 查看键值
GET rate_limit:api_key_123

# 查看TTL
TTL rate_limit:api_key_123

# 清空缓存
FLUSHDB
```

## 🤝 贡献指南

### 开发流程

1. **Fork项目**

```bash
# Fork到你的GitHub账号
# 克隆你的Fork
git clone https://github.com/your-username/mosquito.git
cd mosquito
git remote add upstream https://github.com/your-org/mosquito.git
```

2. **创建功能分支**

```bash
git checkout -b feature/add-leaderboard
```

3. **开发功能**

- 编写代码
- 添加测试
- 更新文档

4. **提交代码**

```bash
git add .
git commit -m "feat(activity): add leaderboard endpoint"
```

5. **同步上游**

```bash
git fetch upstream
git rebase upstream/main
```

6. **推送分支**

```bash
git push origin feature/add-leaderboard
```

7. **创建Pull Request**

- 访问GitHub仓库
- 点击 "New Pull Request"
- 填写PR描述
- 等待代码审查

### Pull Request检查清单

- [ ] 代码遵循项目规范
- [ ] 添加了单元测试
- [ ] 添加了集成测试
- [ ] 测试覆盖率不降低
- [ ] 更新了相关文档
- [ ] 通过了CI/CD检查
- [ ] 代码已经过自我审查
- [ ] 提交信息遵循规范

### 代码审查标准

**必须检查：**
- 功能是否正确实现
- 是否有安全漏洞
- 是否有性能问题
- 测试是否充分
- 代码是否可维护

**建议检查：**
- 命名是否清晰
- 注释是否充分
- 是否有重复代码
- 是否可以简化

## ❓ 常见问题

### Q1: 数据库连接失败

**问题：** `Connection refused: connect`

**解决：**
```bash
# 检查PostgreSQL是否运行
sudo systemctl status postgresql

# 启动PostgreSQL
sudo systemctl start postgresql

# 检查连接
psql -U mosquito -h localhost -d mosquito_dev
```

### Q2: Redis连接失败

**问题：** `Unable to connect to Redis`

**解决：**
```bash
# 检查Redis是否运行
sudo systemctl status redis

# 启动Redis
sudo systemctl start redis

# 测试连接
redis-cli ping
```

### Q3: 测试失败

**问题：** `TestContainers: Could not find a valid Docker environment`

**解决：**
```bash
# 安装Docker
sudo apt-get install docker.io

# 启动Docker
sudo systemctl start docker

# 添加用户到docker组
sudo usermod -aG docker $USER
```

### Q4: 端口被占用

**问题：** `Port 8080 is already in use`

**解决：**
```bash
# 查找占用端口的进程
lsof -i :8080

# 杀死进程
kill -9 <PID>

# 或使用其他端口
java -jar target/mosquito-1.0.0.jar --server.port=8081
```

### Q5: Flyway迁移失败

**问题：** `Flyway migration failed`

**解决：**
```bash
# 查看迁移状态
mvn flyway:info

# 修复失败的迁移
mvn flyway:repair

# 清空数据库重新迁移（仅开发环境）
mvn flyway:clean flyway:migrate
```

## 📚 相关资源

- [部署指南](./DEPLOYMENT_GUIDE.md) - 部署说明
- [配置指南](./CONFIGURATION_GUIDE.md) - 配置选项
- [API文档](./api.md) - API接口文档
- [API集成指南](./API_INTEGRATION_GUIDE.md) - API集成示例

---

**文档版本**: 1.0
**最后更新**: 2026-03-04
