# Multi-Module Architecture Refactor Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** 将 novalon-manage-api 从单体模块重构为网关 + 单体多模块架构，实现模块化、统一认证授权、独立部署和性能优化。

**Architecture:** 采用网关（manage-gateway）+ 应用层（manage-app）+ 业务模块（manage-sys、manage-audit、manage-notify、manage-file）+ 公共模块（manage-common、manage-db）的分层架构。网关统一处理JWT认证、RBAC权限和限流熔断，应用层聚合所有业务模块，通过Caffeine缓存优化性能，使用Docker容器化部署。

**Tech Stack:** Java 21, Spring Boot 3.4.1, Spring WebFlux, Spring Security, R2DBC, PostgreSQL, JWT, Caffeine, Docker, Maven

---

## Phase 1: Preparation (1-2 days)

### Task 1: Create manage-gateway module structure

**Files:**
- Create: `novalon-manage-api/manage-gateway/pom.xml`
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/GatewayApplication.java`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application.yml`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application-dev.yml`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application-prod.yml`
- Create: `novalon-manage-api/manage-gateway/Dockerfile`

**Step 1: Create manage-gateway pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-gateway</artifactId>
    <packaging>jar</packaging>

    <name>Manage Gateway</name>
    <description>Gateway module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>cn.novalon.manage.gateway.GatewayApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Create GatewayApplication.java**

```java
package cn.novalon.manage.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("manage-app", r -> r
                        .path("/api/**")
                        .uri("http://manage-app:8081"))
                .build();
    }
}
```

**Step 3: Create application.yml**

```yaml
server:
  port: 8080

spring:
  application:
    name: manage-gateway
  cloud:
    gateway:
      routes:
        - id: manage-app
          uri: http://manage-app:8081
          predicates:
            - Path=/api/**
      default-filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics
      base-path: /actuator
  endpoint:
    health:
      show-details: always
  metrics:
    tags:
      application: ${spring.application.name}

logging:
  level:
    cn.novalon.manage: DEBUG
    org.springframework.cloud.gateway: DEBUG
```

**Step 4: Create Dockerfile**

```dockerfile
FROM openjdk:21-jdk-slim

WORKDIR /app

COPY manage-gateway/target/manage-gateway-1.0.0.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]
```

**Step 5: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway -am`

Expected: BUILD SUCCESS

**Step 6: Commit**

```bash
git add novalon-manage-api/manage-gateway/
git commit -m "feat: create manage-gateway module structure"
```

---

### Task 2: Create manage-app module structure

**Files:**
- Create: `novalon-manage-api/manage-app/pom.xml`
- Create: `novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/ManageApplication.java`
- Create: `novalon-manage-api/manage-app/src/main/resources/application.yml`
- Create: `novalon-manage-api/manage-app/src/main/resources/application-dev.yml`
- Create: `novalon-manage-api/manage-app/src/main/resources/application-prod.yml`
- Create: `novalon-manage-api/manage-app/Dockerfile`

**Step 1: Create manage-app pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-app</artifactId>
    <packaging>jar</packaging>

    <name>Manage App</name>
    <description>Application module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-sys</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-audit</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-notify</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-file</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-db</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>r2dbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-database-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>cn.novalon.manage.app.ManageApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Create ManageApplication.java**

```java
package cn.novalon.manage.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = "cn.novalon.manage")
@ComponentScan(basePackages = "cn.novalon.manage")
public class ManageApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManageApplication.class, args);
    }
}
```

**Step 3: Create application.yml**

```yaml
server:
  port: 8081

spring:
  application:
    name: manage-app
  r2dbc:
    url: r2dbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:novalon_manage}
    username: ${DB_USERNAME:postgres}
    password: ${DB_PASSWORD:postgres}
    pool:
      initial-size: 10
      max-size: 50
      max-idle-time: 30m
      max-life-time: 1h
      acquire-timeout: 5s
  flyway:
    enabled: true
    locations: classpath:db/migration

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env,loggers
      base-path: /actuator
  endpoint:
    health:
      show-details: always
  metrics:
    tags:
      application: ${spring.application.name}
      environment: ${spring.profiles.active}

