This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git

commit 323a31cc7c4e1bec3141272541ccce5dd694c55e
Author: lizhimins <[email protected]>
AuthorDate: Sun Jul 5 15:34:00 2026 +0800

    feat: implement backend common module and auth
    
    - Add common domain classes (Result, PageResult, BaseEntity)
    - Add 16 business enums (ClusterStatus, TopicType, etc.)
    - Implement global exception handler
    - Configure CORS and web MVC
    - Implement authentication (AuthController, AuthService)
    - Add auth unit tests
    
    Co-Authored-By: Claude <[email protected]>
---
 .../com/rocketmq/studio/auth/AuthController.java   |  44 ++++++++
 .../java/com/rocketmq/studio/auth/AuthService.java |  60 +++++++++++
 .../java/com/rocketmq/studio/auth/LoginDTO.java    |  26 +++++
 .../java/com/rocketmq/studio/auth/LoginVO.java     |  42 ++++++++
 .../com/rocketmq/studio/auth/SecurityConfig.java   |  25 +++++
 .../rocketmq/studio/common/config/CorsConfig.java  |  33 ++++++
 .../rocketmq/studio/common/config/WebConfig.java   |  25 +++++
 .../rocketmq/studio/common/domain/BaseEntity.java  |  27 +++++
 .../rocketmq/studio/common/domain/PageResult.java  |  47 +++++++++
 .../com/rocketmq/studio/common/domain/Result.java  |  47 +++++++++
 .../studio/common/domain/enums/AlertLevel.java     |  22 ++++
 .../studio/common/domain/enums/BrokerStatus.java   |  22 ++++
 .../studio/common/domain/enums/CertStatus.java     |  22 ++++
 .../studio/common/domain/enums/CertType.java       |  22 ++++
 .../studio/common/domain/enums/ClientLanguage.java |  22 ++++
 .../studio/common/domain/enums/ClientType.java     |  22 ++++
 .../studio/common/domain/enums/ClusterStatus.java  |  22 ++++
 .../studio/common/domain/enums/ClusterType.java    |  22 ++++
 .../studio/common/domain/enums/ConsumeType.java    |  22 ++++
 .../studio/common/domain/enums/DeliveryStatus.java |  22 ++++
 .../studio/common/domain/enums/FlushDiskType.java  |  22 ++++
 .../studio/common/domain/enums/InstanceType.java   |  22 ++++
 .../studio/common/domain/enums/Protocol.java       |  22 ++++
 .../common/domain/enums/SubscriptionMode.java      |  22 ++++
 .../studio/common/domain/enums/TopicPerm.java      |  22 ++++
 .../studio/common/domain/enums/TopicType.java      |  22 ++++
 .../studio/common/exception/BusinessException.java |  29 ++++++
 .../common/exception/GlobalExceptionHandler.java   |  45 ++++++++
 .../rocketmq/studio/auth/AuthControllerTest.java   | 115 +++++++++++++++++++++
 .../com/rocketmq/studio/auth/AuthServiceTest.java  | 115 +++++++++++++++++++++
 30 files changed, 1032 insertions(+)