logging:
  level:
    cn.novalon.manage: DEBUG
    org.springframework.r2dbc: DEBUG
```

**Step 4: Create Dockerfile**

```dockerfile
FROM openjdk:21-jdk-slim

WORKDIR /app

COPY manage-app/target/manage-app-1.0.0.jar app.jar

EXPOSE 8081

ENTRYPOINT ["java", "-jar", "app.jar"]
```

**Step 5: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-app -am`

Expected: BUILD SUCCESS

**Step 6: Commit**

```bash
git add novalon-manage-api/manage-app/
git commit -m "feat: create manage-app module structure"
```

---

### Task 3: Create manage-common module structure

**Files:**
- Create: `novalon-manage-api/manage-common/pom.xml`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/filter/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/exception/`

**Step 1: Create manage-common pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-common</artifactId>
    <packaging>jar</packaging>

    <name>Manage Common</name>
    <description>Common module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Create package structure**

Run: `mkdir -p novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/{util,config,filter,exception,dto}`

Expected: Directories created successfully

**Step 3: Create common exception classes**

Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/exception/BusinessException.java`

```java
package cn.novalon.manage.common.exception;

public class BusinessException extends RuntimeException {

    private final String code;
    private final String message;

    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    @Override
    public String getMessage() {
        return message;
    }
}
```

**Step 4: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-common -am`

Expected: BUILD SUCCESS

**Step 5: Commit**

```bash
git add novalon-manage-api/manage-common/
git commit -m "feat: create manage-common module structure"
```

---

### Task 4: Create manage-db module structure

**Files:**
- Create: `novalon-manage-api/manage-db/pom.xml`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`
- Create: `novalon-manage-api/manage-db/src/main/resources/db/migration/`

**Step 1: Create manage-db pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-db</artifactId>
    <packaging>jar</packaging>

    <name>Manage DB</name>
    <description>Database module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>r2dbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-database-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.5.5.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.5.5.Final</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Copy migration scripts**

Run: `cp -r novalon-manage-api/manage-sys/src/main/resources/db/migration/* novalon-manage-api/manage-db/src/main/resources/db/migration/`

Expected: Migration scripts copied successfully

**Step 3: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-db -am`

Expected: BUILD SUCCESS

**Step 4: Commit**

```bash
git add novalon-manage-api/manage-db/
git commit -m "feat: create manage-db module structure"
```

---

### Task 5: Create manage-audit module structure

**Files:**
- Create: `novalon-manage-api/manage-audit/pom.xml`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/dto/`

**Step 1: Create manage-audit pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-audit</artifactId>
    <packaging>jar</packaging>

    <name>Manage Audit</name>
    <description>Audit module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-db</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-audit -am`

Expected: BUILD SUCCESS

**Step 3: Commit**

```bash
git add novalon-manage-api/manage-audit/
git commit -m "feat: create manage-audit module structure"
```

---

### Task 6: Create manage-notify module structure

**Files:**
- Create: `novalon-manage-api/manage-notify/pom.xml`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`

**Step 1: Create manage-notify pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-notify</artifactId>
    <packaging>jar</packaging>

    <name>Manage Notify</name>
    <description>Notify module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-db</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-notify -am`

Expected: BUILD SUCCESS

**Step 3: Commit**

```bash
git add novalon-manage-api/manage-notify/
git commit -m "feat: create manage-notify module structure"
```

---

### Task 7: Create manage-file module structure

**Files:**
- Create: `novalon-manage-api/manage-file/pom.xml`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`

**Step 1: Create manage-file pom.xml**

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>novalon-manage-api</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>manage-file</artifactId>
    <packaging>jar</packaging>

    <name>Manage File</name>
    <description>File module for Novalon Manage API</description>

    <dependencies>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-db</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>cn.novalon.manage</groupId>
            <artifactId>manage-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
```

**Step 2: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-file -am`

Expected: BUILD SUCCESS

**Step 3: Commit**

```bash
git add novalon-manage-api/manage-file/
git commit -m "feat: create manage-file module structure"
```

---

### Task 8: Update parent pom.xml with new modules

**Files:**
- Modify: `novalon-manage-api/pom.xml`

**Step 1: Update modules section**

Read: `novalon-manage-api/pom.xml`

Find: `<modules>` section and replace with:

```xml
<modules>
    <module>manage-gateway</module>
    <module>manage-app</module>
    <module>manage-sys</module>
    <module>manage-audit</module>
    <module>manage-notify</module>
    <module>manage-file</module>
    <module>manage-common</module>
    <module>manage-db</module>
</modules>
```

**Step 2: Verify build**

Run: `cd novalon-manage-api && mvn clean compile`

Expected: BUILD SUCCESS

**Step 3: Commit**

```bash
git add novalon-manage-api/pom.xml
git commit -m "feat: update parent pom.xml with new modules"
```

---

## Phase 2: Module Extraction (3-5 days)

### Task 9: Extract common utilities to manage-common

**Files:**
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/SnowflakeId.java`
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/JwtProperties.java`

**Step 1: Move SnowflakeId to manage-common**

Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`

Copy content to: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/SnowflakeId.java`

Update package declaration: `package cn.novalon.manage.common.util;`

**Step 2: Move JwtProperties to manage-common**

Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`

Copy content to: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/JwtProperties.java`

Update package declaration: `package cn.novalon.manage.common.config;`

**Step 3: Update manage-sys imports**

Find all files in manage-sys that import SnowflakeId or JwtProperties and update imports:

```bash
cd novalon-manage-api/manage-sys
find src -name "*.java" -exec grep -l "SnowflakeId\|JwtProperties" {} \;
```

Update imports from:
- `import cn.novalon.manage.sys.utils.SnowflakeId;` to `import cn.novalon.manage.common.util.SnowflakeId;`
- `import cn.novalon.manage.sys.config.JwtProperties;` to `import cn.novalon.manage.common.config.JwtProperties;`

**Step 4: Remove old files from manage-sys**

Run: `rm novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`

Run: `rm novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`

**Step 5: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile`

Expected: BUILD SUCCESS

**Step 6: Commit**

```bash
git add novalon-manage-api/manage-common/ novalon-manage-api/manage-sys/
git commit -m "refactor: extract common utilities to manage-common"
```

---

### Task 10: Extract database entities to manage-db

**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/*` to `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/repository/*` to `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`

**Step 1: Move entity classes**

Run: `mkdir -p novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/* novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`

**Step 2: Update entity package declarations**

For each entity file in manage-db/entity, update package declaration:

From: `package cn.novalon.manage.sys.infrastructure.db.entity;`
To: `package cn.novalon.manage.db.entity;`

**Step 3: Move repository interfaces**

Run: `mkdir -p novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/repository/* novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`

**Step 4: Update repository package declarations**

For each repository file in manage-db/repository, update package declaration:

From: `package cn.novalon.manage.sys.infrastructure.db.repository;`
To: `package cn.novalon.manage.db.repository;`

**Step 5: Update imports in manage-sys**

Find all files in manage-sys that import entities or repositories and update imports:

```bash
cd novalon-manage-api/manage-sys
find src -name "*.java" -exec grep -l "cn.novalon.manage.sys.infrastructure.db" {} \;
```

Update imports from:
- `import cn.novalon.manage.sys.infrastructure.db.entity.*;` to `import cn.novalon.manage.db.entity.*;`
- `import cn.novalon.manage.sys.infrastructure.db.repository.*;` to `import cn.novalon.manage.db.repository.*;`