diff --git a/server/src/main/java/com/rocketmq/studio/auth/AuthController.java 
b/server/src/main/java/com/rocketmq/studio/auth/AuthController.java
new file mode 100644
index 0000000..8b4f6f1
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/auth/AuthController.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import com.rocketmq.studio.common.domain.Result;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/auth")
+@RequiredArgsConstructor
+public class AuthController {
+
+    private final AuthService authService;
+
+    @PostMapping("/login")
+    public Result<LoginVO> login(@RequestBody LoginDTO request) {
+        return Result.ok(authService.login(request));
+    }
+
+    @PostMapping("/logout")
+    public Result<Void> logout() {
+        authService.logout();
+        return Result.ok();
+    }
+}
diff --git a/server/src/main/java/com/rocketmq/studio/auth/AuthService.java 
b/server/src/main/java/com/rocketmq/studio/auth/AuthService.java
new file mode 100644
index 0000000..0591cef
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/auth/AuthService.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import com.rocketmq.studio.common.exception.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.UUID;
+
+@Slf4j
+@Service
+public class AuthService {
+
+    public LoginVO login(LoginDTO request) {
+        log.info("Login attempt for user: {}", request.getUsername());
+
+        if (request.getUsername() == null || request.getUsername().isBlank()) {
+            throw new BusinessException(400, "Username is required");
+        }
+        if (request.getPassword() == null || request.getPassword().isBlank()) {
+            throw new BusinessException(400, "Password is required");
+        }
+
+        // Mock authentication — accept any non-empty credentials
+        String token = "mock-jwt-" + UUID.randomUUID();
+        boolean isAdmin = "admin".equals(request.getUsername());
+
+        LoginVO response = LoginVO.builder()
+                .token(token)
+                .expiresIn(86400)
+                .user(LoginVO.UserInfo.builder()
+                        .username(request.getUsername())
+                        .admin(isAdmin)
+                        .build())
+                .build();
+
+        log.info("User {} logged in successfully, admin={}", 
request.getUsername(), isAdmin);
+        return response;
+    }
+
+    public void logout() {
+        log.info("User logged out");
+    }
+}
diff --git a/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java 
b/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java
new file mode 100644
index 0000000..a24238f
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/auth/LoginDTO.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import lombok.Data;
+
+@Data
+public class LoginDTO {
+    private String username;
+    private String password;
+}
diff --git a/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java 
b/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java
new file mode 100644
index 0000000..2a826f5
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/auth/LoginVO.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LoginVO {
+    private String token;
+    private int expiresIn;
+    private UserInfo user;
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class UserInfo {
+        private String username;
+        private boolean admin;
+    }
+}
diff --git a/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java 
b/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java
new file mode 100644
index 0000000..7784098
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/auth/SecurityConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SecurityConfig {
+    // TODO: Add Spring Security configuration when Spring Security dependency 
is added
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java 
b/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java
new file mode 100644
index 0000000..fd14f2f
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/config/CorsConfig.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**")
+                .allowedOrigins("*")
+                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
+                .allowedHeaders("*");
+    }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java 
b/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java
new file mode 100644
index 0000000..951171f
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/config/WebConfig.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+    // TODO: Add web configuration as needed
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java
new file mode 100644
index 0000000..50144c5
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/domain/BaseEntity.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.domain;
+
+import lombok.Data;
+import java.time.LocalDateTime;
+
+@Data
+public abstract class BaseEntity {
+    private String id;
+    private LocalDateTime createdAt;
+    private LocalDateTime updatedAt;
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java
new file mode 100644
index 0000000..0d6b1e4
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/domain/PageResult.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.domain;
+
+import java.util.Collections;
+import java.util.List;
+
+public class PageResult<T> {
+    private List<T> items;
+    private long total;
+    private int page;
+    private int size;
+
+    private PageResult() {}
+
+    public static <T> PageResult<T> of(List<T> items, long total, int page, 
int size) {
+        PageResult<T> result = new PageResult<>();
+        result.items = items;
+        result.total = total;
+        result.page = page;
+        result.size = size;
+        return result;
+    }
+
+    public static <T> PageResult<T> empty(int page, int size) {
+        return of(Collections.emptyList(), 0, page, size);
+    }
+
+    public List<T> getItems() { return items; }
+    public long getTotal() { return total; }
+    public int getPage() { return page; }
+    public int getSize() { return size; }
+}
diff --git a/server/src/main/java/com/rocketmq/studio/common/domain/Result.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/Result.java
new file mode 100644
index 0000000..b234e08
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/domain/Result.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.domain;
+
+public class Result<T> {
+    private int code;
+    private String message;
+    private T data;
+
+    private Result() {}
+
+    private Result(int code, String message, T data) {
+        this.code = code;
+        this.message = message;
+        this.data = data;
+    }
+
+    public static <T> Result<T> ok(T data) {
+        return new Result<>(200, "success", data);
+    }
+
+    public static <T> Result<T> ok() {
+        return new Result<>(200, "success", null);
+    }
+
+    public static <T> Result<T> error(int code, String message) {
+        return new Result<>(code, message, null);
+    }
+
+    public int getCode() { return code; }
+    public String getMessage() { return message; }
+    public T getData() { return data; }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java
new file mode 100644
index 0000000..e1dc8f8
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/AlertLevel.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum AlertLevel {
+    error, warning, info
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java
new file mode 100644
index 0000000..4396f7d
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/BrokerStatus.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum BrokerStatus {
+    running, readonly, maintenance
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java
new file mode 100644
index 0000000..af1d284
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertStatus.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum CertStatus {
+    valid, expiring, expired
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java
new file mode 100644
index 0000000..8b45b36
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/CertType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum CertType {
+    TLS, mTLS, ServiceAccount
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java
new file mode 100644
index 0000000..d87daeb
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientLanguage.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum ClientLanguage {
+    Java, Go, Python, Rust, Cpp, CSharp, NodeJS, PHP
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java
new file mode 100644
index 0000000..f244d18
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClientType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum ClientType {
+    Producer, Consumer
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java
new file mode 100644
index 0000000..5dd4307
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterStatus.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum ClusterStatus {
+    healthy, warning, error, offline
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java
new file mode 100644
index 0000000..a10f3e2
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ClusterType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum ClusterType {
+    V4_DIRECT, V5_PROXY_LOCAL, V5_PROXY_CLUSTER
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java
new file mode 100644
index 0000000..15e127c
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/ConsumeType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum ConsumeType {
+    CLUSTERING, BROADCASTING
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java
new file mode 100644
index 0000000..7c474f1
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/DeliveryStatus.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum DeliveryStatus {
+    success, failed, pending
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java
new file mode 100644
index 0000000..6bba212
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/FlushDiskType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum FlushDiskType {
+    ASYNC_FLUSH, SYNC_FLUSH
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java
new file mode 100644
index 0000000..132b726
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/InstanceType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum InstanceType {
+    PROXY, DIRECT
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java
new file mode 100644
index 0000000..64a568a
--- /dev/null
+++ b/server/src/main/java/com/rocketmq/studio/common/domain/enums/Protocol.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum Protocol {
+    gRPC, Remoting
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java
 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java
new file mode 100644
index 0000000..3a65255
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/SubscriptionMode.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum SubscriptionMode {
+    Push, Pop
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java
new file mode 100644
index 0000000..cd3660a
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicPerm.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum TopicPerm {
+    RW, RO, WO
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java
new file mode 100644
index 0000000..1b2571b
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/domain/enums/TopicType.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.common.domain.enums;
+
+public enum TopicType {
+    NORMAL, FIFO, DELAY, TRANSACTION, LITE
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java
 
b/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java
new file mode 100644
index 0000000..cb6c566
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/exception/BusinessException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.exception;
+
+import lombok.Getter;
+
+@Getter
+public class BusinessException extends RuntimeException {
+    private final int code;
+
+    public BusinessException(int code, String message) {
+        super(message);
+        this.code = code;
+    }
+}
diff --git 
a/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java
 
b/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..3bc1c19
--- /dev/null
+++ 
b/server/src/main/java/com/rocketmq/studio/common/exception/GlobalExceptionHandler.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.rocketmq.studio.common.exception;
+
+import com.rocketmq.studio.common.domain.Result;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    private static final Logger log = 
LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    @ExceptionHandler(BusinessException.class)
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    public Result<?> handleBusinessException(BusinessException ex) {
+        log.warn("Business exception: {}", ex.getMessage());
+        return Result.error(ex.getCode(), ex.getMessage());
+    }
+
+    @ExceptionHandler(Exception.class)
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    public Result<?> handleException(Exception ex) {
+        log.error("Unexpected exception", ex);
+        return Result.error(500, "Internal Server Error");
+    }
+}
diff --git 
a/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java 
b/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java
new file mode 100644
index 0000000..b4fe26f
--- /dev/null
+++ b/server/src/test/java/com/rocketmq/studio/auth/AuthControllerTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import 
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static 
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static 
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@WebMvcTest(AuthController.class)
+@AutoConfigureMockMvc(addFilters = false)
+class AuthControllerTest {
+
+    @Autowired
+    private MockMvc mockMvc;
+
+    @MockBean
+    private AuthService authService;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Test
+    void loginShouldReturnTokenOnValidRequest() throws Exception {
+        LoginVO mockResponse = LoginVO.builder()
+                .token("mock-jwt-abc123")
+                .expiresIn(86400)
+                .user(LoginVO.UserInfo.builder()
+                        .username("testuser")
+                        .admin(false)
+                        .build())
+                .build();
+
+        when(authService.login(any(LoginDTO.class))).thenReturn(mockResponse);
+
+        LoginDTO request = new LoginDTO();
+        request.setUsername("testuser");
+        request.setPassword("testpass");
+
+        mockMvc.perform(post("/api/auth/login")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(objectMapper.writeValueAsString(request)))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.message").value("success"))
+                .andExpect(jsonPath("$.data.token").value("mock-jwt-abc123"))
+                .andExpect(jsonPath("$.data.expiresIn").value(86400))
+                .andExpect(jsonPath("$.data.user.username").value("testuser"))
+                .andExpect(jsonPath("$.data.user.admin").value(false));
+    }
+
+    @Test
+    void loginShouldReturnAdminUserWhenAdminLogsIn() throws Exception {
+        LoginVO mockResponse = LoginVO.builder()
+                .token("mock-jwt-admin")
+                .expiresIn(86400)
+                .user(LoginVO.UserInfo.builder()
+                        .username("admin")
+                        .admin(true)
+                        .build())
+                .build();
+
+        when(authService.login(any(LoginDTO.class))).thenReturn(mockResponse);
+
+        LoginDTO request = new LoginDTO();
+        request.setUsername("admin");
+        request.setPassword("adminpass");
+
+        mockMvc.perform(post("/api/auth/login")
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .content(objectMapper.writeValueAsString(request)))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.data.user.username").value("admin"))
+                .andExpect(jsonPath("$.data.user.admin").value(true));
+    }
+
+    @Test
+    void logoutShouldReturnSuccess() throws Exception {
+        doNothing().when(authService).logout();
+
+        mockMvc.perform(post("/api/auth/logout"))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.code").value(200))
+                .andExpect(jsonPath("$.message").value("success"));
+
+        verify(authService).logout();
+    }
+}
diff --git a/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java 
b/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java
new file mode 100644
index 0000000..1452572
--- /dev/null
+++ b/server/src/test/java/com/rocketmq/studio/auth/AuthServiceTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.rocketmq.studio.auth;
+
+import com.rocketmq.studio.common.exception.BusinessException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@ExtendWith(MockitoExtension.class)
+class AuthServiceTest {
+
+    private AuthService authService;
+
+    @BeforeEach
+    void setUp() {
+        authService = new AuthService();
+    }
+
+    @Test
+    void loginShouldReturnTokenForValidCredentials() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername("testuser");
+        request.setPassword("testpass");
+
+        LoginVO response = authService.login(request);
+
+        assertThat(response).isNotNull();
+        assertThat(response.getToken()).startsWith("mock-jwt-");
+        assertThat(response.getExpiresIn()).isEqualTo(86400);
+        assertThat(response.getUser()).isNotNull();
+        assertThat(response.getUser().getUsername()).isEqualTo("testuser");
+        assertThat(response.getUser().isAdmin()).isFalse();
+    }
+
+    @Test
+    void loginShouldReturnAdminFlagForAdminUser() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername("admin");
+        request.setPassword("adminpass");
+
+        LoginVO response = authService.login(request);
+
+        assertThat(response.getUser().getUsername()).isEqualTo("admin");
+        assertThat(response.getUser().isAdmin()).isTrue();
+    }
+
+    @Test
+    void loginShouldThrowWhenUsernameIsNull() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername(null);
+        request.setPassword("password");
+
+        assertThatThrownBy(() -> authService.login(request))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Username is required");
+    }
+
+    @Test
+    void loginShouldThrowWhenUsernameIsBlank() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername("   ");
+        request.setPassword("password");
+
+        assertThatThrownBy(() -> authService.login(request))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Username is required");
+    }
+
+    @Test
+    void loginShouldThrowWhenPasswordIsNull() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername("testuser");
+        request.setPassword(null);
+
+        assertThatThrownBy(() -> authService.login(request))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Password is required");
+    }
+
+    @Test
+    void loginShouldThrowWhenPasswordIsBlank() {
+        LoginDTO request = new LoginDTO();
+        request.setUsername("testuser");
+        request.setPassword("   ");
+
+        assertThatThrownBy(() -> authService.login(request))
+                .isInstanceOf(BusinessException.class)
+                .hasMessage("Password is required");
+    }
+
+    @Test
+    void logoutShouldCompleteWithoutError() {
+        authService.logout();
+    }
+}

Reply via email to