**Step 6: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile`

Expected: BUILD SUCCESS

**Step 7: Commit**

```bash
git add novalon-manage-api/manage-db/ novalon-manage-api/manage-sys/
git commit -m "refactor: extract database entities to manage-db"
```

---

### Task 11: Refactor manage-sys module

**Files:**
- Modify: `novalon-manage-api/manage-sys/pom.xml`
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/ManageSysApplication.java`

**Step 1: Update manage-sys pom.xml dependencies**

Read: `novalon-manage-api/manage-sys/pom.xml`

Replace dependencies section with:

```xml
<dependencies>
    <dependency>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>manage-db</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>cn.novalon.manage</groupId>
        <artifactId>manage-common</artifactId>
        <version>${project.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
```

**Step 2: Update ManageSysApplication.java**

Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/ManageSysApplication.java`

Update package scan to include new packages:

```java
package cn.novalon.manage.sys;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = "cn.novalon.manage")
@ComponentScan(basePackages = "cn.novalon.manage")
public class ManageSysApplication {

    public static void main(String[] args) {
        SpringApplication.run(ManageSysApplication.class, args);
    }
}
```

**Step 3: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-sys -am`

Expected: BUILD SUCCESS

**Step 4: Commit**

```bash
git add novalon-manage-api/manage-sys/
git commit -m "refactor: update manage-sys module dependencies"
```

---

### Task 12: Migrate audit functionality to manage-audit

**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/log/SysLogHandler.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/OperationLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysLoginLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysExceptionLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`

**Step 1: Move audit handlers**

Run: `mkdir -p novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/log/SysLogHandler.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`

**Step 2: Move audit services**

Run: `mkdir -p novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/OperationLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysLoginLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysExceptionLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`

**Step 3: Update package declarations**

For each moved file, update package declaration:

From: `package cn.novalon.manage.sys.handler.log;` to `package cn.novalon.manage.audit.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.audit.service.impl;`

**Step 4: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-audit -am`

Expected: BUILD SUCCESS

**Step 5: Commit**

```bash
git add novalon-manage-api/manage-audit/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate audit functionality to manage-audit"
```

---

### Task 13: Migrate notify functionality to manage-notify

**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/notice/SysNoticeHandler.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/message/SysUserMessageHandler.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysNoticeService.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysUserMessageService.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/WebSocketServiceImpl.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/WebSocketConfig.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`

**Step 1: Move notify handlers**

Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/notice/SysNoticeHandler.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/message/SysUserMessageHandler.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`

**Step 2: Move notify services**

Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysNoticeService.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysUserMessageService.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/WebSocketServiceImpl.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`

**Step 3: Move notify config**

Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/WebSocketConfig.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`

**Step 4: Update package declarations**

For each moved file, update package declaration:

From: `package cn.novalon.manage.sys.handler.notice;` to `package cn.novalon.manage.notify.handler;`
From: `package cn.novalon.manage.sys.handler.message;` to `package cn.novalon.manage.notify.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.notify.service.impl;`
From: `package cn.novalon.manage.sys.config;` to `package cn.novalon.manage.notify.config;`

**Step 5: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-notify -am`

Expected: BUILD SUCCESS

**Step 6: Commit**

```bash
git add novalon-manage-api/manage-notify/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate notify functionality to manage-notify"
```

---

### Task 14: Migrate file functionality to manage-file

**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/MultipartConfig.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`

**Step 1: Move file handler**

Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`

**Step 2: Move file service**

Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl/`

**Step 3: Move file config**

Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config`

Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/MultipartConfig.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`

**Step 4: Update package declarations**

For each moved file, update package declaration:

From: `package cn.novalon.manage.sys.handler.file;` to `package cn.novalon.manage.file.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.file.service.impl;`
From: `package cn.novalon.manage.sys.config;` to `package cn.novalon.manage.file.config;`

**Step 5: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-file -am`

Expected: BUILD SUCCESS

**Step 6: Commit**

```bash
git add novalon-manage-api/manage-file/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate file functionality to manage-file"
```

---

## Phase 3: Gateway and Application Layer (2-3 days)

### Task 15: Implement JWT authentication filter in manage-gateway

**Files:**
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/JwtAuthenticationFilter.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/JwtTokenProvider.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/dto/JwtUser.java`

**Step 1: Create JwtUser DTO**

Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/dto/JwtUser.java`

```java
package cn.novalon.manage.common.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class JwtUser {
    private String userId;
    private String username;
    private List<String> roles;
    private List<String> permissions;
}
```

**Step 2: Create JwtTokenProvider**

Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/JwtTokenProvider.java`

```java
package cn.novalon.manage.common.util;

import cn.novalon.manage.common.config.JwtProperties;
import cn.novalon.manage.common.dto.JwtUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.List;

@Component
public class JwtTokenProvider {

    private final JwtProperties jwtProperties;
    private final SecretKey key;

    public JwtTokenProvider(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
        this.key = Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes());
    }

    public String generateToken(JwtUser user) {
        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtProperties.getExpiration() * 1000);

        return Jwts.builder()
                .subject(user.getUserId())
                .claim("username", user.getUsername())
                .claim("roles", user.getRoles())
                .claim("permissions", user.getPermissions())
                .issuedAt(now)
                .expiration(expiryDate)
                .signWith(key)
                .compact();
    }

    public JwtUser parseToken(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();

        JwtUser user = new JwtUser();
        user.setUserId(claims.getSubject());
        user.setUsername(claims.get("username", String.class));
        user.setRoles(claims.get("roles", List.class));
        user.setPermissions(claims.get("permissions", List.class));

        return user;
    }

    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
```

**Step 3: Create JwtAuthenticationFilter**

Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/JwtAuthenticationFilter.java`

```java
package cn.novalon.manage.gateway.filter;

import cn.novalon.manage.common.dto.JwtUser;
import cn.novalon.manage.common.util.JwtTokenProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAuthenticationFilter.Config> {

    private final JwtTokenProvider jwtTokenProvider;

    public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
        super(Config.class);
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getPath().value();

            if (isPublicPath(path)) {
                return chain.filter(exchange);
            }

            String token = extractToken(request);

            if (token == null || !jwtTokenProvider.validateToken(token)) {
                return unauthorized(exchange.getResponse());
            }

            JwtUser user = jwtTokenProvider.parseToken(token);
            addHeaders(exchange, user);

            return chain.filter(exchange);
        };
    }

    private boolean isPublicPath(String path) {
        return path.startsWith("/api/auth/login") || path.startsWith("/api/auth/register");
    }

    private String extractToken(ServerHttpRequest request) {
        String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }

    private void addHeaders(ServerWebExchange exchange, JwtUser user) {
        ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
                .header("X-User-Id", user.getUserId())
                .header("X-User-Username", user.getUsername())
                .header("X-User-Roles", String.join(",", user.getRoles()))
                .header("X-User-Permissions", String.join(",", user.getPermissions()))
                .build();

        exchange.mutate().request(mutatedRequest).build();
    }

    private Mono<Void> unauthorized(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return response.setComplete();
    }

    public static class Config {
    }
}
```

**Step 4: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway,manage-common -am`

Expected: BUILD SUCCESS

**Step 5: Commit**

```bash
git add novalon-manage-api/manage-gateway/ novalon-manage-api/manage-common/
git commit -m "feat: implement JWT authentication filter in manage-gateway"
```

---

### Task 16: Implement RBAC authorization filter in manage-gateway

**Files:**
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/RbacAuthorizationFilter.java`
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/config/PermissionConfig.java`

**Step 1: Create PermissionConfig**

Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/config/PermissionConfig.java`

```java
package cn.novalon.manage.gateway.config;

import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class PermissionConfig {

    public static final Map<String, String> PATH_PERMISSIONS = new HashMap<>();

    static {
        PATH_PERMISSIONS.put("/api/sys/users", "user:read");
        PATH_PERMISSIONS.put("/api/sys/users/**", "user:write");
        PATH_PERMISSIONS.put("/api/sys/roles", "role:read");
        PATH_PERMISSIONS.put("/api/sys/roles/**", "role:write");
        PATH_PERMISSIONS.put("/api/sys/menus", "menu:read");
        PATH_PERMISSIONS.put("/api/sys/menus/**", "menu:write");
        PATH_PERMISSIONS.put("/api/sys/config", "config:read");
        PATH_PERMISSIONS.put("/api/sys/config/**", "config:write");
        PATH_PERMISSIONS.put("/api/audit/logs", "audit:read");
        PATH_PERMISSIONS.put("/api/notify/notices", "notice:read");
        PATH_PERMISSIONS.put("/api/notify/notices/**", "notice:write");
        PATH_PERMISSIONS.put("/api/file/files", "file:read");
        PATH_PERMISSIONS.put("/api/file/files/**", "file:write");
    }

    public static String getRequiredPermission(String path, String method) {
        String permissionKey = path;
        if (!PATH_PERMISSIONS.containsKey(path)) {
            permissionKey = path.substring(0, path.lastIndexOf('/'));
        }
        return PATH_PERMISSIONS.get(permissionKey);
    }
}
```

**Step 2: Create RbacAuthorizationFilter**

Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/RbacAuthorizationFilter.java`

```java
package cn.novalon.manage.gateway.filter;

import cn.novalon.manage.gateway.config.PermissionConfig;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

@Component
public class RbacAuthorizationFilter extends AbstractGatewayFilterFactory<RbacAuthorizationFilter.Config> {

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getPath().value();
            String method = request.getMethod().name();

            if (isPublicPath(path)) {
                return chain.filter(exchange);
            }

            List<String> permissions = request.getHeaders().get("X-User-Permissions");
            List<String> roles = request.getHeaders().get("X-User-Roles");

            if (permissions == null || roles == null) {
                return forbidden(exchange.getResponse());
            }

            String requiredPermission = PermissionConfig.getRequiredPermission(path, method);

            if (requiredPermission != null && !hasPermission(permissions, requiredPermission)) {
                return forbidden(exchange.getResponse());
            }

            return chain.filter(exchange);
        };
    }

    private boolean isPublicPath(String path) {
        return path.startsWith("/api/auth/login") || path.startsWith("/api/auth/register");
    }

    private boolean hasPermission(List<String> permissions, String requiredPermission) {
        return permissions.contains(requiredPermission) || permissions.contains("*:*");
    }

    private Mono<Void> forbidden(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return response.setComplete();
    }

    public static class Config {
    }
}
```

**Step 3: Update GatewayApplication to register filters**

Read: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/GatewayApplication.java`

Update to include filters:

```java
package cn.novalon.manage.gateway;

import cn.novalon.manage.gateway.filter.JwtAuthenticationFilter;
import cn.novalon.manage.gateway.filter.RbacAuthorizationFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("manage-app", r -> r
                        .path("/api/**")
                        .filters(f -> f
                                .filter(new JwtAuthenticationFilter.Config())
                                .filter(new RbacAuthorizationFilter.Config()))
                        .uri("http://manage-app:8081"))
                .build();
    }
}
```

**Step 4: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway -am`

Expected: BUILD SUCCESS

**Step 5: Commit**

```bash
git add novalon-manage-api/manage-gateway/
git commit -m "feat: implement RBAC authorization filter in manage-gateway"
```

---

### Task 17: Configure Caffeine cache in manage-common

**Files:**
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/CacheConfig.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/service/TokenBlacklistService.java`

**Step 1: Create CacheConfig**

Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/CacheConfig.java`

```java
package cn.novalon.manage.common.config;

import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeineCacheBuilder());
        return cacheManager;
    }

    @Bean
    public com.github.benmanes.caffeine.cache.Cache<Object, Object> caffeineCache() {
        return Caffeine.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .build();
    }

    private Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(10, TimeUnit.MINUTES);
    }
}
```

**Step 2: Create TokenBlacklistService**

Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/service/TokenBlacklistService.java`

```java
package cn.novalon.manage.common.service;

import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class TokenBlacklistService {

    private final Cache<String, Boolean> tokenBlacklistCache;

    public TokenBlacklistService() {
        this.tokenBlacklistCache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
                .maximumSize(10000)
                .expireAfterWrite(2, TimeUnit.HOURS)
                .build();
    }

    public void addToBlacklist(String tokenId) {
        tokenBlacklistCache.put(tokenId, true);
    }

    public boolean isBlacklisted(String tokenId) {
        return tokenBlacklistCache.getIfPresent(tokenId) != null;
    }
}
```

**Step 3: Compile and verify**

Run: `cd novalon-manage-api && mvn clean compile -pl manage-common -am`

Expected: BUILD SUCCESS

**Step 4: Commit**

```bash
git add novalon-manage-api/manage-common/
git commit -m "feat: configure Caffeine cache in manage-common"
```

---

### Task 18: Create Docker Compose configuration

**Files:**
- Create: `novalon-manage-system/docker-compose.yml`
- Create: `novalon-manage-system/.env.example`

**Step 1: Create docker-compose.yml**

Create: `novalon-manage-system/docker-compose.yml`

```yaml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: novalon-postgres
    environment:
      POSTGRES_DB: novalon_manage
      POSTGRES_USER: ${DB_USERNAME:-postgres}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./docs/sql:/docker-entrypoint-initdb.d
    networks:
      - novalon-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  manage-gateway:
    build:
      context: ./novalon-manage-api
      dockerfile: manage-gateway/Dockerfile
    container_name: novalon-gateway
    ports:
      - "8080:8080"
    environment:
      SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
      JWT_SECRET: ${JWT_SECRET}
      JWT_EXPIRATION: ${JWT_EXPIRATION:-7200}
      APP_SERVICE_URL: http://manage-app:8081
    depends_on:
      manage-app:
        condition: service_healthy
    networks:
      - novalon-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  manage-app:
    build:
      context: ./novalon-manage-api
      dockerfile: manage-app/Dockerfile
    container_name: novalon-app
    ports:
      - "8081:8081"
    environment:
      SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
      DB_HOST: postgres
      DB_PORT: 5432
      DB_NAME: novalon_manage
      DB_USERNAME: ${DB_USERNAME:-postgres}
      DB_PASSWORD: ${DB_PASSWORD:-postgres}
      JWT_SECRET: ${JWT_SECRET}
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - novalon-network
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  postgres_data:

networks:
  novalon-network:
    driver: bridge
```

**Step 2: Create .env.example**

Create: `novalon-manage-system/.env.example`

```bash
# Database Configuration
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password

# JWT Configuration
JWT_SECRET=your_jwt_secret_key_minimum_256_bits
JWT_EXPIRATION=7200

# Spring Profile
SPRING_PROFILES_ACTIVE=prod
```

**Step 3: Commit**

```bash
git add novalon-manage-system/docker-compose.yml novalon-manage-system/.env.example
git commit -m "feat: add Docker Compose configuration"
```

---

## Phase 4: Testing and Optimization (2-3 days)

### Task 19: Write unit tests for manage-common

**Files:**
- Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/util/JwtTokenProviderTest.java`
- Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/service/TokenBlacklistServiceTest.java`

**Step 1: Write JwtTokenProviderTest**

Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/util/JwtTokenProviderTest.java`

```java
package cn.novalon.manage.common.util;

import cn.novalon.manage.common.config.JwtProperties;
import cn.novalon.manage.common.dto.JwtUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class JwtTokenProviderTest {

    private JwtTokenProvider jwtTokenProvider;
    private JwtProperties jwtProperties;

    @BeforeEach
    void setUp() {
        jwtProperties = new JwtProperties();
        jwtProperties.setSecret("test-secret-key-for-testing-purposes-only");
        jwtProperties.setExpiration(7200);
        jwtTokenProvider = new JwtTokenProvider(jwtProperties);
    }

    @Test
    void testGenerateToken() {
        JwtUser user = new JwtUser();
        user.setUserId("user123");
        user.setUsername("testuser");
        user.setRoles(Arrays.asList("ADMIN"));
        user.setPermissions(Arrays.asList("user:read", "user:write"));

        String token = jwtTokenProvider.generateToken(user);

        assertNotNull(token);
        assertFalse(token.isEmpty());
    }

    @Test
    void testParseToken() {
        JwtUser originalUser = new JwtUser();
        originalUser.setUserId("user123");
        originalUser.setUsername("testuser");
        originalUser.setRoles(Arrays.asList("ADMIN"));
        originalUser.setPermissions(Arrays.asList("user:read", "user:write"));

        String token = jwtTokenProvider.generateToken(originalUser);
        JwtUser parsedUser = jwtTokenProvider.parseToken(token);

        assertEquals(originalUser.getUserId(), parsedUser.getUserId());
        assertEquals(originalUser.getUsername(), parsedUser.getUsername());
        assertEquals(originalUser.getRoles(), parsedUser.getRoles());
        assertEquals(originalUser.getPermissions(), parsedUser.getPermissions());
    }

    @Test
    void testValidateToken() {
        JwtUser user = new JwtUser();
        user.setUserId("user123");
        user.setUsername("testuser");
        user.setRoles(Arrays.asList("ADMIN"));
        user.setPermissions(Arrays.asList("user:read"));

        String validToken = jwtTokenProvider.generateToken(user);
        assertTrue(jwtTokenProvider.validateToken(validToken));

        String invalidToken = "invalid.token.here";
        assertFalse(jwtTokenProvider.validateToken(invalidToken));
    }
}
```

**Step 2: Write TokenBlacklistServiceTest**

Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/service/TokenBlacklistServiceTest.java`

```java
package cn.novalon.manage.common.service;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class TokenBlacklistServiceTest {

    private TokenBlacklistService tokenBlacklistService;

    @BeforeEach
    void setUp() {
        tokenBlacklistService = new TokenBlacklistService();
    }

    @Test
    void testAddToBlacklist() {
        String tokenId = "token123";
        tokenBlacklistService.addToBlacklist(tokenId);

        assertTrue(tokenBlacklistService.isBlacklisted(tokenId));
    }

    @Test
    void testIsBlacklisted() {
        String tokenId = "token456";
        assertFalse(tokenBlacklistService.isBlacklisted(tokenId));

        tokenBlacklistService.addToBlacklist(tokenId);
        assertTrue(tokenBlacklistService.isBlacklisted(tokenId));
    }

    @Test
    void testMultipleTokens() {
        String token1 = "token1";
        String token2 = "token2";
        String token3 = "token3";

        tokenBlacklistService.addToBlacklist(token1);
        tokenBlacklistService.addToBlacklist(token2);
        tokenBlacklistService.addToBlacklist(token3);

        assertTrue(tokenBlacklistService.isBlacklisted(token1));
        assertTrue(tokenBlacklistService.isBlacklisted(token2));
        assertTrue(tokenBlacklistService.isBlacklisted(token3));
    }
}
```

**Step 3: Run tests**

Run: `cd novalon-manage-api && mvn test -pl manage-common`

Expected: All tests pass

**Step 4: Commit**

```bash
